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  }