golang.org/x/net@v0.25.1-0.20240516223405-c87a5b62e243/quic/wire.go (about) 1 // Copyright 2023 The Go Authors. All rights reserved. 2 // Use of this source code is governed by a BSD-style 3 // license that can be found in the LICENSE file. 4 5 //go:build go1.21 6 7 package quic 8 9 import "encoding/binary" 10 11 const ( 12 maxVarintSize = 8 // encoded size in bytes 13 maxVarint = (1 << 62) - 1 14 ) 15 16 // consumeVarint parses a variable-length integer, reporting its length. 17 // It returns a negative length upon an error. 18 // 19 // https://www.rfc-editor.org/rfc/rfc9000.html#section-16 20 func consumeVarint(b []byte) (v uint64, n int) { 21 if len(b) < 1 { 22 return 0, -1 23 } 24 b0 := b[0] & 0x3f 25 switch b[0] >> 6 { 26 case 0: 27 return uint64(b0), 1 28 case 1: 29 if len(b) < 2 { 30 return 0, -1 31 } 32 return uint64(b0)<<8 | uint64(b[1]), 2 33 case 2: 34 if len(b) < 4 { 35 return 0, -1 36 } 37 return uint64(b0)<<24 | uint64(b[1])<<16 | uint64(b[2])<<8 | uint64(b[3]), 4 38 case 3: 39 if len(b) < 8 { 40 return 0, -1 41 } 42 return uint64(b0)<<56 | uint64(b[1])<<48 | uint64(b[2])<<40 | uint64(b[3])<<32 | uint64(b[4])<<24 | uint64(b[5])<<16 | uint64(b[6])<<8 | uint64(b[7]), 8 43 } 44 return 0, -1 45 } 46 47 // consumeVarint64 parses a variable-length integer as an int64. 48 func consumeVarintInt64(b []byte) (v int64, n int) { 49 u, n := consumeVarint(b) 50 // QUIC varints are 62-bits large, so this conversion can never overflow. 51 return int64(u), n 52 } 53 54 // appendVarint appends a variable-length integer to b. 55 // 56 // https://www.rfc-editor.org/rfc/rfc9000.html#section-16 57 func appendVarint(b []byte, v uint64) []byte { 58 switch { 59 case v <= 63: 60 return append(b, byte(v)) 61 case v <= 16383: 62 return append(b, (1<<6)|byte(v>>8), byte(v)) 63 case v <= 1073741823: 64 return append(b, (2<<6)|byte(v>>24), byte(v>>16), byte(v>>8), byte(v)) 65 case v <= 4611686018427387903: 66 return append(b, (3<<6)|byte(v>>56), byte(v>>48), byte(v>>40), byte(v>>32), byte(v>>24), byte(v>>16), byte(v>>8), byte(v)) 67 default: 68 panic("varint too large") 69 } 70 } 71 72 // sizeVarint returns the size of the variable-length integer encoding of f. 73 func sizeVarint(v uint64) int { 74 switch { 75 case v <= 63: 76 return 1 77 case v <= 16383: 78 return 2 79 case v <= 1073741823: 80 return 4 81 case v <= 4611686018427387903: 82 return 8 83 default: 84 panic("varint too large") 85 } 86 } 87 88 // consumeUint32 parses a 32-bit fixed-length, big-endian integer, reporting its length. 89 // It returns a negative length upon an error. 90 func consumeUint32(b []byte) (uint32, int) { 91 if len(b) < 4 { 92 return 0, -1 93 } 94 return binary.BigEndian.Uint32(b), 4 95 } 96 97 // consumeUint64 parses a 64-bit fixed-length, big-endian integer, reporting its length. 98 // It returns a negative length upon an error. 99 func consumeUint64(b []byte) (uint64, int) { 100 if len(b) < 8 { 101 return 0, -1 102 } 103 return binary.BigEndian.Uint64(b), 8 104 } 105 106 // consumeUint8Bytes parses a sequence of bytes prefixed with an 8-bit length, 107 // reporting the total number of bytes consumed. 108 // It returns a negative length upon an error. 109 func consumeUint8Bytes(b []byte) ([]byte, int) { 110 if len(b) < 1 { 111 return nil, -1 112 } 113 size := int(b[0]) 114 const n = 1 115 if size > len(b[n:]) { 116 return nil, -1 117 } 118 return b[n:][:size], size + n 119 } 120 121 // appendUint8Bytes appends a sequence of bytes prefixed by an 8-bit length. 122 func appendUint8Bytes(b, v []byte) []byte { 123 if len(v) > 0xff { 124 panic("uint8-prefixed bytes too large") 125 } 126 b = append(b, uint8(len(v))) 127 b = append(b, v...) 128 return b 129 } 130 131 // consumeVarintBytes parses a sequence of bytes preceded by a variable-length integer length, 132 // reporting the total number of bytes consumed. 133 // It returns a negative length upon an error. 134 func consumeVarintBytes(b []byte) ([]byte, int) { 135 size, n := consumeVarint(b) 136 if n < 0 { 137 return nil, -1 138 } 139 if size > uint64(len(b[n:])) { 140 return nil, -1 141 } 142 return b[n:][:size], int(size) + n 143 } 144 145 // appendVarintBytes appends a sequence of bytes prefixed by a variable-length integer length. 146 func appendVarintBytes(b, v []byte) []byte { 147 b = appendVarint(b, uint64(len(v))) 148 b = append(b, v...) 149 return b 150 }