github.com/metacubex/quic-go@v0.44.1-0.20240520163451-20b689a59136/internal/wire/datagram_frame_test.go (about)

     1  package wire
     2  
     3  import (
     4  	"bytes"
     5  	"io"
     6  
     7  	"github.com/metacubex/quic-go/internal/protocol"
     8  	"github.com/metacubex/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 containing a length", func() {
    17  			data := encodeVarInt(0x6) // length
    18  			data = append(data, []byte("foobar")...)
    19  			frame, l, err := parseDatagramFrame(data, 0x30^0x1, protocol.Version1)
    20  			Expect(err).ToNot(HaveOccurred())
    21  			Expect(frame.Data).To(Equal([]byte("foobar")))
    22  			Expect(frame.DataLenPresent).To(BeTrue())
    23  			Expect(l).To(Equal(len(data)))
    24  		})
    25  
    26  		It("parses a frame without length", func() {
    27  			data := []byte("Lorem ipsum dolor sit amet")
    28  			frame, l, err := parseDatagramFrame(data, 0x30, protocol.Version1)
    29  			Expect(err).ToNot(HaveOccurred())
    30  			Expect(frame.Data).To(Equal([]byte("Lorem ipsum dolor sit amet")))
    31  			Expect(frame.DataLenPresent).To(BeFalse())
    32  			Expect(l).To(Equal(len(data)))
    33  		})
    34  
    35  		It("errors when the length is longer than the rest of the frame", func() {
    36  			data := encodeVarInt(0x6) // length
    37  			data = append(data, []byte("fooba")...)
    38  			_, _, err := parseDatagramFrame(data, 0x30^0x1, protocol.Version1)
    39  			Expect(err).To(MatchError(io.EOF))
    40  		})
    41  
    42  		It("errors on EOFs", func() {
    43  			const typ = 0x30 ^ 0x1
    44  			data := encodeVarInt(6) // length
    45  			data = append(data, []byte("foobar")...)
    46  			_, l, err := parseDatagramFrame(data, typ, protocol.Version1)
    47  			Expect(err).NotTo(HaveOccurred())
    48  			Expect(l).To(Equal(len(data)))
    49  			for i := range data {
    50  				_, _, err = parseDatagramFrame(data[0:i], typ, protocol.Version1)
    51  				Expect(err).To(MatchError(io.EOF))
    52  			}
    53  		})
    54  	})
    55  
    56  	Context("when writing", func() {
    57  		It("writes a frame with length", func() {
    58  			f := &DatagramFrame{
    59  				DataLenPresent: true,
    60  				Data:           []byte("foobar"),
    61  			}
    62  			b, err := f.Append(nil, protocol.Version1)
    63  			Expect(err).ToNot(HaveOccurred())
    64  			expected := []byte{0x30 ^ 0x1}
    65  			expected = append(expected, encodeVarInt(0x6)...)
    66  			expected = append(expected, []byte("foobar")...)
    67  			Expect(b).To(Equal(expected))
    68  		})
    69  
    70  		It("writes a frame without length", func() {
    71  			f := &DatagramFrame{Data: []byte("Lorem ipsum")}
    72  			b, err := f.Append(nil, protocol.Version1)
    73  			Expect(err).ToNot(HaveOccurred())
    74  			expected := []byte{0x30}
    75  			expected = append(expected, []byte("Lorem ipsum")...)
    76  			Expect(b).To(Equal(expected))
    77  		})
    78  	})
    79  
    80  	Context("length", func() {
    81  		It("has the right length for a frame with length", func() {
    82  			f := &DatagramFrame{
    83  				DataLenPresent: true,
    84  				Data:           []byte("foobar"),
    85  			}
    86  			Expect(f.Length(protocol.Version1)).To(BeEquivalentTo(1 + quicvarint.Len(6) + 6))
    87  		})
    88  
    89  		It("has the right length for a frame without length", func() {
    90  			f := &DatagramFrame{Data: []byte("foobar")}
    91  			Expect(f.Length(protocol.Version1)).To(Equal(protocol.ByteCount(1 + 6)))
    92  		})
    93  	})
    94  
    95  	Context("max data length", func() {
    96  		const maxSize = 3000
    97  
    98  		It("returns a data length such that the resulting frame has the right size, if data length is not present", func() {
    99  			data := make([]byte, maxSize)
   100  			f := &DatagramFrame{}
   101  			b := &bytes.Buffer{}
   102  			for i := 1; i < 3000; i++ {
   103  				b.Reset()
   104  				f.Data = nil
   105  				maxDataLen := f.MaxDataLen(protocol.ByteCount(i), protocol.Version1)
   106  				if maxDataLen == 0 { // 0 means that no valid STREAM frame can be written
   107  					// check that writing a minimal size STREAM frame (i.e. with 1 byte data) is actually larger than the desired size
   108  					f.Data = []byte{0}
   109  					b, err := f.Append(nil, protocol.Version1)
   110  					Expect(err).ToNot(HaveOccurred())
   111  					Expect(len(b)).To(BeNumerically(">", i))
   112  					continue
   113  				}
   114  				f.Data = data[:int(maxDataLen)]
   115  				b, err := f.Append(nil, protocol.Version1)
   116  				Expect(err).ToNot(HaveOccurred())
   117  				Expect(b).To(HaveLen(i))
   118  			}
   119  		})
   120  
   121  		It("always returns a data length such that the resulting frame has the right size, if data length is present", func() {
   122  			data := make([]byte, maxSize)
   123  			f := &DatagramFrame{DataLenPresent: true}
   124  			var frameOneByteTooSmallCounter int
   125  			for i := 1; i < 3000; i++ {
   126  				f.Data = nil
   127  				maxDataLen := f.MaxDataLen(protocol.ByteCount(i), protocol.Version1)
   128  				if maxDataLen == 0 { // 0 means that no valid STREAM frame can be written
   129  					// check that writing a minimal size STREAM frame (i.e. with 1 byte data) is actually larger than the desired size
   130  					f.Data = []byte{0}
   131  					b, err := f.Append(nil, protocol.Version1)
   132  					Expect(err).ToNot(HaveOccurred())
   133  					Expect(len(b)).To(BeNumerically(">", i))
   134  					continue
   135  				}
   136  				f.Data = data[:int(maxDataLen)]
   137  				b, err := f.Append(nil, protocol.Version1)
   138  				Expect(err).ToNot(HaveOccurred())
   139  				// There's *one* pathological case, where a data length of x can be encoded into 1 byte
   140  				// but a data lengths of x+1 needs 2 bytes
   141  				// In that case, it's impossible to create a STREAM frame of the desired size
   142  				if len(b) == i-1 {
   143  					frameOneByteTooSmallCounter++
   144  					continue
   145  				}
   146  				Expect(b).To(HaveLen(i))
   147  			}
   148  			Expect(frameOneByteTooSmallCounter).To(Equal(1))
   149  		})
   150  	})
   151  })