github.com/danielpfeifer02/quic-go-prio-packs@v0.41.0-28/internal/wire/stream_frame_test.go (about)

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