diff --git a/frames/stream_frame.go b/frames/stream_frame.go index 364fd56cc..1e769fcff 100644 --- a/frames/stream_frame.go +++ b/frames/stream_frame.go @@ -11,11 +11,12 @@ import ( // A StreamFrame of QUIC type StreamFrame struct { - FinBit bool - StreamID protocol.StreamID - streamIDLen protocol.ByteCount - Offset protocol.ByteCount - Data []byte + FinBit bool + StreamID protocol.StreamID + streamIDLen protocol.ByteCount + Offset protocol.ByteCount + Data []byte + DataLenPresent bool } var ( @@ -33,7 +34,7 @@ func ParseStreamFrame(r *bytes.Reader) (*StreamFrame, error) { } frame.FinBit = typeByte&0x40 > 0 - dataLenPresent := typeByte&0x20 > 0 + frame.DataLenPresent = typeByte&0x20 > 0 offsetLen := typeByte & 0x1C >> 2 if offsetLen != 0 { offsetLen++ @@ -53,7 +54,7 @@ func ParseStreamFrame(r *bytes.Reader) (*StreamFrame, error) { frame.Offset = protocol.ByteCount(offset) var dataLen uint16 - if dataLenPresent { + if frame.DataLenPresent { dataLen, err = utils.ReadUint16(r) if err != nil { return nil, err @@ -79,10 +80,14 @@ func ParseStreamFrame(r *bytes.Reader) (*StreamFrame, error) { // WriteStreamFrame writes a stream frame. func (f *StreamFrame) Write(b *bytes.Buffer, packetNumber protocol.PacketNumber, packetNumberLen protocol.PacketNumberLen, version protocol.VersionNumber) error { typeByte := uint8(0x80) // sets the leftmost bit to 1 + if f.FinBit { typeByte ^= 0x40 } - typeByte ^= 0x20 // dataLenPresent + + if f.DataLenPresent { + typeByte ^= 0x20 + } offsetLength := f.getOffsetLength() @@ -130,8 +135,12 @@ func (f *StreamFrame) Write(b *bytes.Buffer, packetNumber protocol.PacketNumber, return errInvalidOffsetLen } - utils.WriteUint16(b, uint16(len(f.Data))) + if f.DataLenPresent { + utils.WriteUint16(b, uint16(len(f.Data))) + } + b.Write(f.Data) + return nil } @@ -178,7 +187,12 @@ func (f *StreamFrame) MinLength() protocol.ByteCount { f.calculateStreamIDLength() } - return 1 + f.streamIDLen + f.getOffsetLength() + 2 + 1 + length := protocol.ByteCount(1) + f.streamIDLen + f.getOffsetLength() + if f.DataLenPresent { + length += 2 + } + + return length + 1 } // MaybeSplitOffFrame removes the first n bytes and returns them as a separate frame. If n >= len(n), nil is returned and nothing is modified. diff --git a/frames/stream_frame_test.go b/frames/stream_frame_test.go index 3bf1686bf..769bf401b 100644 --- a/frames/stream_frame_test.go +++ b/frames/stream_frame_test.go @@ -17,16 +17,18 @@ var _ = Describe("StreamFrame", func() { Expect(frame.FinBit).To(BeFalse()) Expect(frame.StreamID).To(Equal(protocol.StreamID(1))) Expect(frame.Offset).To(BeZero()) + Expect(frame.DataLenPresent).To(BeTrue()) Expect(frame.Data).To(Equal([]byte("foobar"))) }) - It("accepts frame without datalength", func() { + It("accepts frame without data length", func() { b := bytes.NewReader([]byte{0x80, 0x1, 'f', 'o', 'o', 'b', 'a', 'r'}) frame, err := ParseStreamFrame(b) Expect(err).ToNot(HaveOccurred()) Expect(frame.FinBit).To(BeFalse()) Expect(frame.StreamID).To(Equal(protocol.StreamID(1))) Expect(frame.Offset).To(BeZero()) + Expect(frame.DataLenPresent).To(BeFalse()) Expect(frame.Data).To(Equal([]byte("foobar"))) }) }) @@ -35,8 +37,9 @@ var _ = Describe("StreamFrame", func() { It("writes sample frame", func() { b := &bytes.Buffer{} (&StreamFrame{ - StreamID: 1, - Data: []byte("foobar"), + StreamID: 1, + Data: []byte("foobar"), + DataLenPresent: true, }).Write(b, 1, protocol.PacketNumberLen6, 0) Expect(b.Bytes()).To(Equal([]byte{0xa0, 0x1, 0x06, 0x00, 'f', 'o', 'o', 'b', 'a', 'r'})) }) @@ -63,6 +66,52 @@ var _ = Describe("StreamFrame", func() { Expect(f.MinLength()).To(Equal(protocol.ByteCount(b.Len()))) }) + Context("data length field", func() { + It("writes the data length", func() { + dataLen := 0x1337 + b := &bytes.Buffer{} + f := &StreamFrame{ + StreamID: 1, + Data: bytes.Repeat([]byte{'f'}, dataLen), + DataLenPresent: true, + Offset: 0, + } + f.Write(b, 1, protocol.PacketNumberLen6, 0) + headerLength := f.MinLength() - 1 + Expect(b.Bytes()[0] & 0x20).To(Equal(uint8(0x20))) + Expect(b.Bytes()[headerLength-2 : headerLength]).To(Equal([]byte{0x37, 0x13})) + }) + + It("omits the data length field", func() { + dataLen := 0x1337 + b := &bytes.Buffer{} + f := &StreamFrame{ + StreamID: 1, + Data: bytes.Repeat([]byte{'f'}, dataLen), + DataLenPresent: false, + Offset: 0, + } + f.Write(b, 1, protocol.PacketNumberLen6, 0) + Expect(b.Bytes()[0] & 0x20).To(Equal(uint8(0))) + Expect(b.Bytes()[1 : b.Len()-dataLen]).ToNot(ContainSubstring(string([]byte{0x37, 0x13}))) + minLength := f.MinLength() + f.DataLenPresent = true + Expect(minLength).To(Equal(f.MinLength() - 2)) + }) + + It("calculates the correcct min-length", func() { + f := &StreamFrame{ + StreamID: 0xCAFE, + Data: []byte("foobar"), + DataLenPresent: false, + Offset: 0xDEADBEEF, + } + minLengthWithoutDataLen := f.MinLength() + f.DataLenPresent = true + Expect(f.MinLength()).To(Equal(minLengthWithoutDataLen + 2)) + }) + }) + Context("offset lengths", func() { It("does not write an offset if the offset is 0", func() { b := &bytes.Buffer{} diff --git a/session_test.go b/session_test.go index 6b0c999bd..e249301a1 100644 --- a/session_test.go +++ b/session_test.go @@ -420,7 +420,7 @@ var _ = Describe("Session", func() { }) It("should call OnSent", func() { - session.QueueStreamFrame(&frames.StreamFrame{StreamID: 5}) + session.QueueStreamFrame(&frames.StreamFrame{StreamID: 5, DataLenPresent: true}) session.sendPacket() Expect(cong.nCalls).To(Equal(2)) // OnPacketSent + GetCongestionWindow Expect(cong.argsOnPacketSent[1]).To(Equal(protocol.ByteCount(27)))