forked from quic-go/quic-go
* wire: translate ACK frame tests * wire: translate CONNECTION_CLOSE frame tests * wire: translate DATA_BLOCKED frame tests * wire: translate DATAGRAM frame tests * wire: translate HANDSHAKE_DONE frame tests * wire: translate MAX_DATA frame tests * wire: translate MAX_STREAM_DATA frame tests * wire: translate MAX_STREAMS frame tests * wire: translate NEW_CONNECTION_ID frame tests * wire: translate NEW_TOKEN frame tests * wire: translate PATH_CHALLENGE frame tests * wire: translate PATH_RESPONSE frame tests * wire: translate PING frame test * wire: translate RESET_STREAM frame tests * wire: translate RETIRE_CONNECTION_ID frame tests * wire: translate STOP_SENDING frame tests * wire: translate STREAM_DATA_BLOCKED frame tests * wire: translate STREAMS_BLOCKED frame tests * wire: translate CRYPTO frame tests * wire: translate STREAM frame tests * wire: translate version negotiation tests * wire: translate header tests * wire: translate pool tests * wire: translate frame logging tests * wire: translate short header tests * wire: translate framer parser tests * wire: translate transport parameter tests
576 lines
21 KiB
Go
576 lines
21 KiB
Go
package wire
|
|
|
|
import (
|
|
"bytes"
|
|
"crypto/rand"
|
|
"encoding/binary"
|
|
"io"
|
|
mrand "math/rand"
|
|
"testing"
|
|
"time"
|
|
|
|
"github.com/quic-go/quic-go/internal/protocol"
|
|
|
|
"github.com/stretchr/testify/require"
|
|
)
|
|
|
|
func TestParseConnIDLongHeaderPacket(t *testing.T) {
|
|
b, err := (&ExtendedHeader{
|
|
Header: Header{
|
|
Type: protocol.PacketTypeHandshake,
|
|
DestConnectionID: protocol.ParseConnectionID([]byte{0xde, 0xca, 0xfb, 0xad}),
|
|
SrcConnectionID: protocol.ParseConnectionID([]byte{1, 2, 3, 4, 5, 6}),
|
|
Version: protocol.Version1,
|
|
},
|
|
PacketNumberLen: 2,
|
|
}).Append(nil, protocol.Version1)
|
|
require.NoError(t, err)
|
|
connID, err := ParseConnectionID(b, 8)
|
|
require.NoError(t, err)
|
|
require.Equal(t, protocol.ParseConnectionID([]byte{0xde, 0xca, 0xfb, 0xad}), connID)
|
|
}
|
|
|
|
func TestParseConnIDTooLong(t *testing.T) {
|
|
b := []byte{0x80, 0, 0, 0, 0}
|
|
binary.BigEndian.PutUint32(b[1:], uint32(protocol.Version1))
|
|
b = append(b, 21) // dest conn id len
|
|
b = append(b, make([]byte, 21)...)
|
|
_, err := ParseConnectionID(b, 4)
|
|
require.Error(t, err)
|
|
require.ErrorIs(t, err, protocol.ErrInvalidConnectionIDLen)
|
|
}
|
|
|
|
func TestParseConnIDEOFLongHeader(t *testing.T) {
|
|
b, err := (&ExtendedHeader{
|
|
Header: Header{
|
|
Type: protocol.PacketTypeHandshake,
|
|
DestConnectionID: protocol.ParseConnectionID([]byte{0xde, 0xca, 0xfb, 0xad, 0x13, 0x37}),
|
|
SrcConnectionID: protocol.ParseConnectionID([]byte{1, 2, 3, 4, 5, 6, 8, 9}),
|
|
Version: protocol.Version1,
|
|
},
|
|
PacketNumberLen: 2,
|
|
}).Append(nil, protocol.Version1)
|
|
require.NoError(t, err)
|
|
data := b[:len(b)-2] // cut the packet number
|
|
_, err = ParseConnectionID(data, 8)
|
|
require.NoError(t, err)
|
|
for i := 0; i < 1 /* first byte */ +4 /* version */ +1 /* conn ID lengths */ +6; /* dest conn ID */ i++ {
|
|
b := make([]byte, i)
|
|
copy(b, data[:i])
|
|
_, err := ParseConnectionID(b, 8)
|
|
require.Error(t, err)
|
|
require.ErrorIs(t, err, io.EOF)
|
|
}
|
|
}
|
|
|
|
func TestIs0RTT(t *testing.T) {
|
|
t.Run("QUIC v1", func(t *testing.T) {
|
|
zeroRTTHeader := make([]byte, 5)
|
|
zeroRTTHeader[0] = 0x80 | 0b01<<4
|
|
binary.BigEndian.PutUint32(zeroRTTHeader[1:], uint32(protocol.Version1))
|
|
|
|
require.True(t, Is0RTTPacket(zeroRTTHeader))
|
|
require.False(t, Is0RTTPacket(zeroRTTHeader[:4])) // too short
|
|
require.False(t, Is0RTTPacket([]byte{zeroRTTHeader[0], 1, 2, 3, 4})) // unknown version
|
|
require.False(t, Is0RTTPacket([]byte{zeroRTTHeader[0] | 0x80, 1, 2, 3, 4})) // short header
|
|
require.True(t, Is0RTTPacket(append(zeroRTTHeader, []byte("foobar")...)))
|
|
})
|
|
|
|
t.Run("QUIC v2", func(t *testing.T) {
|
|
zeroRTTHeader := make([]byte, 5)
|
|
zeroRTTHeader[0] = 0x80 | 0b10<<4
|
|
binary.BigEndian.PutUint32(zeroRTTHeader[1:], uint32(protocol.Version2))
|
|
|
|
require.True(t, Is0RTTPacket(zeroRTTHeader))
|
|
require.False(t, Is0RTTPacket(zeroRTTHeader[:4])) // too short
|
|
require.False(t, Is0RTTPacket([]byte{zeroRTTHeader[0], 1, 2, 3, 4})) // unknown version
|
|
require.False(t, Is0RTTPacket([]byte{zeroRTTHeader[0] | 0x80, 1, 2, 3, 4})) // short header
|
|
require.True(t, Is0RTTPacket(append(zeroRTTHeader, []byte("foobar")...)))
|
|
})
|
|
}
|
|
|
|
func TestParseVersion(t *testing.T) {
|
|
b := []byte{0x80, 0xde, 0xad, 0xbe, 0xef}
|
|
v, err := ParseVersion(b)
|
|
require.NoError(t, err)
|
|
require.Equal(t, protocol.Version(0xdeadbeef), v)
|
|
|
|
for i := range b {
|
|
_, err := ParseVersion(b[:i])
|
|
require.ErrorIs(t, err, io.EOF)
|
|
}
|
|
}
|
|
|
|
func TestParseArbitraryLengthConnectionIDs(t *testing.T) {
|
|
generateConnID := func(l int) protocol.ArbitraryLenConnectionID {
|
|
c := make(protocol.ArbitraryLenConnectionID, l)
|
|
rand.Read(c)
|
|
return c
|
|
}
|
|
|
|
src := generateConnID(mrand.Intn(255) + 1)
|
|
dest := generateConnID(mrand.Intn(255) + 1)
|
|
b := []byte{0x80, 1, 2, 3, 4}
|
|
b = append(b, uint8(dest.Len()))
|
|
b = append(b, dest.Bytes()...)
|
|
b = append(b, uint8(src.Len()))
|
|
b = append(b, src.Bytes()...)
|
|
l := len(b)
|
|
b = append(b, []byte("foobar")...) // add some payload
|
|
|
|
parsed, d, s, err := ParseArbitraryLenConnectionIDs(b)
|
|
require.Equal(t, l, parsed)
|
|
require.NoError(t, err)
|
|
require.Equal(t, src, s)
|
|
require.Equal(t, dest, d)
|
|
|
|
for i := range b[:l] {
|
|
_, _, _, err := ParseArbitraryLenConnectionIDs(b[:i])
|
|
require.ErrorIs(t, err, io.EOF)
|
|
}
|
|
}
|
|
|
|
func TestIdentifyVersionNegotiationPackets(t *testing.T) {
|
|
require.True(t, IsVersionNegotiationPacket([]byte{0x80 | 0x56, 0, 0, 0, 0}))
|
|
require.False(t, IsVersionNegotiationPacket([]byte{0x56, 0, 0, 0, 0}))
|
|
require.False(t, IsVersionNegotiationPacket([]byte{0x80, 1, 0, 0, 0}))
|
|
require.False(t, IsVersionNegotiationPacket([]byte{0x80, 0, 1, 0, 0}))
|
|
require.False(t, IsVersionNegotiationPacket([]byte{0x80, 0, 0, 1, 0}))
|
|
require.False(t, IsVersionNegotiationPacket([]byte{0x80, 0, 0, 0, 1}))
|
|
}
|
|
|
|
func TestVersionNegotiationPacketEOF(t *testing.T) {
|
|
vnp := []byte{0x80, 0, 0, 0, 0}
|
|
for i := range vnp {
|
|
require.False(t, IsVersionNegotiationPacket(vnp[:i]))
|
|
}
|
|
}
|
|
|
|
func TestParseLongHeader(t *testing.T) {
|
|
destConnID := protocol.ParseConnectionID([]byte{9, 8, 7, 6, 5, 4, 3, 2, 1})
|
|
srcConnID := protocol.ParseConnectionID([]byte{0xde, 0xad, 0xbe, 0xef})
|
|
data := []byte{0xc0 ^ 0x3}
|
|
data = appendVersion(data, protocol.Version1)
|
|
data = append(data, 0x9) // dest conn id length
|
|
data = append(data, destConnID.Bytes()...)
|
|
data = append(data, 0x4) // src conn id length
|
|
data = append(data, srcConnID.Bytes()...)
|
|
data = append(data, encodeVarInt(6)...) // token length
|
|
data = append(data, []byte("foobar")...) // token
|
|
data = append(data, encodeVarInt(10)...) // length
|
|
hdrLen := len(data)
|
|
data = append(data, []byte{0, 0, 0xbe, 0xef}...) // packet number
|
|
data = append(data, []byte("foobar")...)
|
|
require.False(t, IsVersionNegotiationPacket(data))
|
|
|
|
hdr, pdata, rest, err := ParsePacket(data)
|
|
require.NoError(t, err)
|
|
require.Equal(t, data, pdata)
|
|
require.Equal(t, destConnID, hdr.DestConnectionID)
|
|
require.Equal(t, srcConnID, hdr.SrcConnectionID)
|
|
require.Equal(t, protocol.PacketTypeInitial, hdr.Type)
|
|
require.Equal(t, []byte("foobar"), hdr.Token)
|
|
require.Equal(t, protocol.ByteCount(10), hdr.Length)
|
|
require.Equal(t, protocol.Version1, hdr.Version)
|
|
require.Empty(t, rest)
|
|
extHdr, err := hdr.ParseExtended(data)
|
|
require.NoError(t, err)
|
|
require.Equal(t, protocol.PacketNumberLen4, extHdr.PacketNumberLen)
|
|
require.Equal(t, protocol.PacketNumber(0xbeef), extHdr.PacketNumber)
|
|
require.Equal(t, hdrLen, int(hdr.ParsedLen()))
|
|
require.Equal(t, hdr.ParsedLen()+4, extHdr.ParsedLen())
|
|
}
|
|
|
|
func TestErrorIfReservedBitNotSet(t *testing.T) {
|
|
data := []byte{
|
|
0x80 | 0x2<<4,
|
|
0x11, // connection ID lengths
|
|
0xde, 0xca, 0xfb, 0xad, // dest conn ID
|
|
0xde, 0xad, 0xbe, 0xef, // src conn ID
|
|
}
|
|
_, _, _, err := ParsePacket(data)
|
|
require.EqualError(t, err, "not a QUIC packet")
|
|
}
|
|
|
|
func TestStopParsingWhenEncounteringUnsupportedVersion(t *testing.T) {
|
|
data := []byte{
|
|
0xc0,
|
|
0xde, 0xad, 0xbe, 0xef,
|
|
0x8, // dest conn ID len
|
|
0x1, 0x2, 0x3, 0x4, 0x5, 0x6, 0x7, 0x8, // dest conn ID
|
|
0x8, // src conn ID len
|
|
0x8, 0x7, 0x6, 0x5, 0x4, 0x3, 0x2, 0x1, // src conn ID
|
|
'f', 'o', 'o', 'b', 'a', 'r', // unspecified bytes
|
|
}
|
|
hdr, _, rest, err := ParsePacket(data)
|
|
require.EqualError(t, err, ErrUnsupportedVersion.Error())
|
|
require.Equal(t, protocol.Version(0xdeadbeef), hdr.Version)
|
|
require.Equal(t, protocol.ParseConnectionID([]byte{0x1, 0x2, 0x3, 0x4, 0x5, 0x6, 0x7, 0x8}), hdr.DestConnectionID)
|
|
require.Equal(t, protocol.ParseConnectionID([]byte{0x8, 0x7, 0x6, 0x5, 0x4, 0x3, 0x2, 0x1}), hdr.SrcConnectionID)
|
|
require.Empty(t, rest)
|
|
}
|
|
|
|
func TestParseLongHeaderWithoutDestinationConnectionID(t *testing.T) {
|
|
data := []byte{0xc0 ^ 0x1<<4}
|
|
data = appendVersion(data, protocol.Version1)
|
|
data = append(data, 0) // dest conn ID len
|
|
data = append(data, 4) // src conn ID len
|
|
data = append(data, []byte{0xde, 0xad, 0xbe, 0xef}...) // source connection ID
|
|
data = append(data, encodeVarInt(0)...) // length
|
|
data = append(data, []byte{0xde, 0xca, 0xfb, 0xad}...)
|
|
hdr, _, _, err := ParsePacket(data)
|
|
require.NoError(t, err)
|
|
require.Equal(t, protocol.PacketType0RTT, hdr.Type)
|
|
require.Equal(t, protocol.ParseConnectionID([]byte{0xde, 0xad, 0xbe, 0xef}), hdr.SrcConnectionID)
|
|
require.Zero(t, hdr.DestConnectionID)
|
|
}
|
|
|
|
func TestParseLongHeaderWithoutSourceConnectionID(t *testing.T) {
|
|
data := []byte{0xc0 ^ 0x2<<4}
|
|
data = appendVersion(data, protocol.Version1)
|
|
data = append(data, 10) // dest conn ID len
|
|
data = append(data, []byte{1, 2, 3, 4, 5, 6, 7, 8, 9, 10}...) // dest connection ID
|
|
data = append(data, 0) // src conn ID len
|
|
data = append(data, encodeVarInt(0)...) // length
|
|
data = append(data, []byte{0xde, 0xca, 0xfb, 0xad}...)
|
|
hdr, _, _, err := ParsePacket(data)
|
|
require.NoError(t, err)
|
|
require.Zero(t, hdr.SrcConnectionID)
|
|
require.Equal(t, protocol.ParseConnectionID([]byte{1, 2, 3, 4, 5, 6, 7, 8, 9, 10}), hdr.DestConnectionID)
|
|
}
|
|
|
|
func TestErrorOnTooLongDestinationConnectionID(t *testing.T) {
|
|
data := []byte{0xc0 ^ 0x2<<4}
|
|
data = appendVersion(data, protocol.Version1)
|
|
data = append(data, 21) // dest conn ID len
|
|
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
|
|
data = append(data, 0x0) // src conn ID len
|
|
data = append(data, encodeVarInt(0)...) // length
|
|
data = append(data, []byte{0xde, 0xca, 0xfb, 0xad}...)
|
|
_, _, _, err := ParsePacket(data)
|
|
require.EqualError(t, err, protocol.ErrInvalidConnectionIDLen.Error())
|
|
}
|
|
|
|
func TestParseLongHeaderWith2BytePacketNumber(t *testing.T) {
|
|
data := []byte{0xc0 ^ 0x1}
|
|
data = appendVersion(data, protocol.Version1) // version number
|
|
data = append(data, []byte{0x0, 0x0}...) // connection ID lengths
|
|
data = append(data, encodeVarInt(0)...) // token length
|
|
data = append(data, encodeVarInt(0)...) // length
|
|
data = append(data, []byte{0x1, 0x23}...)
|
|
|
|
hdr, _, _, err := ParsePacket(data)
|
|
require.NoError(t, err)
|
|
extHdr, err := hdr.ParseExtended(data)
|
|
require.NoError(t, err)
|
|
require.Equal(t, protocol.PacketNumber(0x123), extHdr.PacketNumber)
|
|
require.Equal(t, protocol.PacketNumberLen2, extHdr.PacketNumberLen)
|
|
require.Equal(t, len(data), int(extHdr.ParsedLen()))
|
|
}
|
|
|
|
func TestParseRetryPacket(t *testing.T) {
|
|
for _, version := range []protocol.Version{protocol.Version1, protocol.Version2} {
|
|
t.Run(version.String(), func(t *testing.T) {
|
|
var packetType byte
|
|
if version == protocol.Version1 {
|
|
packetType = 0b11 << 4
|
|
} else {
|
|
packetType = 0b00 << 4
|
|
}
|
|
data := []byte{0xc0 | packetType | (10 - 3) /* connection ID length */}
|
|
data = appendVersion(data, version)
|
|
data = append(data, []byte{6}...) // dest conn ID len
|
|
data = append(data, []byte{6, 5, 4, 3, 2, 1}...) // dest conn ID
|
|
data = append(data, []byte{10}...) // src conn ID len
|
|
data = append(data, []byte{1, 2, 3, 4, 5, 6, 7, 8, 9, 10}...) // source connection ID
|
|
data = append(data, []byte{'f', 'o', 'o', 'b', 'a', 'r'}...) // token
|
|
data = append(data, []byte{16, 15, 14, 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1}...)
|
|
hdr, pdata, rest, err := ParsePacket(data)
|
|
require.NoError(t, err)
|
|
require.Equal(t, protocol.PacketTypeRetry, hdr.Type)
|
|
require.Equal(t, version, hdr.Version)
|
|
require.Equal(t, protocol.ParseConnectionID([]byte{6, 5, 4, 3, 2, 1}), hdr.DestConnectionID)
|
|
require.Equal(t, protocol.ParseConnectionID([]byte{1, 2, 3, 4, 5, 6, 7, 8, 9, 10}), hdr.SrcConnectionID)
|
|
require.Equal(t, []byte("foobar"), hdr.Token)
|
|
require.Equal(t, data, pdata)
|
|
require.Empty(t, rest)
|
|
})
|
|
}
|
|
}
|
|
|
|
func TestRetryPacketTooShortForIntegrityTag(t *testing.T) {
|
|
data := []byte{0xc0 | 0x3<<4 | (10 - 3) /* connection ID length */}
|
|
data = appendVersion(data, protocol.Version1)
|
|
data = append(data, []byte{0, 0}...) // conn ID lens
|
|
data = append(data, []byte{'f', 'o', 'o', 'b', 'a', 'r'}...) // token
|
|
data = append(data, []byte{1, 2, 3, 4, 5, 6, 7, 8, 9, 10}...)
|
|
// this results in a token length of 0
|
|
_, _, _, err := ParsePacket(data)
|
|
require.Equal(t, io.EOF, err)
|
|
}
|
|
|
|
func TestTokenLengthTooLarge(t *testing.T) {
|
|
data := []byte{0xc0 ^ 0x1}
|
|
data = appendVersion(data, protocol.Version1)
|
|
data = append(data, 0x0) // connection ID lengths
|
|
data = append(data, encodeVarInt(4)...) // token length: 4 bytes (1 byte too long)
|
|
data = append(data, encodeVarInt(0x42)...) // length, 1 byte
|
|
data = append(data, []byte{0x12, 0x34}...) // packet number
|
|
|
|
_, _, _, err := ParsePacket(data)
|
|
require.Equal(t, io.EOF, err)
|
|
}
|
|
|
|
func TestErrorOn5thOr6thBitSet(t *testing.T) {
|
|
data := []byte{0xc0 | 0x2<<4 | 0x8 /* set the 5th bit */ | 0x1 /* 2 byte packet number */}
|
|
data = appendVersion(data, protocol.Version1)
|
|
data = append(data, []byte{0x0, 0x0}...) // connection ID lengths
|
|
data = append(data, encodeVarInt(2)...) // length
|
|
data = append(data, []byte{0x12, 0x34}...) // packet number
|
|
hdr, _, _, err := ParsePacket(data)
|
|
require.NoError(t, err)
|
|
require.Equal(t, protocol.PacketTypeHandshake, hdr.Type)
|
|
extHdr, err := hdr.ParseExtended(data)
|
|
require.EqualError(t, err, ErrInvalidReservedBits.Error())
|
|
require.NotNil(t, extHdr)
|
|
require.Equal(t, protocol.PacketNumber(0x1234), extHdr.PacketNumber)
|
|
}
|
|
|
|
func TestHeaderEOF(t *testing.T) {
|
|
data := []byte{0xc0 ^ 0x2<<4}
|
|
data = appendVersion(data, protocol.Version1)
|
|
data = append(data, 0x8) // dest conn ID len
|
|
data = append(data, []byte{0xde, 0xad, 0xbe, 0xef, 0xca, 0xfe, 0x13, 0x37}...) // dest conn ID
|
|
data = append(data, 0x8) // src conn ID len
|
|
data = append(data, []byte{0xde, 0xad, 0xbe, 0xef, 0xca, 0xfe, 0x13, 0x37}...) // src conn ID
|
|
for i := 1; i < len(data); i++ {
|
|
_, _, _, err := ParsePacket(data[:i])
|
|
require.Equal(t, io.EOF, err)
|
|
}
|
|
}
|
|
|
|
func TestParseExtendedHeaderEOF(t *testing.T) {
|
|
data := []byte{0xc0 | 0x2<<4 | 0x3}
|
|
data = appendVersion(data, protocol.Version1)
|
|
data = append(data, []byte{0x0, 0x0}...) // connection ID lengths
|
|
data = append(data, encodeVarInt(0)...) // length
|
|
hdrLen := len(data)
|
|
data = append(data, []byte{0xde, 0xad, 0xbe, 0xef}...) // packet number
|
|
for i := hdrLen; i < len(data); i++ {
|
|
b := data[:i]
|
|
hdr, _, _, err := ParsePacket(b)
|
|
require.NoError(t, err)
|
|
_, err = hdr.ParseExtended(b)
|
|
require.Equal(t, io.EOF, err)
|
|
}
|
|
}
|
|
|
|
func TestParseRetryEOF(t *testing.T) {
|
|
data := []byte{0xc0 ^ 0x3<<4}
|
|
data = appendVersion(data, protocol.Version1)
|
|
data = append(data, []byte{0x0, 0x0}...) // connection ID lengths
|
|
data = append(data, 0xa) // Orig Destination Connection ID length
|
|
data = append(data, []byte{1, 2, 3, 4, 5, 6, 7, 8, 9, 10}...) // source connection ID
|
|
hdrLen := len(data)
|
|
for i := hdrLen; i < len(data); i++ {
|
|
data = data[:i]
|
|
hdr, _, _, err := ParsePacket(data)
|
|
require.NoError(t, err)
|
|
_, err = hdr.ParseExtended(data)
|
|
require.Equal(t, io.EOF, err)
|
|
}
|
|
}
|
|
|
|
func TestCoalescedPacketParsing(t *testing.T) {
|
|
hdr := Header{
|
|
Type: protocol.PacketTypeInitial,
|
|
DestConnectionID: protocol.ParseConnectionID([]byte{1, 2, 3, 4}),
|
|
Length: 2 + 6,
|
|
Version: protocol.Version1,
|
|
}
|
|
b, err := (&ExtendedHeader{
|
|
Header: hdr,
|
|
PacketNumber: 0x1337,
|
|
PacketNumberLen: 2,
|
|
}).Append(nil, protocol.Version1)
|
|
require.NoError(t, err)
|
|
hdrRaw := append([]byte{}, b...)
|
|
b = append(b, []byte("foobar")...) // payload of the first packet
|
|
b = append(b, []byte("raboof")...) // second packet
|
|
parsedHdr, data, rest, err := ParsePacket(b)
|
|
require.NoError(t, err)
|
|
require.Equal(t, hdr.Type, parsedHdr.Type)
|
|
require.Equal(t, hdr.DestConnectionID, parsedHdr.DestConnectionID)
|
|
require.Equal(t, append(hdrRaw, []byte("foobar")...), data)
|
|
require.Equal(t, []byte("raboof"), rest)
|
|
}
|
|
|
|
func TestCoalescedPacketErrorOnTooSmallPacketNumber(t *testing.T) {
|
|
b, err := (&ExtendedHeader{
|
|
Header: Header{
|
|
Type: protocol.PacketTypeInitial,
|
|
DestConnectionID: protocol.ParseConnectionID([]byte{1, 2, 3, 4}),
|
|
Length: 3,
|
|
Version: protocol.Version1,
|
|
},
|
|
PacketNumber: 0x1337,
|
|
PacketNumberLen: 2,
|
|
}).Append(nil, protocol.Version1)
|
|
require.NoError(t, err)
|
|
_, _, _, err = ParsePacket(b)
|
|
require.Error(t, err)
|
|
require.Contains(t, err.Error(), "packet length (2 bytes) is smaller than the expected length (3 bytes)")
|
|
}
|
|
|
|
func TestCoalescedPacketErrorOnTooSmallPayload(t *testing.T) {
|
|
b, err := (&ExtendedHeader{
|
|
Header: Header{
|
|
Type: protocol.PacketTypeInitial,
|
|
DestConnectionID: protocol.ParseConnectionID([]byte{1, 2, 3, 4}),
|
|
Length: 1000,
|
|
Version: protocol.Version1,
|
|
},
|
|
PacketNumber: 0x1337,
|
|
PacketNumberLen: 2,
|
|
}).Append(nil, protocol.Version1)
|
|
require.NoError(t, err)
|
|
b = append(b, make([]byte, 500-2 /* for packet number length */)...)
|
|
_, _, _, err = ParsePacket(b)
|
|
require.EqualError(t, err, "packet length (500 bytes) is smaller than the expected length (1000 bytes)")
|
|
}
|
|
|
|
func TestDistinguishesLongAndShortHeaderPackets(t *testing.T) {
|
|
require.False(t, IsLongHeaderPacket(0x40))
|
|
require.True(t, IsLongHeaderPacket(0x80^0x40^0x12))
|
|
}
|
|
|
|
func TestPacketTypeForLogging(t *testing.T) {
|
|
require.Equal(t, "Initial", (&Header{Type: protocol.PacketTypeInitial}).PacketType())
|
|
require.Equal(t, "Handshake", (&Header{Type: protocol.PacketTypeHandshake}).PacketType())
|
|
}
|
|
|
|
func BenchmarkIs0RTTPacket(b *testing.B) {
|
|
random := mrand.New(mrand.NewSource(time.Now().UnixNano()))
|
|
packets := make([][]byte, 1024)
|
|
for i := 0; i < len(packets); i++ {
|
|
packets[i] = make([]byte, random.Intn(256))
|
|
random.Read(packets[i])
|
|
}
|
|
|
|
b.ResetTimer()
|
|
for i := 0; i < b.N; i++ {
|
|
Is0RTTPacket(packets[i%len(packets)])
|
|
}
|
|
}
|
|
|
|
func BenchmarkParseInitial(b *testing.B) {
|
|
b.Run("without token", func(b *testing.B) {
|
|
benchmarkInitialPacketParsing(b, nil)
|
|
})
|
|
b.Run("with token", func(b *testing.B) {
|
|
token := make([]byte, 32)
|
|
rand.Read(token)
|
|
benchmarkInitialPacketParsing(b, token)
|
|
})
|
|
}
|
|
|
|
func benchmarkInitialPacketParsing(b *testing.B, token []byte) {
|
|
hdr := Header{
|
|
Type: protocol.PacketTypeInitial,
|
|
DestConnectionID: protocol.ParseConnectionID([]byte{1, 2, 3, 4, 5, 6, 7, 8, 9, 10}),
|
|
SrcConnectionID: protocol.ParseConnectionID([]byte{8, 7, 6, 5, 4, 3, 2, 1}),
|
|
Length: 1000,
|
|
Token: token,
|
|
Version: protocol.Version1,
|
|
}
|
|
data, err := (&ExtendedHeader{
|
|
Header: hdr,
|
|
PacketNumber: 0x1337,
|
|
PacketNumberLen: 4,
|
|
}).Append(nil, protocol.Version1)
|
|
if err != nil {
|
|
b.Fatal(err)
|
|
}
|
|
data = append(data, make([]byte, 1000)...)
|
|
|
|
b.ResetTimer()
|
|
b.ReportAllocs()
|
|
for i := 0; i < b.N; i++ {
|
|
h, _, _, err := ParsePacket(data)
|
|
if err != nil {
|
|
b.Fatal(err)
|
|
}
|
|
if h.Type != hdr.Type || h.DestConnectionID != hdr.DestConnectionID || h.SrcConnectionID != hdr.SrcConnectionID ||
|
|
!bytes.Equal(h.Token, hdr.Token) {
|
|
b.Fatalf("headers don't match: %v vs %v", h, hdr)
|
|
}
|
|
}
|
|
}
|
|
|
|
func BenchmarkParseRetry(b *testing.B) {
|
|
token := make([]byte, 64)
|
|
rand.Read(token)
|
|
hdr := &ExtendedHeader{
|
|
Header: Header{
|
|
Type: protocol.PacketTypeRetry,
|
|
SrcConnectionID: protocol.ParseConnectionID([]byte{1, 2, 3, 4, 5, 6, 7, 8, 9, 10}),
|
|
DestConnectionID: protocol.ParseConnectionID([]byte{8, 7, 6, 5, 4, 3, 2, 1}),
|
|
Token: token,
|
|
Version: protocol.Version1,
|
|
},
|
|
}
|
|
data, err := hdr.Append(nil, hdr.Version)
|
|
if err != nil {
|
|
b.Fatal(err)
|
|
}
|
|
|
|
b.ResetTimer()
|
|
b.ReportAllocs()
|
|
for i := 0; i < b.N; i++ {
|
|
h, _, _, err := ParsePacket(data)
|
|
if err != nil {
|
|
b.Fatal(err)
|
|
}
|
|
if h.Type != hdr.Type || h.DestConnectionID != hdr.DestConnectionID || h.SrcConnectionID != hdr.SrcConnectionID ||
|
|
!bytes.Equal(h.Token, hdr.Token[:len(hdr.Token)-16]) {
|
|
b.Fatalf("headers don't match: %#v vs %#v", h, hdr)
|
|
}
|
|
}
|
|
}
|
|
|
|
func BenchmarkArbitraryHeaderParsing(b *testing.B) {
|
|
b.Run("dest 8/ src 10", func(b *testing.B) { benchmarkArbitraryHeaderParsing(b, 8, 10) })
|
|
b.Run("dest 20 / src 20", func(b *testing.B) { benchmarkArbitraryHeaderParsing(b, 20, 20) })
|
|
b.Run("dest 100 / src 150", func(b *testing.B) { benchmarkArbitraryHeaderParsing(b, 100, 150) })
|
|
}
|
|
|
|
func benchmarkArbitraryHeaderParsing(b *testing.B, destLen, srcLen int) {
|
|
destConnID := make([]byte, destLen)
|
|
rand.Read(destConnID)
|
|
srcConnID := make([]byte, srcLen)
|
|
rand.Read(srcConnID)
|
|
buf := []byte{0x80, 1, 2, 3, 4}
|
|
buf = append(buf, uint8(destLen))
|
|
buf = append(buf, destConnID...)
|
|
buf = append(buf, uint8(srcLen))
|
|
buf = append(buf, srcConnID...)
|
|
|
|
b.ResetTimer()
|
|
b.ReportAllocs()
|
|
for i := 0; i < b.N; i++ {
|
|
parsed, d, s, err := ParseArbitraryLenConnectionIDs(buf)
|
|
if err != nil {
|
|
b.Fatal(err)
|
|
}
|
|
if parsed != len(buf) {
|
|
b.Fatal("expected to parse entire slice")
|
|
}
|
|
if !bytes.Equal(destConnID, d.Bytes()) {
|
|
b.Fatalf("destination connection IDs don't match: %v vs %v", destConnID, d.Bytes())
|
|
}
|
|
if !bytes.Equal(srcConnID, s.Bytes()) {
|
|
b.Fatalf("source connection IDs don't match: %v vs %v", srcConnID, s.Bytes())
|
|
}
|
|
}
|
|
}
|