github.com/quic-go/quic-go@v0.44.0/internal/wire/stream_frame_test.go (about)

     1  package wire
     2  
     3  import (
     4  	"bytes"
     5  	"io"
     6  
     7  	"github.com/quic-go/quic-go/internal/protocol"
     8  	"github.com/quic-go/quic-go/quicvarint"
     9  
    10  	. "github.com/onsi/ginkgo/v2"
    11  	. "github.com/onsi/gomega"
    12  )
    13  
    14  var _ = Describe("STREAM frame", func() {
    15  	Context("when parsing", func() {
    16  		It("parses a frame with OFF bit", func() {
    17  			data := encodeVarInt(0x12345)                    // stream ID
    18  			data = append(data, encodeVarInt(0xdecafbad)...) // offset
    19  			data = append(data, []byte("foobar")...)
    20  			frame, l, err := parseStreamFrame(data, 0x8^0x4, protocol.Version1)
    21  			Expect(err).ToNot(HaveOccurred())
    22  			Expect(frame.StreamID).To(Equal(protocol.StreamID(0x12345)))
    23  			Expect(frame.Data).To(Equal([]byte("foobar")))
    24  			Expect(frame.Fin).To(BeFalse())
    25  			Expect(frame.Offset).To(Equal(protocol.ByteCount(0xdecafbad)))
    26  			Expect(l).To(Equal(len(data)))
    27  		})
    28  
    29  		It("respects the LEN when parsing the frame", func() {
    30  			data := encodeVarInt(0x12345)           // stream ID
    31  			data = append(data, encodeVarInt(4)...) // data length
    32  			data = append(data, []byte("foobar")...)
    33  			frame, l, err := parseStreamFrame(data, 0x8^0x2, protocol.Version1)
    34  			Expect(err).ToNot(HaveOccurred())
    35  			Expect(frame.StreamID).To(Equal(protocol.StreamID(0x12345)))
    36  			Expect(frame.Data).To(Equal([]byte("foob")))
    37  			Expect(frame.Fin).To(BeFalse())
    38  			Expect(frame.Offset).To(BeZero())
    39  			Expect(l).To(Equal(len(data) - 2))
    40  		})
    41  
    42  		It("parses a frame with FIN bit", func() {
    43  			data := encodeVarInt(9) // stream ID
    44  			data = append(data, []byte("foobar")...)
    45  			frame, l, err := parseStreamFrame(data, 0x8^0x1, protocol.Version1)
    46  			Expect(err).ToNot(HaveOccurred())
    47  			Expect(frame.StreamID).To(Equal(protocol.StreamID(9)))
    48  			Expect(frame.Data).To(Equal([]byte("foobar")))
    49  			Expect(frame.Fin).To(BeTrue())
    50  			Expect(frame.Offset).To(BeZero())
    51  			Expect(l).To(Equal(len(data)))
    52  		})
    53  
    54  		It("allows empty frames", func() {
    55  			data := encodeVarInt(0x1337)                  // stream ID
    56  			data = append(data, encodeVarInt(0x12345)...) // offset
    57  			f, l, err := parseStreamFrame(data, 0x8^0x4, protocol.Version1)
    58  			Expect(err).ToNot(HaveOccurred())
    59  			Expect(f.StreamID).To(Equal(protocol.StreamID(0x1337)))
    60  			Expect(f.Offset).To(Equal(protocol.ByteCount(0x12345)))
    61  			Expect(f.Data).To(BeEmpty())
    62  			Expect(f.Fin).To(BeFalse())
    63  			Expect(l).To(Equal(len(data)))
    64  		})
    65  
    66  		It("rejects frames that overflow the maximum offset", func() {
    67  			data := encodeVarInt(0x12345)                                         // stream ID
    68  			data = append(data, encodeVarInt(uint64(protocol.MaxByteCount-5))...) // offset
    69  			data = append(data, []byte("foobar")...)
    70  			_, _, err := parseStreamFrame(data, 0x8^0x4, protocol.Version1)
    71  			Expect(err).To(MatchError("stream data overflows maximum offset"))
    72  		})
    73  
    74  		It("rejects frames that claim to be longer than the packet buffer size", func() {
    75  			data := encodeVarInt(0x12345)                                                // stream ID
    76  			data = append(data, encodeVarInt(uint64(protocol.MaxPacketBufferSize)+1)...) // data length
    77  			data = append(data, make([]byte, protocol.MaxPacketBufferSize+1)...)
    78  			_, _, err := parseStreamFrame(data, 0x8^0x2, protocol.Version1)
    79  			Expect(err).To(Equal(io.EOF))
    80  		})
    81  
    82  		It("rejects frames that claim to be longer than the remaining size", func() {
    83  			data := encodeVarInt(0x12345)           // stream ID
    84  			data = append(data, encodeVarInt(7)...) // data length
    85  			data = append(data, []byte("foobar")...)
    86  			_, _, err := parseStreamFrame(data, 0x8^0x2, protocol.Version1)
    87  			Expect(err).To(Equal(io.EOF))
    88  		})
    89  
    90  		It("errors on EOFs", func() {
    91  			typ := uint64(0x8 ^ 0x4 ^ 0x2)
    92  			data := encodeVarInt(0x12345)                    // stream ID
    93  			data = append(data, encodeVarInt(0xdecafbad)...) // offset
    94  			data = append(data, encodeVarInt(6)...)          // data length
    95  			data = append(data, []byte("foobar")...)
    96  			_, _, err := parseStreamFrame(data, typ, protocol.Version1)
    97  			Expect(err).NotTo(HaveOccurred())
    98  			for i := range data {
    99  				_, _, err = parseStreamFrame(data[:i], typ, protocol.Version1)
   100  				Expect(err).To(HaveOccurred())
   101  			}
   102  		})
   103  	})
   104  
   105  	Context("using the buffer", func() {
   106  		It("uses the buffer for long STREAM frames", func() {
   107  			data := encodeVarInt(0x12345) // stream ID
   108  			data = append(data, bytes.Repeat([]byte{'f'}, protocol.MinStreamFrameBufferSize)...)
   109  			frame, l, err := parseStreamFrame(data, 0x8, protocol.Version1)
   110  			Expect(err).ToNot(HaveOccurred())
   111  			Expect(frame.StreamID).To(Equal(protocol.StreamID(0x12345)))
   112  			Expect(frame.Data).To(Equal(bytes.Repeat([]byte{'f'}, protocol.MinStreamFrameBufferSize)))
   113  			Expect(frame.DataLen()).To(BeEquivalentTo(protocol.MinStreamFrameBufferSize))
   114  			Expect(frame.Fin).To(BeFalse())
   115  			Expect(frame.fromPool).To(BeTrue())
   116  			Expect(l).To(Equal(len(data)))
   117  			Expect(frame.PutBack).ToNot(Panic())
   118  		})
   119  
   120  		It("doesn't use the buffer for short STREAM frames", func() {
   121  			data := encodeVarInt(0x12345) // stream ID
   122  			data = append(data, bytes.Repeat([]byte{'f'}, protocol.MinStreamFrameBufferSize-1)...)
   123  			frame, l, err := parseStreamFrame(data, 0x8, protocol.Version1)
   124  			Expect(err).ToNot(HaveOccurred())
   125  			Expect(frame.StreamID).To(Equal(protocol.StreamID(0x12345)))
   126  			Expect(frame.Data).To(Equal(bytes.Repeat([]byte{'f'}, protocol.MinStreamFrameBufferSize-1)))
   127  			Expect(frame.DataLen()).To(BeEquivalentTo(protocol.MinStreamFrameBufferSize - 1))
   128  			Expect(frame.Fin).To(BeFalse())
   129  			Expect(frame.fromPool).To(BeFalse())
   130  			Expect(l).To(Equal(len(data)))
   131  			Expect(frame.PutBack).ToNot(Panic())
   132  		})
   133  	})
   134  
   135  	Context("when writing", func() {
   136  		It("writes a frame without offset", func() {
   137  			f := &StreamFrame{
   138  				StreamID: 0x1337,
   139  				Data:     []byte("foobar"),
   140  			}
   141  			b, err := f.Append(nil, protocol.Version1)
   142  			Expect(err).ToNot(HaveOccurred())
   143  			expected := []byte{0x8}
   144  			expected = append(expected, encodeVarInt(0x1337)...) // stream ID
   145  			expected = append(expected, []byte("foobar")...)
   146  			Expect(b).To(Equal(expected))
   147  		})
   148  
   149  		It("writes a frame with offset", func() {
   150  			f := &StreamFrame{
   151  				StreamID: 0x1337,
   152  				Offset:   0x123456,
   153  				Data:     []byte("foobar"),
   154  			}
   155  			b, err := f.Append(nil, protocol.Version1)
   156  			Expect(err).ToNot(HaveOccurred())
   157  			expected := []byte{0x8 ^ 0x4}
   158  			expected = append(expected, encodeVarInt(0x1337)...)   // stream ID
   159  			expected = append(expected, encodeVarInt(0x123456)...) // offset
   160  			expected = append(expected, []byte("foobar")...)
   161  			Expect(b).To(Equal(expected))
   162  		})
   163  
   164  		It("writes a frame with FIN bit", func() {
   165  			f := &StreamFrame{
   166  				StreamID: 0x1337,
   167  				Offset:   0x123456,
   168  				Fin:      true,
   169  			}
   170  			b, err := f.Append(nil, protocol.Version1)
   171  			Expect(err).ToNot(HaveOccurred())
   172  			expected := []byte{0x8 ^ 0x4 ^ 0x1}
   173  			expected = append(expected, encodeVarInt(0x1337)...)   // stream ID
   174  			expected = append(expected, encodeVarInt(0x123456)...) // offset
   175  			Expect(b).To(Equal(expected))
   176  		})
   177  
   178  		It("writes a frame with data length", func() {
   179  			f := &StreamFrame{
   180  				StreamID:       0x1337,
   181  				Data:           []byte("foobar"),
   182  				DataLenPresent: true,
   183  			}
   184  			b, err := f.Append(nil, protocol.Version1)
   185  			Expect(err).ToNot(HaveOccurred())
   186  			expected := []byte{0x8 ^ 0x2}
   187  			expected = append(expected, encodeVarInt(0x1337)...) // stream ID
   188  			expected = append(expected, encodeVarInt(6)...)      // data length
   189  			expected = append(expected, []byte("foobar")...)
   190  			Expect(b).To(Equal(expected))
   191  		})
   192  
   193  		It("writes a frame with data length and offset", func() {
   194  			f := &StreamFrame{
   195  				StreamID:       0x1337,
   196  				Data:           []byte("foobar"),
   197  				DataLenPresent: true,
   198  				Offset:         0x123456,
   199  			}
   200  			b, err := f.Append(nil, protocol.Version1)
   201  			Expect(err).ToNot(HaveOccurred())
   202  			expected := []byte{0x8 ^ 0x4 ^ 0x2}
   203  			expected = append(expected, encodeVarInt(0x1337)...)   // stream ID
   204  			expected = append(expected, encodeVarInt(0x123456)...) // offset
   205  			expected = append(expected, encodeVarInt(6)...)        // data length
   206  			expected = append(expected, []byte("foobar")...)
   207  			Expect(b).To(Equal(expected))
   208  		})
   209  
   210  		It("refuses to write an empty frame without FIN", func() {
   211  			f := &StreamFrame{
   212  				StreamID: 0x42,
   213  				Offset:   0x1337,
   214  			}
   215  			_, err := f.Append(nil, protocol.Version1)
   216  			Expect(err).To(MatchError("StreamFrame: attempting to write empty frame without FIN"))
   217  		})
   218  	})
   219  
   220  	Context("length", func() {
   221  		It("has the right length for a frame without offset and data length", func() {
   222  			f := &StreamFrame{
   223  				StreamID: 0x1337,
   224  				Data:     []byte("foobar"),
   225  			}
   226  			Expect(f.Length(protocol.Version1)).To(BeEquivalentTo(1 + quicvarint.Len(0x1337) + 6))
   227  		})
   228  
   229  		It("has the right length for a frame with offset", func() {
   230  			f := &StreamFrame{
   231  				StreamID: 0x1337,
   232  				Offset:   0x42,
   233  				Data:     []byte("foobar"),
   234  			}
   235  			Expect(f.Length(protocol.Version1)).To(BeEquivalentTo(1 + quicvarint.Len(0x1337) + quicvarint.Len(0x42) + 6))
   236  		})
   237  
   238  		It("has the right length for a frame with data length", func() {
   239  			f := &StreamFrame{
   240  				StreamID:       0x1337,
   241  				Offset:         0x1234567,
   242  				DataLenPresent: true,
   243  				Data:           []byte("foobar"),
   244  			}
   245  			Expect(f.Length(protocol.Version1)).To(BeEquivalentTo(1 + quicvarint.Len(0x1337) + quicvarint.Len(0x1234567) + quicvarint.Len(6) + 6))
   246  		})
   247  	})
   248  
   249  	Context("max data length", func() {
   250  		const maxSize = 3000
   251  
   252  		It("always returns a data length such that the resulting frame has the right size, if data length is not present", func() {
   253  			data := make([]byte, maxSize)
   254  			f := &StreamFrame{
   255  				StreamID: 0x1337,
   256  				Offset:   0xdeadbeef,
   257  			}
   258  			for i := 1; i < 3000; i++ {
   259  				f.Data = nil
   260  				maxDataLen := f.MaxDataLen(protocol.ByteCount(i), protocol.Version1)
   261  				if maxDataLen == 0 { // 0 means that no valid STREAM frame can be written
   262  					// check that writing a minimal size STREAM frame (i.e. with 1 byte data) is actually larger than the desired size
   263  					f.Data = []byte{0}
   264  					b, err := f.Append(nil, protocol.Version1)
   265  					Expect(err).ToNot(HaveOccurred())
   266  					Expect(len(b)).To(BeNumerically(">", i))
   267  					continue
   268  				}
   269  				f.Data = data[:int(maxDataLen)]
   270  				b, err := f.Append(nil, protocol.Version1)
   271  				Expect(err).ToNot(HaveOccurred())
   272  				Expect(len(b)).To(Equal(i))
   273  			}
   274  		})
   275  
   276  		It("always returns a data length such that the resulting frame has the right size, if data length is present", func() {
   277  			data := make([]byte, maxSize)
   278  			f := &StreamFrame{
   279  				StreamID:       0x1337,
   280  				Offset:         0xdeadbeef,
   281  				DataLenPresent: true,
   282  			}
   283  			var frameOneByteTooSmallCounter int
   284  			for i := 1; i < 3000; i++ {
   285  				f.Data = nil
   286  				maxDataLen := f.MaxDataLen(protocol.ByteCount(i), protocol.Version1)
   287  				if maxDataLen == 0 { // 0 means that no valid STREAM frame can be written
   288  					// check that writing a minimal size STREAM frame (i.e. with 1 byte data) is actually larger than the desired size
   289  					f.Data = []byte{0}
   290  					b, err := f.Append(nil, protocol.Version1)
   291  					Expect(err).ToNot(HaveOccurred())
   292  					Expect(len(b)).To(BeNumerically(">", i))
   293  					continue
   294  				}
   295  				f.Data = data[:int(maxDataLen)]
   296  				b, err := f.Append(nil, protocol.Version1)
   297  				Expect(err).ToNot(HaveOccurred())
   298  				// There's *one* pathological case, where a data length of x can be encoded into 1 byte
   299  				// but a data lengths of x+1 needs 2 bytes
   300  				// In that case, it's impossible to create a STREAM frame of the desired size
   301  				if len(b) == i-1 {
   302  					frameOneByteTooSmallCounter++
   303  					continue
   304  				}
   305  				Expect(len(b)).To(Equal(i))
   306  			}
   307  			Expect(frameOneByteTooSmallCounter).To(Equal(1))
   308  		})
   309  	})
   310  
   311  	Context("splitting", func() {
   312  		It("doesn't split if the frame is short enough", func() {
   313  			f := &StreamFrame{
   314  				StreamID:       0x1337,
   315  				DataLenPresent: true,
   316  				Offset:         0xdeadbeef,
   317  				Data:           make([]byte, 100),
   318  			}
   319  			frame, needsSplit := f.MaybeSplitOffFrame(f.Length(protocol.Version1), protocol.Version1)
   320  			Expect(needsSplit).To(BeFalse())
   321  			Expect(frame).To(BeNil())
   322  			Expect(f.DataLen()).To(BeEquivalentTo(100))
   323  			frame, needsSplit = f.MaybeSplitOffFrame(f.Length(protocol.Version1)-1, protocol.Version1)
   324  			Expect(needsSplit).To(BeTrue())
   325  			Expect(frame.DataLen()).To(BeEquivalentTo(99))
   326  			f.PutBack()
   327  		})
   328  
   329  		It("keeps the data len", func() {
   330  			f := &StreamFrame{
   331  				StreamID:       0x1337,
   332  				DataLenPresent: true,
   333  				Data:           make([]byte, 100),
   334  			}
   335  			frame, needsSplit := f.MaybeSplitOffFrame(66, protocol.Version1)
   336  			Expect(needsSplit).To(BeTrue())
   337  			Expect(frame).ToNot(BeNil())
   338  			Expect(f.DataLenPresent).To(BeTrue())
   339  			Expect(frame.DataLenPresent).To(BeTrue())
   340  		})
   341  
   342  		It("adjusts the offset", func() {
   343  			f := &StreamFrame{
   344  				StreamID: 0x1337,
   345  				Offset:   0x100,
   346  				Data:     []byte("foobar"),
   347  			}
   348  			frame, needsSplit := f.MaybeSplitOffFrame(f.Length(protocol.Version1)-3, protocol.Version1)
   349  			Expect(needsSplit).To(BeTrue())
   350  			Expect(frame).ToNot(BeNil())
   351  			Expect(frame.Offset).To(Equal(protocol.ByteCount(0x100)))
   352  			Expect(frame.Data).To(Equal([]byte("foo")))
   353  			Expect(f.Offset).To(Equal(protocol.ByteCount(0x100 + 3)))
   354  			Expect(f.Data).To(Equal([]byte("bar")))
   355  		})
   356  
   357  		It("preserves the FIN bit", func() {
   358  			f := &StreamFrame{
   359  				StreamID: 0x1337,
   360  				Fin:      true,
   361  				Offset:   0xdeadbeef,
   362  				Data:     make([]byte, 100),
   363  			}
   364  			frame, needsSplit := f.MaybeSplitOffFrame(50, protocol.Version1)
   365  			Expect(needsSplit).To(BeTrue())
   366  			Expect(frame).ToNot(BeNil())
   367  			Expect(frame.Offset).To(BeNumerically("<", f.Offset))
   368  			Expect(f.Fin).To(BeTrue())
   369  			Expect(frame.Fin).To(BeFalse())
   370  		})
   371  
   372  		It("produces frames of the correct length, without data len", func() {
   373  			const size = 1000
   374  			f := &StreamFrame{
   375  				StreamID: 0xdecafbad,
   376  				Offset:   0x1234,
   377  				Data:     []byte{0},
   378  			}
   379  			minFrameSize := f.Length(protocol.Version1)
   380  			for i := protocol.ByteCount(0); i < minFrameSize; i++ {
   381  				f, needsSplit := f.MaybeSplitOffFrame(i, protocol.Version1)
   382  				Expect(needsSplit).To(BeTrue())
   383  				Expect(f).To(BeNil())
   384  			}
   385  			for i := minFrameSize; i < size; i++ {
   386  				f.fromPool = false
   387  				f.Data = make([]byte, size)
   388  				f, needsSplit := f.MaybeSplitOffFrame(i, protocol.Version1)
   389  				Expect(needsSplit).To(BeTrue())
   390  				Expect(f.Length(protocol.Version1)).To(Equal(i))
   391  			}
   392  		})
   393  
   394  		It("produces frames of the correct length, with data len", func() {
   395  			const size = 1000
   396  			f := &StreamFrame{
   397  				StreamID:       0xdecafbad,
   398  				Offset:         0x1234,
   399  				DataLenPresent: true,
   400  				Data:           []byte{0},
   401  			}
   402  			minFrameSize := f.Length(protocol.Version1)
   403  			for i := protocol.ByteCount(0); i < minFrameSize; i++ {
   404  				f, needsSplit := f.MaybeSplitOffFrame(i, protocol.Version1)
   405  				Expect(needsSplit).To(BeTrue())
   406  				Expect(f).To(BeNil())
   407  			}
   408  			var frameOneByteTooSmallCounter int
   409  			for i := minFrameSize; i < size; i++ {
   410  				f.fromPool = false
   411  				f.Data = make([]byte, size)
   412  				newFrame, needsSplit := f.MaybeSplitOffFrame(i, protocol.Version1)
   413  				Expect(needsSplit).To(BeTrue())
   414  				// There's *one* pathological case, where a data length of x can be encoded into 1 byte
   415  				// but a data lengths of x+1 needs 2 bytes
   416  				// In that case, it's impossible to create a STREAM frame of the desired size
   417  				if newFrame.Length(protocol.Version1) == i-1 {
   418  					frameOneByteTooSmallCounter++
   419  					continue
   420  				}
   421  				Expect(newFrame.Length(protocol.Version1)).To(Equal(i))
   422  			}
   423  			Expect(frameOneByteTooSmallCounter).To(Equal(1))
   424  		})
   425  	})
   426  })