diff --git a/packet_unpacker.go b/packet_unpacker.go index ee9965cf..09a000a7 100644 --- a/packet_unpacker.go +++ b/packet_unpacker.go @@ -38,22 +38,22 @@ func (u *packetUnpacker) Unpack(publicHeaderBinary []byte, publicHeader *PublicH fs := []frames.Frame{} // Read all frames in the packet +ReadLoop: for r.Len() > 0 { typeByte, _ := r.ReadByte() r.UnreadByte() var frame frames.Frame - err = nil if typeByte&0x80 == 0x80 { frame, err = frames.ParseStreamFrame(r) - } else if typeByte&0xca == 0x40 { + } else if typeByte&0xc0 == 0x40 { frame, err = frames.ParseAckFrame(r) } else if typeByte&0xe0 == 0x20 { err = errors.New("unimplemented: CONGESTION_FEEDBACK") } else { switch typeByte { case 0x0: // PAD, end of frames - break + break ReadLoop case 0x01: frame, err = frames.ParseRstStreamFrame(r) case 0x02: @@ -64,10 +64,12 @@ func (u *packetUnpacker) Unpack(publicHeaderBinary []byte, publicHeader *PublicH fmt.Println("unimplemented: WINDOW_UPDATE") p := make([]byte, 1+4+8) _, err = r.Read(p) + frame = nil case 0x05: fmt.Println("unimplemented: BLOCKED") p := make([]byte, 1+4) _, err = r.Read(p) + frame = nil case 0x06: frame, err = frames.ParseStopWaitingFrame(r, publicHeader.PacketNumberLen) case 0x07: @@ -81,7 +83,10 @@ func (u *packetUnpacker) Unpack(publicHeaderBinary []byte, publicHeader *PublicH if err != nil { return nil, err } - fs = append(fs, frame) + // TODO: Remove once all frames are implemented + if frame != nil { + fs = append(fs, frame) + } } return &unpackedPacket{ diff --git a/packet_unpacker_test.go b/packet_unpacker_test.go index 425e107c..33aafd55 100644 --- a/packet_unpacker_test.go +++ b/packet_unpacker_test.go @@ -4,6 +4,7 @@ import ( "bytes" "github.com/lucas-clemente/quic-go/crypto" + "github.com/lucas-clemente/quic-go/frames" . "github.com/onsi/ginkgo" . "github.com/onsi/gomega" @@ -16,29 +17,150 @@ var _ = Describe("Packet unpacker", func() { hdrBin []byte aead crypto.AEAD r *bytes.Reader + buf *bytes.Buffer ) BeforeEach(func() { aead = &crypto.NullAEAD{} hdr = &PublicHeader{ - PacketNumber: 1, + PacketNumber: 1, + PacketNumberLen: 1, } hdrBin = []byte{0x04, 0x4c, 0x01} unpacker = &packetUnpacker{aead: aead} r = nil + buf = &bytes.Buffer{} }) setReader := func(data []byte) { - var b bytes.Buffer - b.Write(aead.Seal(0, hdrBin, data)) - r = bytes.NewReader(b.Bytes()) + r = bytes.NewReader(aead.Seal(0, hdrBin, append([]byte{0x01}, data...))) } It("unpacks empty packets", func() { - setReader([]byte{0x01}) + setReader(nil) packet, err := unpacker.Unpack(hdrBin, hdr, r) Expect(err).ToNot(HaveOccurred()) Expect(packet.entropyBit).To(BeTrue()) Expect(packet.frames).To(HaveLen(0)) }) + + It("unpacks stream frames", func() { + f := &frames.StreamFrame{ + StreamID: 1, + Data: []byte("foobar"), + } + err := f.Write(buf) + Expect(err).ToNot(HaveOccurred()) + setReader(buf.Bytes()) + packet, err := unpacker.Unpack(hdrBin, hdr, r) + Expect(err).ToNot(HaveOccurred()) + Expect(packet.frames).To(Equal([]frames.Frame{f})) + }) + + It("unpacks ack frames", func() { + f := &frames.AckFrame{ + LargestObserved: 1, + DelayTime: 1, + } + err := f.Write(buf) + Expect(err).ToNot(HaveOccurred()) + setReader(buf.Bytes()) + packet, err := unpacker.Unpack(hdrBin, hdr, r) + Expect(err).ToNot(HaveOccurred()) + Expect(packet.frames).To(Equal([]frames.Frame{f})) + }) + + It("unpacks ack frames", func() { + f := &frames.AckFrame{ + LargestObserved: 1, + DelayTime: 1, + } + err := f.Write(buf) + Expect(err).ToNot(HaveOccurred()) + setReader(buf.Bytes()) + packet, err := unpacker.Unpack(hdrBin, hdr, r) + Expect(err).ToNot(HaveOccurred()) + Expect(packet.frames).To(Equal([]frames.Frame{f})) + }) + + It("errors on CONGESTION_FEEDBACK frames", func() { + setReader([]byte{0x20}) + _, err := unpacker.Unpack(hdrBin, hdr, r) + Expect(err).To(MatchError("unimplemented: CONGESTION_FEEDBACK")) + }) + + It("handles pad frames", func() { + setReader([]byte{0, 0, 0}) + packet, err := unpacker.Unpack(hdrBin, hdr, r) + Expect(err).ToNot(HaveOccurred()) + Expect(packet.frames).To(HaveLen(0)) + }) + + It("unpacks RST_STREAM frames", func() { + setReader([]byte{0x01, 0xEF, 0xBE, 0xAD, 0xDE, 0x44, 0x33, 0x22, 0x11, 0xAD, 0xFB, 0xCA, 0xDE, 0x34, 0x12, 0x37, 0x13}) + packet, err := unpacker.Unpack(hdrBin, hdr, r) + Expect(err).ToNot(HaveOccurred()) + Expect(packet.frames).To(Equal([]frames.Frame{ + &frames.RstStreamFrame{ + StreamID: 0xDEADBEEF, + ByteOffset: 0xDECAFBAD11223344, + ErrorCode: 0x13371234, + }, + })) + }) + + It("unpacks CONNECTION_CLOSE frames", func() { + f := &frames.ConnectionCloseFrame{ReasonPhrase: "foo"} + err := f.Write(buf) + Expect(err).ToNot(HaveOccurred()) + setReader(buf.Bytes()) + packet, err := unpacker.Unpack(hdrBin, hdr, r) + Expect(err).ToNot(HaveOccurred()) + Expect(packet.frames).To(Equal([]frames.Frame{f})) + }) + + It("errors on GOAWAY frames", func() { + setReader([]byte{0x03}) + _, err := unpacker.Unpack(hdrBin, hdr, r) + Expect(err).To(MatchError("unimplemented: GOAWAY")) + }) + + It("accepts WINDOW_UPDATE frames", func() { + setReader([]byte{0x04, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}) + packet, err := unpacker.Unpack(hdrBin, hdr, r) + Expect(err).ToNot(HaveOccurred()) + Expect(packet.frames).To(HaveLen(0)) + }) + + It("accepts BLOCKED frames", func() { + setReader([]byte{0x05, 0, 0, 0, 0}) + packet, err := unpacker.Unpack(hdrBin, hdr, r) + Expect(err).ToNot(HaveOccurred()) + Expect(packet.frames).To(HaveLen(0)) + }) + + It("unpacks STOP_WAITING frames", func() { + setReader([]byte{0x06, 0xA4, 0x03}) + packet, err := unpacker.Unpack(hdrBin, hdr, r) + Expect(err).ToNot(HaveOccurred()) + Expect(packet.frames).To(Equal([]frames.Frame{ + &frames.StopWaitingFrame{ + Entropy: 0xA4, + LeastUnackedDelta: 0x03, + }, + })) + }) + + It("accepts PING frames", func() { + setReader([]byte{0x07}) + packet, err := unpacker.Unpack(hdrBin, hdr, r) + Expect(err).ToNot(HaveOccurred()) + Expect(packet.frames).To(HaveLen(0)) + }) + + It("errors on invalid type", func() { + setReader([]byte{0x08}) + _, err := unpacker.Unpack(hdrBin, hdr, r) + Expect(err).To(MatchError("unknown type byte 0x8")) + }) })