Skip to content

Commit 3cf4d6d

Browse files
authored
Refactor Protocol/Payload - decoding/encoding (#25)
Updates the EngineIO protocol and payload encoding/decoding methods to be more clear. Updates the Binary support to not be based on if the packet is Binary but rather if the protocol supports binary. Updates the JSON and Base64 encoding to satisfy a common interface and be added to the rw.Writer and rw.Reader structs so they can be used in a fluid manner.
1 parent 663c2f0 commit 3cf4d6d

17 files changed

+221
-124
lines changed

Diff for: engineio/protocol/packet.go

+7-12
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,9 @@
11
package protocol
22

33
import (
4-
"encoding/json"
54
"io"
5+
6+
"github.com/njones/socketio/internal/readwriter"
67
)
78

89
const (
@@ -27,18 +28,12 @@ const (
2728
)
2829

2930
type (
30-
_packetJSONDecoder func(io.Reader) *json.Decoder
31-
_packetJSONEncoder func(io.Writer) *json.Encoder
31+
_packetJSONDecoder = readwriter.JSONDecoder
32+
_packetBase64Decoder = readwriter.Base64Decoder
33+
_packetJSONEncoder = readwriter.JSONEncoderStripNewline
34+
_packetBase64encoder = readwriter.Base64Encoder
3235
)
3336

34-
func (fn _packetJSONDecoder) From(r io.Reader) func(interface{}) error { return fn(r).Decode }
35-
func (fn _packetJSONEncoder) To(w io.Writer) func(interface{}) error {
36-
return fn(&stripLastNewlineWriter{w}).Encode
37-
}
38-
39-
func newJSONDecoder() _packetJSONDecoder { return json.NewDecoder }
40-
func newJSONEncoder() _packetJSONEncoder { return json.NewEncoder }
41-
4237
type Packet struct {
4338
T PacketType `json:"type"`
4439
D interface{} `json:"data"`
@@ -57,7 +52,7 @@ func (pac Packet) Len() int {
5752
case nil:
5853
return n
5954
case string:
60-
return n + len(d)
55+
return n + len([]rune(d))
6156
case useLen:
6257
return n + d.Len()
6358
}

Diff for: engineio/protocol/packet.v2.codec.go

+1-1
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@ func (pac _packetEncoderV2) To(w io.Writer) PacketWriter { return _packetWrite
1717
func (pac _packetReaderV2) ReadPacket(packet PacketRef) (err error) {
1818
var v = PacketV2{Packet: *packet.PacketRef()}
1919
err = pac(&v)
20-
*packet.PacketRef() = v.Packet // add even if err becuase when using Decode this is what happens
20+
*packet.PacketRef() = v.Packet // add even if err because when using Decode this is what happens
2121
return err
2222
}
2323
func (pac _packetWriterV2) WritePacket(packet PacketVal) error {

Diff for: engineio/protocol/packet.v2.go

+8-4
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44
package protocol
55

66
import (
7+
"encoding/json"
78
"fmt"
89
"io"
910
"strings"
@@ -36,7 +37,7 @@ func (dec *PacketDecoderV2) Decode(packet *PacketV2) error {
3637
switch packetType := packet.T; packetType {
3738
case OpenPacket:
3839
var data HandshakeV2
39-
dec.read.Decoder(newJSONDecoder()).Decode(&data).OnErrF(ErrHandshakeDecode, "v2", dec.read.Err())
40+
dec.read.SetDecoder(_packetJSONDecoder(json.NewDecoder)).Decode(&data).OnErrF(ErrHandshakeDecode, "v2", dec.read.Err())
4041
packet.D = &data
4142
case MessagePacket:
4243
var data = new(strings.Builder)
@@ -78,7 +79,7 @@ func (enc *PacketEncoderV2) Encode(packet PacketV2) (err error) {
7879
data.Upgrades = []string{}
7980
}
8081
enc.write.Bytes(packet.T.Bytes()).OnErrF(ErrHandshakeEncode, "v2", enc.write.Err())
81-
enc.write.Encoder(newJSONEncoder()).Encode(data).OnErrF(ErrHandshakeEncode, "v2", enc.write.Err())
82+
enc.write.UseEncoder(_packetJSONEncoder(json.NewEncoder)).Encode(data).OnErrF(ErrHandshakeEncode, "v2", enc.write.Err())
8283
default:
8384
return ErrInvalidHandshake.F("v2")
8485
}
@@ -88,10 +89,13 @@ func (enc *PacketEncoderV2) Encode(packet PacketV2) (err error) {
8889
enc.write.Bytes(packet.T.Bytes()).OnErrF(ErrPacketEncode, "v2", enc.write.Err())
8990
case string:
9091
enc.write.Bytes(packet.T.Bytes()).OnErrF(ErrPacketEncode, "v2", enc.write.Err())
91-
enc.write.String(data).OnErrF(ErrPacketEncode, "v2", enc.write.Err())
92+
enc.write.Encode(data).OnErrF(ErrPacketEncode, "v2", enc.write.Err())
93+
case []byte:
94+
enc.write.Bytes(packet.T.Bytes()).OnErrF(ErrPacketEncode, "v2", enc.write.Err())
95+
enc.write.Encode(data).OnErrF(ErrPacketEncode, "v2", enc.write.Err())
9296
case io.WriterTo:
9397
enc.write.Bytes(packet.T.Bytes()).OnErrF(ErrPacketEncode, "v2", enc.write.Err())
94-
enc.write.To(data).OnErrF(ErrPacketEncode, "v2", enc.write.Err())
98+
enc.write.Encode(data).OnErrF(ErrPacketEncode, "v2", enc.write.Err())
9599
default:
96100
return ErrInvalidPacketData.F(fmt.Sprintf("unexpected data type of: %T", data))
97101
}

Diff for: engineio/protocol/packet.v3.go

+3-2
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ package protocol
55

66
import (
77
"bytes"
8+
"encoding/json"
89
"io"
910

1011
rw "github.com/njones/socketio/internal/readwriter"
@@ -37,7 +38,7 @@ func (dec *PacketDecoderV3) Decode(packet *PacketV3) error {
3738
switch packet.T {
3839
case OpenPacket:
3940
var data HandshakeV3
40-
dec.read.Decoder(newJSONDecoder()).Decode(&data)
41+
dec.read.SetDecoder(_packetJSONDecoder(json.NewDecoder)).Decode(&data)
4142
packet.D = data
4243
return dec.read.Err()
4344
}
@@ -72,7 +73,7 @@ func (enc *PacketEncoderV3) Encode(packet PacketV3) (err error) {
7273
data.Upgrades = []string{}
7374
}
7475
enc.write.Bytes(packet.T.Bytes()).OnErr(ErrPacketEncode)
75-
enc.write.Encoder(newJSONEncoder()).Encode(data).OnErrF(ErrPacketEncode, "v3", enc.write.Err())
76+
enc.write.UseEncoder(_packetJSONEncoder(json.NewEncoder)).Encode(data).OnErrF(ErrHandshakeEncode, "v3", enc.write.Err())
7677
default:
7778
return ErrInvalidHandshake.F("v3")
7879
}

Diff for: engineio/protocol/packet.v4.go

+3-3
Original file line numberDiff line numberDiff line change
@@ -36,7 +36,7 @@ func (dec *PacketDecoderV4) Decode(packet *PacketV4) error {
3636
switch packet.T {
3737
case BinaryPacket:
3838
var data = new(bytes.Buffer)
39-
dec.read.Base64(base64.StdEncoding).Copy(data).OnErrF(ErrPacketDecode, "v4", dec.read.Err())
39+
dec.read.SetDecoder(_packetBase64Decoder(base64.NewDecoder)).Decode(data).OnErrF(ErrPacketDecode, "v4", dec.read.Err())
4040
packet.IsBinary = true
4141
packet.D = (io.Reader)(data)
4242
return dec.read.Err()
@@ -63,9 +63,9 @@ func (enc *PacketEncoderV4) Encode(packet PacketV4) (err error) {
6363
enc.write.Bytes(packet.T.Bytes()).OnErrF(ErrPacketEncode, "v4", enc.write.Err())
6464
switch data := packet.D.(type) {
6565
case []byte:
66-
enc.write.Base64(base64.StdEncoding).Bytes(data).OnErrF(ErrPacketEncode, "v4", enc.write.Err())
66+
enc.write.UseEncoder(_packetBase64encoder(base64.NewEncoder)).Encode(data).OnErrF(ErrPacketEncode, "v4", enc.write.Err())
6767
case io.Reader:
68-
enc.write.Base64(base64.StdEncoding).Copy(data).OnErrF(ErrPacketEncode, "v4", enc.write.Err())
68+
enc.write.UseEncoder(_packetBase64encoder(base64.NewEncoder)).Encode(data).OnErrF(ErrPacketEncode, "v4", enc.write.Err())
6969
default:
7070
return fmt.Errorf("bad packet dinary encode type: %T", data)
7171
}

Diff for: engineio/protocol/payload.go

+7
Original file line numberDiff line numberDiff line change
@@ -26,3 +26,10 @@ type reader struct {
2626
*rw.Reader
2727
err error
2828
}
29+
30+
type writer struct {
31+
*rw.Writer
32+
err error
33+
}
34+
35+
func (w writer) PropagateWriter() *rw.Writer { return w.Writer }

Diff for: engineio/protocol/payload.v2.go

+2-2
Original file line numberDiff line numberDiff line change
@@ -37,10 +37,10 @@ func (dec *PayloadDecoderV2) Decode(payload *PayloadV2) error {
3737
return dec.read.ConvertErr(io.EOF, nil).Err()
3838
}
3939

40-
type PayloadEncoderV2 struct{ write *rw.Writer }
40+
type PayloadEncoderV2 struct{ write *writer }
4141

4242
var NewPayloadEncoderV2 _payloadEncoderV2 = func(w io.Writer) *PayloadEncoderV2 {
43-
return &PayloadEncoderV2{write: rw.NewWriter(w)}
43+
return &PayloadEncoderV2{write: &writer{Writer: rw.NewWriter(w)}}
4444
}
4545

4646
func (enc *PayloadEncoderV2) Encode(payload PayloadV2) error {

Diff for: engineio/protocol/payload.v2.rw.go

+1-6
Original file line numberDiff line numberDiff line change
@@ -27,10 +27,5 @@ func (rdr *reader) packetLen() (n int64) {
2727
}
2828

2929
func (rdr *reader) payload(n int64) io.Reader {
30-
pr, pw := io.Pipe()
31-
go func() {
32-
CopyRuneN(pw, rdr.Bufio(), n)
33-
pw.Close()
34-
}()
35-
return pr
30+
return LimitRuneReader(rdr.Bufio(), n)
3631
}

Diff for: engineio/protocol/payload.v3.codec.go

+18-2
Original file line numberDiff line numberDiff line change
@@ -28,15 +28,31 @@ type _payloadWriterV3 func(pay PayloadV3) (err error)
2828
func (pay _payloadEncoderV3) SetXHR2(isXHR2 bool) _payloadEncoderV3 {
2929
return func(w io.Writer) *PayloadEncoderV3 {
3030
enc := pay(w)
31-
enc.IsXHR2 = isXHR2
31+
enc.hasXHR2Support = isXHR2
32+
return enc
33+
}
34+
}
35+
36+
func (pay _payloadEncoderV3) SetBinary(isBinary bool) _payloadEncoderV3 {
37+
return func(w io.Writer) *PayloadEncoderV3 {
38+
enc := pay(w)
39+
enc.hasBinarySupport = isBinary
3240
return enc
3341
}
3442
}
3543

3644
func (pay _payloadDecoderV3) SetXHR2(isXHR2 bool) _payloadDecoderV3 {
3745
return func(r io.Reader) *PayloadDecoderV3 {
3846
dec := pay(r)
39-
dec.IsXHR2 = isXHR2
47+
dec.hasXHR2Support = isXHR2
48+
return dec
49+
}
50+
}
51+
52+
func (pay _payloadDecoderV3) SetBinary(isBinary bool) _payloadDecoderV3 {
53+
return func(r io.Reader) *PayloadDecoderV3 {
54+
dec := pay(r)
55+
dec.hasBinarySupport = isBinary
4056
return dec
4157
}
4258
}

Diff for: engineio/protocol/payload.v3.go

+23-6
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,8 @@ type PayloadV3 []PacketV3
1717
type PayloadDecoderV3 struct {
1818
*PayloadDecoderV2
1919

20-
IsXHR2 bool
20+
hasBinarySupport bool
21+
hasXHR2Support bool
2122
}
2223

2324
var NewPayloadDecoderV3 _payloadDecoderV3 = func(r io.Reader) *PayloadDecoderV3 {
@@ -29,7 +30,7 @@ func (dec *PayloadDecoderV3) Decode(payload *PayloadV3) error {
2930
payload = &PayloadV3{}
3031
}
3132

32-
if dec.IsXHR2 {
33+
if dec.hasXHR2Support {
3334
first := dec.read.Peek(1)
3435
if first[0] == 0x00 || first[0] == 0x01 {
3536
return dec.read.decodeXHR2(payload)
@@ -45,7 +46,8 @@ func (dec *PayloadDecoderV3) Decode(payload *PayloadV3) error {
4546
b := dec.read.Peek(1)
4647
if dec.read.IsNotErr() && b[0] == 'b' {
4748
isBinary = true
48-
dec.read.CopyN(io.Discard, 1).OnErr(ErrPayloadDecode) // consume and throw away the 'b' byte
49+
_, err := io.CopyN(io.Discard, r, 1) // consume and throw away the 'b' byte
50+
dec.read.SetErr(err)
4951
r = io.MultiReader(io.LimitReader(r, packetTypeLength), base64.NewDecoder(base64.StdEncoding, r))
5052
}
5153

@@ -62,11 +64,12 @@ func (dec *PayloadDecoderV3) Decode(payload *PayloadV3) error {
6264
type PayloadEncoderV3 struct {
6365
*PayloadEncoderV2
6466

65-
IsXHR2 bool
67+
hasBinarySupport bool
68+
hasXHR2Support bool
6669
}
6770

6871
var NewPayloadEncoderV3 _payloadEncoderV3 = func(w io.Writer) *PayloadEncoderV3 {
69-
return &PayloadEncoderV3{PayloadEncoderV2: &PayloadEncoderV2{write: rw.NewWriter(w)}}
72+
return &PayloadEncoderV3{PayloadEncoderV2: &PayloadEncoderV2{write: &writer{Writer: rw.NewWriter(w)}}}
7073
}
7174

7275
func (enc *PayloadEncoderV3) Encode(payload PayloadV3) error {
@@ -79,7 +82,21 @@ func (enc *PayloadEncoderV3) Encode(payload PayloadV3) error {
7982
}
8083

8184
func (enc *PayloadEncoderV3) encode(packet PacketV3) error {
82-
enc.write.String(fmt.Sprintf("%d:", packet.Len()))
85+
86+
var binaryB string
87+
var lenBuf int
88+
if enc.hasBinarySupport && enc.hasXHR2Support {
89+
return enc.write.encodeXHR2(packet)
90+
}
91+
92+
if packet.IsBinary {
93+
enc.write.SetEncoder(_packetBase64encoder(base64.NewEncoder))
94+
binaryB = "b"
95+
packetLen := packet.Len() - 1 // -1 is the MessageType packet length
96+
lenBuf = base64.StdEncoding.EncodedLen(packetLen) - packetLen + 1 // +1 is the "b"
97+
}
98+
99+
enc.write.String(fmt.Sprintf("%d:%s", packet.Len()+lenBuf, binaryB))
83100
if err := NewPacketEncoderV3(enc.write).Encode(packet); err != nil {
84101
return ErrPayloadEncode.F("v3", err)
85102
}

Diff for: engineio/protocol/payload.v3.rw.go

+31
Original file line numberDiff line numberDiff line change
@@ -72,3 +72,34 @@ func (rdr *reader) decodeXHR2(payload *PayloadV3) error {
7272

7373
return rdr.ConvertErr(io.EOF, nil).Err()
7474
}
75+
76+
// Writer methods
77+
78+
func (wtr *writer) writeBinaryPacketLen(n int) {
79+
for _, r := range []byte(strconv.Itoa(n)) {
80+
wtr.Write([]byte{r - '0'})
81+
}
82+
}
83+
84+
func (wtr *writer) encodeXHR2(packet PacketV3) error {
85+
switch {
86+
case packet.IsBinary:
87+
wtr.Write([]byte{0x01})
88+
default:
89+
wtr.Write([]byte{0x00})
90+
}
91+
92+
switch val := packet.D.(type) {
93+
case string:
94+
wtr.writeBinaryPacketLen(len([]byte(val)) + 1) // +1 for the message type
95+
wtr.Write([]byte{0xFF})
96+
wtr.Write(packet.T.Bytes())
97+
wtr.Write([]byte(val))
98+
case io.Reader:
99+
wtr.writeBinaryPacketLen(packet.Len() - 1) // -1 for the message type
100+
wtr.Write([]byte{0xFF})
101+
wtr.Copy(val)
102+
}
103+
104+
return wtr.Err()
105+
}

Diff for: engineio/protocol/payload.v4.go

+1-1
Original file line numberDiff line numberDiff line change
@@ -43,7 +43,7 @@ type PayloadEncoderV4 struct{ *PayloadEncoderV3 }
4343
var NewPayloadEncoderV4 _payloadEncoderV4 = func(w io.Writer) *PayloadEncoderV4 {
4444
return &PayloadEncoderV4{
4545
PayloadEncoderV3: &PayloadEncoderV3{
46-
PayloadEncoderV2: &PayloadEncoderV2{write: rw.NewWriter(w)},
46+
PayloadEncoderV2: &PayloadEncoderV2{write: &writer{Writer: rw.NewWriter(w)}},
4747
},
4848
}
4949
}

Diff for: engineio/transport/utility.go

-10
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,5 @@
11
package transport
22

3-
import "net/http"
4-
53
type socketClose struct{ error }
64

75
func (sc socketClose) SocketCloseChannel() error { return sc.error }
8-
9-
func jsonpFrom(r *http.Request) *string {
10-
j := r.URL.Query().Get("j")
11-
if j != "" {
12-
return &j
13-
}
14-
return nil
15-
}

0 commit comments

Comments
 (0)