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

     1  package wire
     2  
     3  import (
     4  	"io"
     5  
     6  	"github.com/quic-go/quic-go/internal/protocol"
     7  	"github.com/quic-go/quic-go/quicvarint"
     8  
     9  	. "github.com/onsi/ginkgo/v2"
    10  	. "github.com/onsi/gomega"
    11  )
    12  
    13  var _ = Describe("CRYPTO frame", func() {
    14  	Context("when parsing", func() {
    15  		It("parses", func() {
    16  			data := encodeVarInt(0xdecafbad)        // offset
    17  			data = append(data, encodeVarInt(6)...) // length
    18  			data = append(data, []byte("foobar")...)
    19  			frame, l, err := parseCryptoFrame(data, protocol.Version1)
    20  			Expect(err).ToNot(HaveOccurred())
    21  			Expect(frame.Offset).To(Equal(protocol.ByteCount(0xdecafbad)))
    22  			Expect(frame.Data).To(Equal([]byte("foobar")))
    23  			Expect(l).To(Equal(len(data)))
    24  		})
    25  
    26  		It("errors on EOFs", func() {
    27  			data := encodeVarInt(0xdecafbad)        // offset
    28  			data = append(data, encodeVarInt(6)...) // data length
    29  			data = append(data, []byte("foobar")...)
    30  			_, l, err := parseCryptoFrame(data, protocol.Version1)
    31  			Expect(err).NotTo(HaveOccurred())
    32  			Expect(l).To(Equal(len(data)))
    33  			for i := range data {
    34  				_, _, err := parseCryptoFrame(data[:i], protocol.Version1)
    35  				Expect(err).To(MatchError(io.EOF))
    36  			}
    37  		})
    38  	})
    39  
    40  	Context("when writing", func() {
    41  		It("writes a frame", func() {
    42  			f := &CryptoFrame{
    43  				Offset: 0x123456,
    44  				Data:   []byte("foobar"),
    45  			}
    46  			b, err := f.Append(nil, protocol.Version1)
    47  			Expect(err).ToNot(HaveOccurred())
    48  			expected := []byte{cryptoFrameType}
    49  			expected = append(expected, encodeVarInt(0x123456)...) // offset
    50  			expected = append(expected, encodeVarInt(6)...)        // length
    51  			expected = append(expected, []byte("foobar")...)
    52  			Expect(b).To(Equal(expected))
    53  		})
    54  	})
    55  
    56  	Context("max data length", func() {
    57  		const maxSize = 3000
    58  
    59  		It("always returns a data length such that the resulting frame has the right size", func() {
    60  			data := make([]byte, maxSize)
    61  			f := &CryptoFrame{
    62  				Offset: 0xdeadbeef,
    63  			}
    64  			var frameOneByteTooSmallCounter int
    65  			for i := 1; i < maxSize; i++ {
    66  				f.Data = nil
    67  				maxDataLen := f.MaxDataLen(protocol.ByteCount(i))
    68  				if maxDataLen == 0 { // 0 means that no valid CRYTPO frame can be written
    69  					// check that writing a minimal size CRYPTO frame (i.e. with 1 byte data) is actually larger than the desired size
    70  					f.Data = []byte{0}
    71  					b, err := f.Append(nil, protocol.Version1)
    72  					Expect(err).ToNot(HaveOccurred())
    73  					Expect(len(b)).To(BeNumerically(">", i))
    74  					continue
    75  				}
    76  				f.Data = data[:int(maxDataLen)]
    77  				b, err := f.Append(nil, protocol.Version1)
    78  				Expect(err).ToNot(HaveOccurred())
    79  				// There's *one* pathological case, where a data length of x can be encoded into 1 byte
    80  				// but a data lengths of x+1 needs 2 bytes
    81  				// In that case, it's impossible to create a STREAM frame of the desired size
    82  				if len(b) == i-1 {
    83  					frameOneByteTooSmallCounter++
    84  					continue
    85  				}
    86  				Expect(len(b)).To(Equal(i))
    87  			}
    88  			Expect(frameOneByteTooSmallCounter).To(Equal(1))
    89  		})
    90  	})
    91  
    92  	Context("length", func() {
    93  		It("has the right length for a frame without offset and data length", func() {
    94  			f := &CryptoFrame{
    95  				Offset: 0x1337,
    96  				Data:   []byte("foobar"),
    97  			}
    98  			Expect(f.Length(protocol.Version1)).To(BeEquivalentTo(1 + quicvarint.Len(0x1337) + quicvarint.Len(6) + 6))
    99  		})
   100  	})
   101  
   102  	Context("splitting", func() {
   103  		It("splits a frame", func() {
   104  			f := &CryptoFrame{
   105  				Offset: 0x1337,
   106  				Data:   []byte("foobar"),
   107  			}
   108  			hdrLen := f.Length(protocol.Version1) - 6
   109  			new, needsSplit := f.MaybeSplitOffFrame(hdrLen+3, protocol.Version1)
   110  			Expect(needsSplit).To(BeTrue())
   111  			Expect(new.Data).To(Equal([]byte("foo")))
   112  			Expect(new.Offset).To(Equal(protocol.ByteCount(0x1337)))
   113  			Expect(f.Data).To(Equal([]byte("bar")))
   114  			Expect(f.Offset).To(Equal(protocol.ByteCount(0x1337 + 3)))
   115  		})
   116  
   117  		It("doesn't split if there's enough space in the frame", func() {
   118  			f := &CryptoFrame{
   119  				Offset: 0x1337,
   120  				Data:   []byte("foobar"),
   121  			}
   122  			f, needsSplit := f.MaybeSplitOffFrame(f.Length(protocol.Version1), protocol.Version1)
   123  			Expect(needsSplit).To(BeFalse())
   124  			Expect(f).To(BeNil())
   125  		})
   126  
   127  		It("doesn't split if the size is too small", func() {
   128  			f := &CryptoFrame{
   129  				Offset: 0x1337,
   130  				Data:   []byte("foobar"),
   131  			}
   132  			length := f.Length(protocol.Version1) - 6
   133  			for i := protocol.ByteCount(0); i <= length; i++ {
   134  				f, needsSplit := f.MaybeSplitOffFrame(i, protocol.Version1)
   135  				Expect(needsSplit).To(BeTrue())
   136  				Expect(f).To(BeNil())
   137  			}
   138  			f, needsSplit := f.MaybeSplitOffFrame(length+1, protocol.Version1)
   139  			Expect(needsSplit).To(BeTrue())
   140  			Expect(f).ToNot(BeNil())
   141  		})
   142  	})
   143  })