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  }