package wire import ( "bytes" "github.com/lucas-clemente/quic-go/internal/protocol" "github.com/lucas-clemente/quic-go/internal/utils" "github.com/lucas-clemente/quic-go/qerr" . "github.com/onsi/ginkgo" . "github.com/onsi/gomega" ) var _ = Describe("STREAM frame (for IETF QUIC)", func() { Context("when parsing", func() { It("parses a frame with OFF bit", func() { data := []byte{0x10 ^ 0x4} data = append(data, encodeVarInt(0x12345)...) // stream ID data = append(data, encodeVarInt(0xdecafbad)...) // offset data = append(data, []byte("foobar")...) r := bytes.NewReader(data) frame, err := ParseStreamFrame(r, versionIETFFrames) Expect(err).ToNot(HaveOccurred()) Expect(frame.StreamID).To(Equal(protocol.StreamID(0x12345))) Expect(frame.Data).To(Equal([]byte("foobar"))) Expect(frame.FinBit).To(BeFalse()) Expect(frame.Offset).To(Equal(protocol.ByteCount(0xdecafbad))) Expect(r.Len()).To(BeZero()) }) It("respects the LEN when parsing the frame", func() { data := []byte{0x10 ^ 0x2} data = append(data, encodeVarInt(0x12345)...) // stream ID data = append(data, encodeVarInt(4)...) // data length data = append(data, []byte("foobar")...) r := bytes.NewReader(data) frame, err := ParseStreamFrame(r, versionIETFFrames) Expect(err).ToNot(HaveOccurred()) Expect(frame.StreamID).To(Equal(protocol.StreamID(0x12345))) Expect(frame.Data).To(Equal([]byte("foob"))) Expect(frame.FinBit).To(BeFalse()) Expect(frame.Offset).To(BeZero()) Expect(r.Len()).To(Equal(2)) }) It("parses a frame with FIN bit", func() { data := []byte{0x10 ^ 0x1} data = append(data, encodeVarInt(9)...) // stream ID data = append(data, []byte("foobar")...) r := bytes.NewReader(data) frame, err := ParseStreamFrame(r, versionIETFFrames) Expect(err).ToNot(HaveOccurred()) Expect(frame.StreamID).To(Equal(protocol.StreamID(9))) Expect(frame.Data).To(Equal([]byte("foobar"))) Expect(frame.FinBit).To(BeTrue()) Expect(frame.Offset).To(BeZero()) Expect(r.Len()).To(BeZero()) }) It("rejects empty frames than don't have the FIN bit set", func() { data := []byte{0x10} data = append(data, encodeVarInt(0x1337)...) // stream ID r := bytes.NewReader(data) _, err := ParseStreamFrame(r, versionIETFFrames) Expect(err).To(MatchError(qerr.EmptyStreamFrameNoFin)) }) It("rejects frames that overflow the maximum offset", func() { data := []byte{0x10 ^ 0x4} data = append(data, encodeVarInt(0x12345)...) // stream ID data = append(data, encodeVarInt(uint64(protocol.MaxByteCount-5))...) // offset data = append(data, []byte("foobar")...) r := bytes.NewReader(data) _, err := ParseStreamFrame(r, versionIETFFrames) Expect(err).To(MatchError(qerr.Error(qerr.InvalidStreamData, "data overflows maximum offset"))) }) It("errors on EOFs", func() { data := []byte{0x10 ^ 0x4 ^ 0x2} data = append(data, encodeVarInt(0x12345)...) // stream ID data = append(data, encodeVarInt(0xdecafbad)...) // offset data = append(data, encodeVarInt(6)...) // data length data = append(data, []byte("foobar")...) _, err := ParseStreamFrame(bytes.NewReader(data), versionIETFFrames) Expect(err).NotTo(HaveOccurred()) for i := range data { _, err := ParseStreamFrame(bytes.NewReader(data[0:i]), versionIETFFrames) Expect(err).To(HaveOccurred()) } }) }) Context("when writing", func() { It("writes a frame without offset", func() { f := &StreamFrame{ StreamID: 0x1337, Data: []byte("foobar"), } b := &bytes.Buffer{} err := f.Write(b, versionIETFFrames) Expect(err).ToNot(HaveOccurred()) expected := []byte{0x10} expected = append(expected, encodeVarInt(0x1337)...) // stream ID expected = append(expected, []byte("foobar")...) Expect(b.Bytes()).To(Equal(expected)) }) It("writes a frame with offset", func() { f := &StreamFrame{ StreamID: 0x1337, Offset: 0x123456, Data: []byte("foobar"), } b := &bytes.Buffer{} err := f.Write(b, versionIETFFrames) Expect(err).ToNot(HaveOccurred()) expected := []byte{0x10 ^ 0x4} expected = append(expected, encodeVarInt(0x1337)...) // stream ID expected = append(expected, encodeVarInt(0x123456)...) // offset expected = append(expected, []byte("foobar")...) Expect(b.Bytes()).To(Equal(expected)) }) It("writes a frame with FIN bit", func() { f := &StreamFrame{ StreamID: 0x1337, Offset: 0x123456, FinBit: true, } b := &bytes.Buffer{} err := f.Write(b, versionIETFFrames) Expect(err).ToNot(HaveOccurred()) expected := []byte{0x10 ^ 0x4 ^ 0x1} expected = append(expected, encodeVarInt(0x1337)...) // stream ID expected = append(expected, encodeVarInt(0x123456)...) // offset Expect(b.Bytes()).To(Equal(expected)) }) It("writes a frame with data length", func() { f := &StreamFrame{ StreamID: 0x1337, Data: []byte("foobar"), DataLenPresent: true, } b := &bytes.Buffer{} err := f.Write(b, versionIETFFrames) Expect(err).ToNot(HaveOccurred()) expected := []byte{0x10 ^ 0x2} expected = append(expected, encodeVarInt(0x1337)...) // stream ID expected = append(expected, encodeVarInt(6)...) // data length expected = append(expected, []byte("foobar")...) Expect(b.Bytes()).To(Equal(expected)) }) It("writes a frame with data length and offset", func() { f := &StreamFrame{ StreamID: 0x1337, Data: []byte("foobar"), DataLenPresent: true, Offset: 0x123456, } b := &bytes.Buffer{} err := f.Write(b, versionIETFFrames) Expect(err).ToNot(HaveOccurred()) expected := []byte{0x10 ^ 0x4 ^ 0x2} expected = append(expected, encodeVarInt(0x1337)...) // stream ID expected = append(expected, encodeVarInt(0x123456)...) // offset expected = append(expected, encodeVarInt(6)...) // data length expected = append(expected, []byte("foobar")...) Expect(b.Bytes()).To(Equal(expected)) }) It("refuses to write an empty frame without FIN", func() { f := &StreamFrame{ StreamID: 0x42, Offset: 0x1337, } b := &bytes.Buffer{} err := f.Write(b, versionIETFFrames) Expect(err).To(MatchError("StreamFrame: attempting to write empty frame without FIN")) }) }) Context("length", func() { It("has the right length for a frame without offset and data length", func() { f := &StreamFrame{ StreamID: 0x1337, Data: []byte("foobar"), } Expect(f.MinLength(versionIETFFrames)).To(Equal(1 + utils.VarIntLen(0x1337))) }) It("has the right length for a frame with offset", func() { f := &StreamFrame{ StreamID: 0x1337, Offset: 0x42, Data: []byte("foobar"), } Expect(f.MinLength(versionIETFFrames)).To(Equal(1 + utils.VarIntLen(0x1337) + utils.VarIntLen(0x42))) }) It("has the right length for a frame with data length", func() { f := &StreamFrame{ StreamID: 0x1337, Offset: 0x1234567, DataLenPresent: true, Data: []byte("foobar"), } Expect(f.MinLength(versionIETFFrames)).To(Equal(1 + utils.VarIntLen(0x1337) + utils.VarIntLen(0x1234567) + utils.VarIntLen(6))) }) }) Context("max data length", func() { const maxSize = 3000 It("always returns a data length such that the resulting frame has the right size, if data length is not present", func() { data := make([]byte, maxSize) f := &StreamFrame{ StreamID: 0x1337, Offset: 0xdeadbeef, } b := &bytes.Buffer{} for i := 1; i < 3000; i++ { b.Reset() f.Data = nil maxDataLen := f.MaxDataLen(protocol.ByteCount(i), versionIETFFrames) if maxDataLen == 0 { // 0 means that no valid STREAM_FRAME can be written // check that writing a minimal size STREAM_FRAME (i.e. with 1 byte data) is actually larger than the desired size f.Data = []byte{0} err := f.Write(b, versionIETFFrames) Expect(err).ToNot(HaveOccurred()) Expect(b.Len()).To(BeNumerically(">", i)) continue } f.Data = data[:int(maxDataLen)] err := f.Write(b, versionIETFFrames) Expect(err).ToNot(HaveOccurred()) Expect(b.Len()).To(Equal(i)) } }) It("always returns a data length such that the resulting frame has the right size, if data length is present", func() { data := make([]byte, maxSize) f := &StreamFrame{ StreamID: 0x1337, Offset: 0xdeadbeef, DataLenPresent: true, } b := &bytes.Buffer{} var frameOneByteTooSmallCounter int for i := 1; i < 3000; i++ { b.Reset() f.Data = nil maxDataLen := f.MaxDataLen(protocol.ByteCount(i), versionIETFFrames) if maxDataLen == 0 { // 0 means that no valid STREAM_FRAME can be written // check that writing a minimal size STREAM_FRAME (i.e. with 1 byte data) is actually larger than the desired size f.Data = []byte{0} err := f.Write(b, versionIETFFrames) Expect(err).ToNot(HaveOccurred()) Expect(b.Len()).To(BeNumerically(">", i)) continue } f.Data = data[:int(maxDataLen)] err := f.Write(b, versionIETFFrames) Expect(err).ToNot(HaveOccurred()) // There's *one* pathological case, where a data length of x can be encoded into 1 byte // but a data lengths of x+1 needs 2 bytes // In that case, it's impossible to create a STREAM_FRAME of the desired size if b.Len() == i-1 { frameOneByteTooSmallCounter++ continue } Expect(b.Len()).To(Equal(i)) } Expect(frameOneByteTooSmallCounter).To(Equal(1)) }) }) })