github.com/apernet/quic-go@v0.43.1-0.20240515053213-5e9e635fd9f0/internal/wire/crypto_frame_test.go (about)

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