github.com/nats-io/nats-server/v2@v2.11.0-preview.2/server/proto.go (about) 1 // Copyright 2024 The NATS Authors 2 // Licensed under the Apache License, Version 2.0 (the "License"); 3 // you may not use this file except in compliance with the License. 4 // You may obtain a copy of the License at 5 // 6 // http://www.apache.org/licenses/LICENSE-2.0 7 // 8 // Unless required by applicable law or agreed to in writing, software 9 // distributed under the License is distributed on an "AS IS" BASIS, 10 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 11 // See the License for the specific language governing permissions and 12 // limitations under the License. 13 14 // Inspired by https://github.com/protocolbuffers/protobuf-go/blob/master/encoding/protowire/wire.go 15 16 package server 17 18 import ( 19 "errors" 20 "fmt" 21 "math" 22 ) 23 24 var errProtoInsufficient = errors.New("insufficient data to read a value") 25 var errProtoOverflow = errors.New("too much data for a value") 26 var errProtoInvalidFieldNumber = errors.New("invalid field number") 27 28 func protoScanField(b []byte) (num, typ, size int, err error) { 29 num, typ, sizeTag, err := protoScanTag(b) 30 if err != nil { 31 return 0, 0, 0, err 32 } 33 b = b[sizeTag:] 34 35 sizeValue, err := protoScanFieldValue(typ, b) 36 if err != nil { 37 return 0, 0, 0, err 38 } 39 return num, typ, sizeTag + sizeValue, nil 40 } 41 42 func protoScanTag(b []byte) (num, typ, size int, err error) { 43 tagint, size, err := protoScanVarint(b) 44 if err != nil { 45 return 0, 0, 0, err 46 } 47 48 // NOTE: MessageSet allows for larger field numbers than normal. 49 if (tagint >> 3) > uint64(math.MaxInt32) { 50 return 0, 0, 0, errProtoInvalidFieldNumber 51 } 52 num = int(tagint >> 3) 53 if num < 1 { 54 return 0, 0, 0, errProtoInvalidFieldNumber 55 } 56 typ = int(tagint & 7) 57 58 return num, typ, size, nil 59 } 60 61 func protoScanFieldValue(typ int, b []byte) (size int, err error) { 62 switch typ { 63 case 0: 64 _, size, err = protoScanVarint(b) 65 case 5: // fixed32 66 size = 4 67 case 1: // fixed64 68 size = 8 69 case 2: // length-delimited 70 size, err = protoScanBytes(b) 71 default: 72 return 0, fmt.Errorf("unsupported type: %d", typ) 73 } 74 return size, err 75 } 76 77 func protoScanVarint(b []byte) (v uint64, size int, err error) { 78 var y uint64 79 if len(b) <= 0 { 80 return 0, 0, errProtoInsufficient 81 } 82 v = uint64(b[0]) 83 if v < 0x80 { 84 return v, 1, nil 85 } 86 v -= 0x80 87 88 if len(b) <= 1 { 89 return 0, 0, errProtoInsufficient 90 } 91 y = uint64(b[1]) 92 v += y << 7 93 if y < 0x80 { 94 return v, 2, nil 95 } 96 v -= 0x80 << 7 97 98 if len(b) <= 2 { 99 return 0, 0, errProtoInsufficient 100 } 101 y = uint64(b[2]) 102 v += y << 14 103 if y < 0x80 { 104 return v, 3, nil 105 } 106 v -= 0x80 << 14 107 108 if len(b) <= 3 { 109 return 0, 0, errProtoInsufficient 110 } 111 y = uint64(b[3]) 112 v += y << 21 113 if y < 0x80 { 114 return v, 4, nil 115 } 116 v -= 0x80 << 21 117 118 if len(b) <= 4 { 119 return 0, 0, errProtoInsufficient 120 } 121 y = uint64(b[4]) 122 v += y << 28 123 if y < 0x80 { 124 return v, 5, nil 125 } 126 v -= 0x80 << 28 127 128 if len(b) <= 5 { 129 return 0, 0, errProtoInsufficient 130 } 131 y = uint64(b[5]) 132 v += y << 35 133 if y < 0x80 { 134 return v, 6, nil 135 } 136 v -= 0x80 << 35 137 138 if len(b) <= 6 { 139 return 0, 0, errProtoInsufficient 140 } 141 y = uint64(b[6]) 142 v += y << 42 143 if y < 0x80 { 144 return v, 7, nil 145 } 146 v -= 0x80 << 42 147 148 if len(b) <= 7 { 149 return 0, 0, errProtoInsufficient 150 } 151 y = uint64(b[7]) 152 v += y << 49 153 if y < 0x80 { 154 return v, 8, nil 155 } 156 v -= 0x80 << 49 157 158 if len(b) <= 8 { 159 return 0, 0, errProtoInsufficient 160 } 161 y = uint64(b[8]) 162 v += y << 56 163 if y < 0x80 { 164 return v, 9, nil 165 } 166 v -= 0x80 << 56 167 168 if len(b) <= 9 { 169 return 0, 0, errProtoInsufficient 170 } 171 y = uint64(b[9]) 172 v += y << 63 173 if y < 2 { 174 return v, 10, nil 175 } 176 return 0, 0, errProtoOverflow 177 } 178 179 func protoScanBytes(b []byte) (size int, err error) { 180 l, lenSize, err := protoScanVarint(b) 181 if err != nil { 182 return 0, err 183 } 184 if l > uint64(len(b[lenSize:])) { 185 return 0, errProtoInsufficient 186 } 187 return lenSize + int(l), nil 188 } 189 190 func protoEncodeVarint(v uint64) []byte { 191 b := make([]byte, 0, 10) 192 switch { 193 case v < 1<<7: 194 b = append(b, byte(v)) 195 case v < 1<<14: 196 b = append(b, 197 byte((v>>0)&0x7f|0x80), 198 byte(v>>7)) 199 case v < 1<<21: 200 b = append(b, 201 byte((v>>0)&0x7f|0x80), 202 byte((v>>7)&0x7f|0x80), 203 byte(v>>14)) 204 case v < 1<<28: 205 b = append(b, 206 byte((v>>0)&0x7f|0x80), 207 byte((v>>7)&0x7f|0x80), 208 byte((v>>14)&0x7f|0x80), 209 byte(v>>21)) 210 case v < 1<<35: 211 b = append(b, 212 byte((v>>0)&0x7f|0x80), 213 byte((v>>7)&0x7f|0x80), 214 byte((v>>14)&0x7f|0x80), 215 byte((v>>21)&0x7f|0x80), 216 byte(v>>28)) 217 case v < 1<<42: 218 b = append(b, 219 byte((v>>0)&0x7f|0x80), 220 byte((v>>7)&0x7f|0x80), 221 byte((v>>14)&0x7f|0x80), 222 byte((v>>21)&0x7f|0x80), 223 byte((v>>28)&0x7f|0x80), 224 byte(v>>35)) 225 case v < 1<<49: 226 b = append(b, 227 byte((v>>0)&0x7f|0x80), 228 byte((v>>7)&0x7f|0x80), 229 byte((v>>14)&0x7f|0x80), 230 byte((v>>21)&0x7f|0x80), 231 byte((v>>28)&0x7f|0x80), 232 byte((v>>35)&0x7f|0x80), 233 byte(v>>42)) 234 case v < 1<<56: 235 b = append(b, 236 byte((v>>0)&0x7f|0x80), 237 byte((v>>7)&0x7f|0x80), 238 byte((v>>14)&0x7f|0x80), 239 byte((v>>21)&0x7f|0x80), 240 byte((v>>28)&0x7f|0x80), 241 byte((v>>35)&0x7f|0x80), 242 byte((v>>42)&0x7f|0x80), 243 byte(v>>49)) 244 case v < 1<<63: 245 b = append(b, 246 byte((v>>0)&0x7f|0x80), 247 byte((v>>7)&0x7f|0x80), 248 byte((v>>14)&0x7f|0x80), 249 byte((v>>21)&0x7f|0x80), 250 byte((v>>28)&0x7f|0x80), 251 byte((v>>35)&0x7f|0x80), 252 byte((v>>42)&0x7f|0x80), 253 byte((v>>49)&0x7f|0x80), 254 byte(v>>56)) 255 default: 256 b = append(b, 257 byte((v>>0)&0x7f|0x80), 258 byte((v>>7)&0x7f|0x80), 259 byte((v>>14)&0x7f|0x80), 260 byte((v>>21)&0x7f|0x80), 261 byte((v>>28)&0x7f|0x80), 262 byte((v>>35)&0x7f|0x80), 263 byte((v>>42)&0x7f|0x80), 264 byte((v>>49)&0x7f|0x80), 265 byte((v>>56)&0x7f|0x80), 266 1) 267 } 268 return b 269 }