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

     1  package wire
     2  
     3  import (
     4  	"bytes"
     5  	"crypto/rand"
     6  	"encoding/binary"
     7  	"io"
     8  	mrand "math/rand"
     9  	"testing"
    10  	"time"
    11  
    12  	"github.com/metacubex/quic-go/internal/protocol"
    13  
    14  	. "github.com/onsi/ginkgo/v2"
    15  	. "github.com/onsi/gomega"
    16  )
    17  
    18  var _ = Describe("Header Parsing", func() {
    19  	Context("Parsing the Connection ID", func() {
    20  		It("parses the connection ID of a long header packet", func() {
    21  			b, err := (&ExtendedHeader{
    22  				Header: Header{
    23  					Type:             protocol.PacketTypeHandshake,
    24  					DestConnectionID: protocol.ParseConnectionID([]byte{0xde, 0xca, 0xfb, 0xad}),
    25  					SrcConnectionID:  protocol.ParseConnectionID([]byte{1, 2, 3, 4, 5, 6}),
    26  					Version:          protocol.Version1,
    27  				},
    28  				PacketNumberLen: 2,
    29  			}).Append(nil, protocol.Version1)
    30  			Expect(err).ToNot(HaveOccurred())
    31  			connID, err := ParseConnectionID(b, 8)
    32  			Expect(err).ToNot(HaveOccurred())
    33  			Expect(connID).To(Equal(protocol.ParseConnectionID([]byte{0xde, 0xca, 0xfb, 0xad})))
    34  		})
    35  
    36  		It("errors on EOF, for long header packets", func() {
    37  			b, err := (&ExtendedHeader{
    38  				Header: Header{
    39  					Type:             protocol.PacketTypeHandshake,
    40  					DestConnectionID: protocol.ParseConnectionID([]byte{0xde, 0xca, 0xfb, 0xad, 0x13, 0x37}),
    41  					SrcConnectionID:  protocol.ParseConnectionID([]byte{1, 2, 3, 4, 5, 6, 8, 9}),
    42  					Version:          protocol.Version1,
    43  				},
    44  				PacketNumberLen: 2,
    45  			}).Append(nil, protocol.Version1)
    46  			Expect(err).ToNot(HaveOccurred())
    47  			data := b[:len(b)-2] // cut the packet number
    48  			_, err = ParseConnectionID(data, 8)
    49  			Expect(err).ToNot(HaveOccurred())
    50  			for i := 0; i < 1 /* first byte */ +4 /* version */ +1 /* conn ID lengths */ +6; /* dest conn ID */ i++ {
    51  				b := make([]byte, i)
    52  				copy(b, data[:i])
    53  				_, err := ParseConnectionID(b, 8)
    54  				Expect(err).To(MatchError(io.EOF))
    55  			}
    56  		})
    57  
    58  		It("errors when encountering a too long connection ID", func() {
    59  			b := []byte{0x80, 0, 0, 0, 0}
    60  			binary.BigEndian.PutUint32(b[1:], uint32(protocol.Version1))
    61  			b = append(b, 21) // dest conn id len
    62  			b = append(b, make([]byte, 21)...)
    63  			_, err := ParseConnectionID(b, 4)
    64  			Expect(err).To(MatchError(protocol.ErrInvalidConnectionIDLen))
    65  		})
    66  	})
    67  
    68  	Context("identifying 0-RTT packets", func() {
    69  		It("recognizes 0-RTT packets, for QUIC v1", func() {
    70  			zeroRTTHeader := make([]byte, 5)
    71  			zeroRTTHeader[0] = 0x80 | 0b01<<4
    72  			binary.BigEndian.PutUint32(zeroRTTHeader[1:], uint32(protocol.Version1))
    73  
    74  			Expect(Is0RTTPacket(zeroRTTHeader)).To(BeTrue())
    75  			Expect(Is0RTTPacket(zeroRTTHeader[:4])).To(BeFalse())                           // too short
    76  			Expect(Is0RTTPacket([]byte{zeroRTTHeader[0], 1, 2, 3, 4})).To(BeFalse())        // unknown version
    77  			Expect(Is0RTTPacket([]byte{zeroRTTHeader[0] | 0x80, 1, 2, 3, 4})).To(BeFalse()) // short header
    78  			Expect(Is0RTTPacket(append(zeroRTTHeader, []byte("foobar")...))).To(BeTrue())
    79  		})
    80  
    81  		It("recognizes 0-RTT packets, for QUIC v2", func() {
    82  			zeroRTTHeader := make([]byte, 5)
    83  			zeroRTTHeader[0] = 0x80 | 0b10<<4
    84  			binary.BigEndian.PutUint32(zeroRTTHeader[1:], uint32(protocol.Version2))
    85  
    86  			Expect(Is0RTTPacket(zeroRTTHeader)).To(BeTrue())
    87  			Expect(Is0RTTPacket(zeroRTTHeader[:4])).To(BeFalse())                           // too short
    88  			Expect(Is0RTTPacket([]byte{zeroRTTHeader[0], 1, 2, 3, 4})).To(BeFalse())        // unknown version
    89  			Expect(Is0RTTPacket([]byte{zeroRTTHeader[0] | 0x80, 1, 2, 3, 4})).To(BeFalse()) // short header
    90  			Expect(Is0RTTPacket(append(zeroRTTHeader, []byte("foobar")...))).To(BeTrue())
    91  		})
    92  	})
    93  	Context("parsing the version", func() {
    94  		It("parses the version", func() {
    95  			b := []byte{0x80, 0xde, 0xad, 0xbe, 0xef}
    96  			v, err := ParseVersion(b)
    97  			Expect(err).ToNot(HaveOccurred())
    98  			Expect(v).To(Equal(protocol.Version(0xdeadbeef)))
    99  		})
   100  
   101  		It("errors with EOF", func() {
   102  			b := []byte{0x80, 0xde, 0xad, 0xbe, 0xef}
   103  			_, err := ParseVersion(b)
   104  			Expect(err).ToNot(HaveOccurred())
   105  			for i := range b {
   106  				_, err := ParseVersion(b[:i])
   107  				Expect(err).To(MatchError(io.EOF))
   108  			}
   109  		})
   110  	})
   111  
   112  	Context("parsing arbitrary length connection IDs", func() {
   113  		generateConnID := func(l int) protocol.ArbitraryLenConnectionID {
   114  			c := make(protocol.ArbitraryLenConnectionID, l)
   115  			rand.Read(c)
   116  			return c
   117  		}
   118  
   119  		generatePacket := func(src, dest protocol.ArbitraryLenConnectionID) []byte {
   120  			b := []byte{0x80, 1, 2, 3, 4}
   121  			b = append(b, uint8(dest.Len()))
   122  			b = append(b, dest.Bytes()...)
   123  			b = append(b, uint8(src.Len()))
   124  			b = append(b, src.Bytes()...)
   125  			return b
   126  		}
   127  
   128  		It("parses arbitrary length connection IDs", func() {
   129  			src := generateConnID(mrand.Intn(255) + 1)
   130  			dest := generateConnID(mrand.Intn(255) + 1)
   131  			b := generatePacket(src, dest)
   132  			l := len(b)
   133  			b = append(b, []byte("foobar")...) // add some payload
   134  
   135  			parsed, d, s, err := ParseArbitraryLenConnectionIDs(b)
   136  			Expect(parsed).To(Equal(l))
   137  			Expect(err).ToNot(HaveOccurred())
   138  			Expect(s).To(Equal(src))
   139  			Expect(d).To(Equal(dest))
   140  		})
   141  
   142  		It("errors on EOF", func() {
   143  			b := generatePacket(generateConnID(mrand.Intn(255)+1), generateConnID(mrand.Intn(255)+1))
   144  			_, _, _, err := ParseArbitraryLenConnectionIDs(b)
   145  			Expect(err).ToNot(HaveOccurred())
   146  
   147  			for i := range b {
   148  				_, _, _, err := ParseArbitraryLenConnectionIDs(b[:i])
   149  				Expect(err).To(MatchError(io.EOF))
   150  			}
   151  		})
   152  	})
   153  
   154  	Context("Identifying Version Negotiation Packets", func() {
   155  		It("identifies version negotiation packets", func() {
   156  			Expect(IsVersionNegotiationPacket([]byte{0x80 | 0x56, 0, 0, 0, 0})).To(BeTrue())
   157  			Expect(IsVersionNegotiationPacket([]byte{0x56, 0, 0, 0, 0})).To(BeFalse())
   158  			Expect(IsVersionNegotiationPacket([]byte{0x80, 1, 0, 0, 0})).To(BeFalse())
   159  			Expect(IsVersionNegotiationPacket([]byte{0x80, 0, 1, 0, 0})).To(BeFalse())
   160  			Expect(IsVersionNegotiationPacket([]byte{0x80, 0, 0, 1, 0})).To(BeFalse())
   161  			Expect(IsVersionNegotiationPacket([]byte{0x80, 0, 0, 0, 1})).To(BeFalse())
   162  		})
   163  
   164  		It("returns false on EOF", func() {
   165  			vnp := []byte{0x80, 0, 0, 0, 0}
   166  			for i := range vnp {
   167  				Expect(IsVersionNegotiationPacket(vnp[:i])).To(BeFalse())
   168  			}
   169  		})
   170  	})
   171  
   172  	Context("Long Headers", func() {
   173  		It("parses a Long Header", func() {
   174  			destConnID := protocol.ParseConnectionID([]byte{9, 8, 7, 6, 5, 4, 3, 2, 1})
   175  			srcConnID := protocol.ParseConnectionID([]byte{0xde, 0xad, 0xbe, 0xef})
   176  			data := []byte{0xc0 ^ 0x3}
   177  			data = appendVersion(data, protocol.Version1)
   178  			data = append(data, 0x9) // dest conn id length
   179  			data = append(data, destConnID.Bytes()...)
   180  			data = append(data, 0x4) // src conn id length
   181  			data = append(data, srcConnID.Bytes()...)
   182  			data = append(data, encodeVarInt(6)...)  // token length
   183  			data = append(data, []byte("foobar")...) // token
   184  			data = append(data, encodeVarInt(10)...) // length
   185  			hdrLen := len(data)
   186  			data = append(data, []byte{0, 0, 0xbe, 0xef}...) // packet number
   187  			data = append(data, []byte("foobar")...)
   188  			Expect(IsVersionNegotiationPacket(data)).To(BeFalse())
   189  
   190  			hdr, pdata, rest, err := ParsePacket(data)
   191  			Expect(err).ToNot(HaveOccurred())
   192  			Expect(pdata).To(Equal(data))
   193  			Expect(hdr.DestConnectionID).To(Equal(destConnID))
   194  			Expect(hdr.SrcConnectionID).To(Equal(srcConnID))
   195  			Expect(hdr.Type).To(Equal(protocol.PacketTypeInitial))
   196  			Expect(hdr.Token).To(Equal([]byte("foobar")))
   197  			Expect(hdr.Length).To(Equal(protocol.ByteCount(10)))
   198  			Expect(hdr.Version).To(Equal(protocol.Version1))
   199  			Expect(rest).To(BeEmpty())
   200  			b := bytes.NewReader(data)
   201  			extHdr, err := hdr.ParseExtended(b, protocol.Version1)
   202  			Expect(err).ToNot(HaveOccurred())
   203  			Expect(extHdr.PacketNumber).To(Equal(protocol.PacketNumber(0xbeef)))
   204  			Expect(extHdr.PacketNumberLen).To(Equal(protocol.PacketNumberLen4))
   205  			Expect(b.Len()).To(Equal(6)) // foobar
   206  			Expect(hdr.ParsedLen()).To(BeEquivalentTo(hdrLen))
   207  			Expect(extHdr.ParsedLen()).To(Equal(hdr.ParsedLen() + 4))
   208  		})
   209  
   210  		It("errors if 0x40 is not set", func() {
   211  			data := []byte{
   212  				0x80 | 0x2<<4,
   213  				0x11,                   // connection ID lengths
   214  				0xde, 0xca, 0xfb, 0xad, // dest conn ID
   215  				0xde, 0xad, 0xbe, 0xef, // src conn ID
   216  			}
   217  			_, _, _, err := ParsePacket(data)
   218  			Expect(err).To(MatchError("not a QUIC packet"))
   219  		})
   220  
   221  		It("stops parsing when encountering an unsupported version", func() {
   222  			data := []byte{
   223  				0xc0,
   224  				0xde, 0xad, 0xbe, 0xef,
   225  				0x8,                                    // dest conn ID len
   226  				0x1, 0x2, 0x3, 0x4, 0x5, 0x6, 0x7, 0x8, // dest conn ID
   227  				0x8,                                    // src conn ID len
   228  				0x8, 0x7, 0x6, 0x5, 0x4, 0x3, 0x2, 0x1, // src conn ID
   229  				'f', 'o', 'o', 'b', 'a', 'r', // unspecified bytes
   230  			}
   231  			hdr, _, rest, err := ParsePacket(data)
   232  			Expect(err).To(MatchError(ErrUnsupportedVersion))
   233  			Expect(hdr.Version).To(Equal(protocol.Version(0xdeadbeef)))
   234  			Expect(hdr.DestConnectionID).To(Equal(protocol.ParseConnectionID([]byte{0x1, 0x2, 0x3, 0x4, 0x5, 0x6, 0x7, 0x8})))
   235  			Expect(hdr.SrcConnectionID).To(Equal(protocol.ParseConnectionID([]byte{0x8, 0x7, 0x6, 0x5, 0x4, 0x3, 0x2, 0x1})))
   236  			Expect(rest).To(BeEmpty())
   237  		})
   238  
   239  		It("parses a Long Header without a destination connection ID", func() {
   240  			data := []byte{0xc0 ^ 0x1<<4}
   241  			data = appendVersion(data, protocol.Version1)
   242  			data = append(data, 0)                                 // dest conn ID len
   243  			data = append(data, 4)                                 // src conn ID len
   244  			data = append(data, []byte{0xde, 0xad, 0xbe, 0xef}...) // source connection ID
   245  			data = append(data, encodeVarInt(0)...)                // length
   246  			data = append(data, []byte{0xde, 0xca, 0xfb, 0xad}...)
   247  			hdr, _, _, err := ParsePacket(data)
   248  			Expect(err).ToNot(HaveOccurred())
   249  			Expect(hdr.Type).To(Equal(protocol.PacketType0RTT))
   250  			Expect(hdr.SrcConnectionID).To(Equal(protocol.ParseConnectionID([]byte{0xde, 0xad, 0xbe, 0xef})))
   251  			Expect(hdr.DestConnectionID).To(BeZero())
   252  		})
   253  
   254  		It("parses a Long Header without a source connection ID", func() {
   255  			data := []byte{0xc0 ^ 0x2<<4}
   256  			data = appendVersion(data, protocol.Version1)
   257  			data = append(data, 10)                                       // dest conn ID len
   258  			data = append(data, []byte{1, 2, 3, 4, 5, 6, 7, 8, 9, 10}...) // dest connection ID
   259  			data = append(data, 0)                                        // src conn ID len
   260  			data = append(data, encodeVarInt(0)...)                       // length
   261  			data = append(data, []byte{0xde, 0xca, 0xfb, 0xad}...)
   262  			hdr, _, _, err := ParsePacket(data)
   263  			Expect(err).ToNot(HaveOccurred())
   264  			Expect(hdr.SrcConnectionID).To(BeZero())
   265  			Expect(hdr.DestConnectionID).To(Equal(protocol.ParseConnectionID([]byte{1, 2, 3, 4, 5, 6, 7, 8, 9, 10})))
   266  		})
   267  
   268  		It("parses a Long Header without a too long destination connection ID", func() {
   269  			data := []byte{0xc0 ^ 0x2<<4}
   270  			data = appendVersion(data, protocol.Version1)
   271  			data = append(data, 21)                                                                                   // dest conn ID len
   272  			data = append(data, []byte{1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21}...) // dest connection ID
   273  			data = append(data, 0x0)                                                                                  // src conn ID len
   274  			data = append(data, encodeVarInt(0)...)                                                                   // length
   275  			data = append(data, []byte{0xde, 0xca, 0xfb, 0xad}...)
   276  			_, _, _, err := ParsePacket(data)
   277  			Expect(err).To(MatchError(protocol.ErrInvalidConnectionIDLen))
   278  		})
   279  
   280  		It("parses a Long Header with a 2 byte packet number", func() {
   281  			data := []byte{0xc0 ^ 0x1}
   282  			data = appendVersion(data, protocol.Version1) // version number
   283  			data = append(data, []byte{0x0, 0x0}...)      // connection ID lengths
   284  			data = append(data, encodeVarInt(0)...)       // token length
   285  			data = append(data, encodeVarInt(0)...)       // length
   286  			data = append(data, []byte{0x1, 0x23}...)
   287  
   288  			hdr, _, _, err := ParsePacket(data)
   289  			Expect(err).ToNot(HaveOccurred())
   290  			b := bytes.NewReader(data)
   291  			extHdr, err := hdr.ParseExtended(b, protocol.Version1)
   292  			Expect(err).ToNot(HaveOccurred())
   293  			Expect(extHdr.PacketNumber).To(Equal(protocol.PacketNumber(0x123)))
   294  			Expect(extHdr.PacketNumberLen).To(Equal(protocol.PacketNumberLen2))
   295  			Expect(b.Len()).To(BeZero())
   296  		})
   297  
   298  		It("parses a Retry packet, for QUIC v1", func() {
   299  			data := []byte{0xc0 | 0b11<<4 | (10 - 3) /* connection ID length */}
   300  			data = appendVersion(data, protocol.Version1)
   301  			data = append(data, []byte{6}...)                             // dest conn ID len
   302  			data = append(data, []byte{6, 5, 4, 3, 2, 1}...)              // dest conn ID
   303  			data = append(data, []byte{10}...)                            // src conn ID len
   304  			data = append(data, []byte{1, 2, 3, 4, 5, 6, 7, 8, 9, 10}...) // source connection ID
   305  			data = append(data, []byte{'f', 'o', 'o', 'b', 'a', 'r'}...)  // token
   306  			data = append(data, []byte{16, 15, 14, 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1}...)
   307  			hdr, pdata, rest, err := ParsePacket(data)
   308  			Expect(err).ToNot(HaveOccurred())
   309  			Expect(hdr.Type).To(Equal(protocol.PacketTypeRetry))
   310  			Expect(hdr.Version).To(Equal(protocol.Version1))
   311  			Expect(hdr.DestConnectionID).To(Equal(protocol.ParseConnectionID([]byte{6, 5, 4, 3, 2, 1})))
   312  			Expect(hdr.SrcConnectionID).To(Equal(protocol.ParseConnectionID([]byte{1, 2, 3, 4, 5, 6, 7, 8, 9, 10})))
   313  			Expect(hdr.Token).To(Equal([]byte("foobar")))
   314  			Expect(pdata).To(Equal(data))
   315  			Expect(rest).To(BeEmpty())
   316  		})
   317  
   318  		It("parses a Retry packet, for QUIC v2", func() {
   319  			data := []byte{0xc0 | 0b00<<4 | (10 - 3) /* connection ID length */}
   320  			data = appendVersion(data, protocol.Version2)
   321  			data = append(data, []byte{6}...)                             // dest conn ID len
   322  			data = append(data, []byte{6, 5, 4, 3, 2, 1}...)              // dest conn ID
   323  			data = append(data, []byte{10}...)                            // src conn ID len
   324  			data = append(data, []byte{1, 2, 3, 4, 5, 6, 7, 8, 9, 10}...) // source connection ID
   325  			data = append(data, []byte{'f', 'o', 'o', 'b', 'a', 'r'}...)  // token
   326  			data = append(data, []byte{16, 15, 14, 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1}...)
   327  			hdr, pdata, rest, err := ParsePacket(data)
   328  			Expect(err).ToNot(HaveOccurred())
   329  			Expect(hdr.Type).To(Equal(protocol.PacketTypeRetry))
   330  			Expect(hdr.Version).To(Equal(protocol.Version2))
   331  			Expect(hdr.DestConnectionID).To(Equal(protocol.ParseConnectionID([]byte{6, 5, 4, 3, 2, 1})))
   332  			Expect(hdr.SrcConnectionID).To(Equal(protocol.ParseConnectionID([]byte{1, 2, 3, 4, 5, 6, 7, 8, 9, 10})))
   333  			Expect(hdr.Token).To(Equal([]byte("foobar")))
   334  			Expect(pdata).To(Equal(data))
   335  			Expect(rest).To(BeEmpty())
   336  		})
   337  
   338  		It("errors if the Retry packet is too short for the integrity tag", func() {
   339  			data := []byte{0xc0 | 0x3<<4 | (10 - 3) /* connection ID length */}
   340  			data = appendVersion(data, protocol.Version1)
   341  			data = append(data, []byte{0, 0}...)                         // conn ID lens
   342  			data = append(data, []byte{'f', 'o', 'o', 'b', 'a', 'r'}...) // token
   343  			data = append(data, []byte{1, 2, 3, 4, 5, 6, 7, 8, 9, 10}...)
   344  			// this results in a token length of 0
   345  			_, _, _, err := ParsePacket(data)
   346  			Expect(err).To(MatchError(io.EOF))
   347  		})
   348  
   349  		It("errors if the token length is too large", func() {
   350  			data := []byte{0xc0 ^ 0x1}
   351  			data = appendVersion(data, protocol.Version1)
   352  			data = append(data, 0x0)                   // connection ID lengths
   353  			data = append(data, encodeVarInt(4)...)    // token length: 4 bytes (1 byte too long)
   354  			data = append(data, encodeVarInt(0x42)...) // length, 1 byte
   355  			data = append(data, []byte{0x12, 0x34}...) // packet number
   356  
   357  			_, _, _, err := ParsePacket(data)
   358  			Expect(err).To(MatchError(io.EOF))
   359  		})
   360  
   361  		It("errors if the 5th or 6th bit are set", func() {
   362  			data := []byte{0xc0 | 0x2<<4 | 0x8 /* set the 5th bit */ | 0x1 /* 2 byte packet number */}
   363  			data = appendVersion(data, protocol.Version1)
   364  			data = append(data, []byte{0x0, 0x0}...)   // connection ID lengths
   365  			data = append(data, encodeVarInt(2)...)    // length
   366  			data = append(data, []byte{0x12, 0x34}...) // packet number
   367  			hdr, _, _, err := ParsePacket(data)
   368  			Expect(err).ToNot(HaveOccurred())
   369  			Expect(hdr.Type).To(Equal(protocol.PacketTypeHandshake))
   370  			extHdr, err := hdr.ParseExtended(bytes.NewReader(data), protocol.Version1)
   371  			Expect(err).To(MatchError(ErrInvalidReservedBits))
   372  			Expect(extHdr).ToNot(BeNil())
   373  			Expect(extHdr.PacketNumber).To(Equal(protocol.PacketNumber(0x1234)))
   374  		})
   375  
   376  		It("errors on EOF, when parsing the header", func() {
   377  			data := []byte{0xc0 ^ 0x2<<4}
   378  			data = appendVersion(data, protocol.Version1)
   379  			data = append(data, 0x8)                                                       // dest conn ID len
   380  			data = append(data, []byte{0xde, 0xad, 0xbe, 0xef, 0xca, 0xfe, 0x13, 0x37}...) // dest conn ID
   381  			data = append(data, 0x8)                                                       // src conn ID len
   382  			data = append(data, []byte{0xde, 0xad, 0xbe, 0xef, 0xca, 0xfe, 0x13, 0x37}...) // src conn ID
   383  			for i := 1; i < len(data); i++ {
   384  				_, _, _, err := ParsePacket(data[:i])
   385  				Expect(err).To(Equal(io.EOF))
   386  			}
   387  		})
   388  
   389  		It("errors on EOF, when parsing the extended header", func() {
   390  			data := []byte{0xc0 | 0x2<<4 | 0x3}
   391  			data = appendVersion(data, protocol.Version1)
   392  			data = append(data, []byte{0x0, 0x0}...) // connection ID lengths
   393  			data = append(data, encodeVarInt(0)...)  // length
   394  			hdrLen := len(data)
   395  			data = append(data, []byte{0xde, 0xad, 0xbe, 0xef}...) // packet number
   396  			for i := hdrLen; i < len(data); i++ {
   397  				data = data[:i]
   398  				hdr, _, _, err := ParsePacket(data)
   399  				Expect(err).ToNot(HaveOccurred())
   400  				b := bytes.NewReader(data)
   401  				_, err = hdr.ParseExtended(b, protocol.Version1)
   402  				Expect(err).To(Equal(io.EOF))
   403  			}
   404  		})
   405  
   406  		It("errors on EOF, for a Retry packet", func() {
   407  			data := []byte{0xc0 ^ 0x3<<4}
   408  			data = appendVersion(data, protocol.Version1)
   409  			data = append(data, []byte{0x0, 0x0}...)                      // connection ID lengths
   410  			data = append(data, 0xa)                                      // Orig Destination Connection ID length
   411  			data = append(data, []byte{1, 2, 3, 4, 5, 6, 7, 8, 9, 10}...) // source connection ID
   412  			hdrLen := len(data)
   413  			for i := hdrLen; i < len(data); i++ {
   414  				data = data[:i]
   415  				hdr, _, _, err := ParsePacket(data)
   416  				Expect(err).ToNot(HaveOccurred())
   417  				b := bytes.NewReader(data)
   418  				_, err = hdr.ParseExtended(b, protocol.Version1)
   419  				Expect(err).To(Equal(io.EOF))
   420  			}
   421  		})
   422  
   423  		Context("coalesced packets", func() {
   424  			It("cuts packets", func() {
   425  				hdr := Header{
   426  					Type:             protocol.PacketTypeInitial,
   427  					DestConnectionID: protocol.ParseConnectionID([]byte{1, 2, 3, 4}),
   428  					Length:           2 + 6,
   429  					Version:          protocol.Version1,
   430  				}
   431  				b, err := (&ExtendedHeader{
   432  					Header:          hdr,
   433  					PacketNumber:    0x1337,
   434  					PacketNumberLen: 2,
   435  				}).Append(nil, protocol.Version1)
   436  				Expect(err).ToNot(HaveOccurred())
   437  				hdrRaw := append([]byte{}, b...)
   438  				b = append(b, []byte("foobar")...) // payload of the first packet
   439  				b = append(b, []byte("raboof")...) // second packet
   440  				parsedHdr, data, rest, err := ParsePacket(b)
   441  				Expect(err).ToNot(HaveOccurred())
   442  				Expect(parsedHdr.Type).To(Equal(hdr.Type))
   443  				Expect(parsedHdr.DestConnectionID).To(Equal(hdr.DestConnectionID))
   444  				Expect(data).To(Equal(append(hdrRaw, []byte("foobar")...)))
   445  				Expect(rest).To(Equal([]byte("raboof")))
   446  			})
   447  
   448  			It("errors on packets that are smaller than the length in the packet header, for too small packet number", func() {
   449  				b, err := (&ExtendedHeader{
   450  					Header: Header{
   451  						Type:             protocol.PacketTypeInitial,
   452  						DestConnectionID: protocol.ParseConnectionID([]byte{1, 2, 3, 4}),
   453  						Length:           3,
   454  						Version:          protocol.Version1,
   455  					},
   456  					PacketNumber:    0x1337,
   457  					PacketNumberLen: 2,
   458  				}).Append(nil, protocol.Version1)
   459  				Expect(err).ToNot(HaveOccurred())
   460  				_, _, _, err = ParsePacket(b)
   461  				Expect(err).To(HaveOccurred())
   462  				Expect(err.Error()).To(ContainSubstring("packet length (2 bytes) is smaller than the expected length (3 bytes)"))
   463  			})
   464  
   465  			It("errors on packets that are smaller than the length in the packet header, for too small payload", func() {
   466  				b, err := (&ExtendedHeader{
   467  					Header: Header{
   468  						Type:             protocol.PacketTypeInitial,
   469  						DestConnectionID: protocol.ParseConnectionID([]byte{1, 2, 3, 4}),
   470  						Length:           1000,
   471  						Version:          protocol.Version1,
   472  					},
   473  					PacketNumber:    0x1337,
   474  					PacketNumberLen: 2,
   475  				}).Append(nil, protocol.Version1)
   476  				Expect(err).ToNot(HaveOccurred())
   477  				b = append(b, make([]byte, 500-2 /* for packet number length */)...)
   478  				_, _, _, err = ParsePacket(b)
   479  				Expect(err).To(MatchError("packet length (500 bytes) is smaller than the expected length (1000 bytes)"))
   480  			})
   481  		})
   482  	})
   483  
   484  	It("distinguishes long and short header packets", func() {
   485  		Expect(IsLongHeaderPacket(0x40)).To(BeFalse())
   486  		Expect(IsLongHeaderPacket(0x80 ^ 0x40 ^ 0x12)).To(BeTrue())
   487  	})
   488  
   489  	It("tells its packet type for logging", func() {
   490  		Expect((&Header{Type: protocol.PacketTypeInitial}).PacketType()).To(Equal("Initial"))
   491  		Expect((&Header{Type: protocol.PacketTypeHandshake}).PacketType()).To(Equal("Handshake"))
   492  	})
   493  })
   494  
   495  func BenchmarkIs0RTTPacket(b *testing.B) {
   496  	random := mrand.New(mrand.NewSource(time.Now().UnixNano()))
   497  	packets := make([][]byte, 1024)
   498  	for i := 0; i < len(packets); i++ {
   499  		packets[i] = make([]byte, random.Intn(256))
   500  		random.Read(packets[i])
   501  	}
   502  
   503  	b.ResetTimer()
   504  	for i := 0; i < b.N; i++ {
   505  		Is0RTTPacket(packets[i%len(packets)])
   506  	}
   507  }
   508  
   509  func BenchmarkParseInitial(b *testing.B) {
   510  	b.Run("without token", func(b *testing.B) {
   511  		benchmarkInitialPacketParsing(b, nil)
   512  	})
   513  	b.Run("with token", func(b *testing.B) {
   514  		token := make([]byte, 32)
   515  		rand.Read(token)
   516  		benchmarkInitialPacketParsing(b, token)
   517  	})
   518  }
   519  
   520  func benchmarkInitialPacketParsing(b *testing.B, token []byte) {
   521  	hdr := Header{
   522  		Type:             protocol.PacketTypeInitial,
   523  		DestConnectionID: protocol.ParseConnectionID([]byte{1, 2, 3, 4, 5, 6, 7, 8, 9, 10}),
   524  		SrcConnectionID:  protocol.ParseConnectionID([]byte{8, 7, 6, 5, 4, 3, 2, 1}),
   525  		Length:           1000,
   526  		Token:            token,
   527  		Version:          protocol.Version1,
   528  	}
   529  	data, err := (&ExtendedHeader{
   530  		Header:          hdr,
   531  		PacketNumber:    0x1337,
   532  		PacketNumberLen: 4,
   533  	}).Append(nil, protocol.Version1)
   534  	if err != nil {
   535  		b.Fatal(err)
   536  	}
   537  	data = append(data, make([]byte, 1000)...)
   538  
   539  	b.ResetTimer()
   540  	b.ReportAllocs()
   541  	for i := 0; i < b.N; i++ {
   542  		h, _, _, err := ParsePacket(data)
   543  		if err != nil {
   544  			b.Fatal(err)
   545  		}
   546  		if h.Type != hdr.Type || h.DestConnectionID != hdr.DestConnectionID || h.SrcConnectionID != hdr.SrcConnectionID ||
   547  			!bytes.Equal(h.Token, hdr.Token) {
   548  			b.Fatalf("headers don't match: %v vs %v", h, hdr)
   549  		}
   550  	}
   551  }
   552  
   553  func BenchmarkParseRetry(b *testing.B) {
   554  	token := make([]byte, 64)
   555  	rand.Read(token)
   556  	hdr := &ExtendedHeader{
   557  		Header: Header{
   558  			Type:             protocol.PacketTypeRetry,
   559  			SrcConnectionID:  protocol.ParseConnectionID([]byte{1, 2, 3, 4, 5, 6, 7, 8, 9, 10}),
   560  			DestConnectionID: protocol.ParseConnectionID([]byte{8, 7, 6, 5, 4, 3, 2, 1}),
   561  			Token:            token,
   562  			Version:          protocol.Version1,
   563  		},
   564  	}
   565  	data, err := hdr.Append(nil, hdr.Version)
   566  	if err != nil {
   567  		b.Fatal(err)
   568  	}
   569  
   570  	b.ResetTimer()
   571  	b.ReportAllocs()
   572  	for i := 0; i < b.N; i++ {
   573  		h, _, _, err := ParsePacket(data)
   574  		if err != nil {
   575  			b.Fatal(err)
   576  		}
   577  		if h.Type != hdr.Type || h.DestConnectionID != hdr.DestConnectionID || h.SrcConnectionID != hdr.SrcConnectionID ||
   578  			!bytes.Equal(h.Token, hdr.Token[:len(hdr.Token)-16]) {
   579  			b.Fatalf("headers don't match: %#v vs %#v", h, hdr)
   580  		}
   581  	}
   582  }