github.com/cloudwego/hertz@v0.9.3/internal/bytesconv/bytesconv.go (about) 1 /* 2 * Copyright 2022 CloudWeGo Authors 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 * 16 * The MIT License (MIT) 17 * 18 * Copyright (c) 2015-present Aliaksandr Valialkin, VertaMedia, Kirill Danshin, Erik Dubbelboer, FastHTTP Authors 19 * 20 * Permission is hereby granted, free of charge, to any person obtaining a copy 21 * of this software and associated documentation files (the "Software"), to deal 22 * in the Software without restriction, including without limitation the rights 23 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 24 * copies of the Software, and to permit persons to whom the Software is 25 * furnished to do so, subject to the following conditions: 26 * 27 * The above copyright notice and this permission notice shall be included in 28 * all copies or substantial portions of the Software. 29 * 30 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 31 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 32 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 33 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 34 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 35 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 36 * THE SOFTWARE. 37 * 38 * This file may have been modified by CloudWeGo authors. All CloudWeGo 39 * Modifications are Copyright 2022 CloudWeGo Authors. 40 */ 41 42 package bytesconv 43 44 import ( 45 "net/http" 46 "reflect" 47 "sync" 48 "time" 49 "unsafe" 50 51 "github.com/cloudwego/hertz/pkg/network" 52 ) 53 54 const ( 55 upperhex = "0123456789ABCDEF" 56 lowerhex = "0123456789abcdef" 57 ) 58 59 var hexIntBufPool sync.Pool 60 61 func LowercaseBytes(b []byte) { 62 for i := 0; i < len(b); i++ { 63 p := &b[i] 64 *p = ToLowerTable[*p] 65 } 66 } 67 68 // B2s converts byte slice to a string without memory allocation. 69 // See https://groups.google.com/forum/#!msg/Golang-Nuts/ENgbUzYvCuU/90yGx7GUAgAJ . 70 // 71 // Note it may break if string and/or slice header will change 72 // in the future go versions. 73 func B2s(b []byte) string { 74 /* #nosec G103 */ 75 return *(*string)(unsafe.Pointer(&b)) 76 } 77 78 // S2b converts string to a byte slice without memory allocation. 79 // 80 // Note it may break if string and/or slice header will change 81 // in the future go versions. 82 func S2b(s string) (b []byte) { 83 /* #nosec G103 */ 84 bh := (*reflect.SliceHeader)(unsafe.Pointer(&b)) 85 /* #nosec G103 */ 86 sh := (*reflect.StringHeader)(unsafe.Pointer(&s)) 87 bh.Data = sh.Data 88 bh.Len = sh.Len 89 bh.Cap = sh.Len 90 return b 91 } 92 93 func WriteHexInt(w network.Writer, n int) error { 94 if n < 0 { 95 panic("BUG: int must be positive") 96 } 97 98 v := hexIntBufPool.Get() 99 if v == nil { 100 v = make([]byte, maxHexIntChars+1) 101 } 102 buf := v.([]byte) 103 i := len(buf) - 1 104 for { 105 buf[i] = lowerhex[n&0xf] 106 n >>= 4 107 if n == 0 { 108 break 109 } 110 i-- 111 } 112 safeBuf, err := w.Malloc(maxHexIntChars + 1 - i) 113 copy(safeBuf, buf[i:]) 114 hexIntBufPool.Put(v) 115 return err 116 } 117 118 func ReadHexInt(r network.Reader) (int, error) { 119 n := 0 120 i := 0 121 var k int 122 for { 123 buf, err := r.Peek(1) 124 if err != nil { 125 r.Skip(1) 126 127 if i > 0 { 128 return n, nil 129 } 130 return -1, err 131 } 132 133 c := buf[0] 134 k = int(Hex2intTable[c]) 135 if k == 16 { 136 if i == 0 { 137 r.Skip(1) 138 return -1, errEmptyHexNum 139 } 140 return n, nil 141 } 142 if i >= maxHexIntChars { 143 r.Skip(1) 144 return -1, errTooLargeHexNum 145 } 146 147 r.Skip(1) 148 n = (n << 4) | k 149 i++ 150 } 151 } 152 153 func ParseUintBuf(b []byte) (int, int, error) { 154 n := len(b) 155 if n == 0 { 156 return -1, 0, errEmptyInt 157 } 158 v := 0 159 for i := 0; i < n; i++ { 160 c := b[i] 161 k := c - '0' 162 if k > 9 { 163 if i == 0 { 164 return -1, i, errUnexpectedFirstChar 165 } 166 return v, i, nil 167 } 168 vNew := 10*v + int(k) 169 // Test for overflow. 170 if vNew < v { 171 return -1, i, errTooLongInt 172 } 173 v = vNew 174 } 175 return v, n, nil 176 } 177 178 // AppendUint appends n to dst and returns the extended dst. 179 func AppendUint(dst []byte, n int) []byte { 180 if n < 0 { 181 panic("BUG: int must be positive") 182 } 183 184 var b [20]byte 185 buf := b[:] 186 i := len(buf) 187 var q int 188 for n >= 10 { 189 i-- 190 q = n / 10 191 buf[i] = '0' + byte(n-q*10) 192 n = q 193 } 194 i-- 195 buf[i] = '0' + byte(n) 196 197 dst = append(dst, buf[i:]...) 198 return dst 199 } 200 201 // AppendHTTPDate appends HTTP-compliant representation of date 202 // to dst and returns the extended dst. 203 func AppendHTTPDate(dst []byte, date time.Time) []byte { 204 return date.UTC().AppendFormat(dst, http.TimeFormat) 205 } 206 207 func AppendQuotedPath(dst, src []byte) []byte { 208 // Fix issue in https://github.com/golang/go/issues/11202 209 if len(src) == 1 && src[0] == '*' { 210 return append(dst, '*') 211 } 212 213 for _, c := range src { 214 if QuotedPathShouldEscapeTable[int(c)] != 0 { 215 dst = append(dst, '%', upperhex[c>>4], upperhex[c&15]) 216 } else { 217 dst = append(dst, c) 218 } 219 } 220 return dst 221 } 222 223 // AppendQuotedArg appends url-encoded src to dst and returns appended dst. 224 func AppendQuotedArg(dst, src []byte) []byte { 225 for _, c := range src { 226 switch { 227 case c == ' ': 228 dst = append(dst, '+') 229 case QuotedArgShouldEscapeTable[int(c)] != 0: 230 dst = append(dst, '%', upperhex[c>>4], upperhex[c&0xf]) 231 default: 232 dst = append(dst, c) 233 } 234 } 235 return dst 236 } 237 238 // ParseHTTPDate parses HTTP-compliant (RFC1123) date. 239 func ParseHTTPDate(date []byte) (time.Time, error) { 240 return time.Parse(time.RFC1123, B2s(date)) 241 } 242 243 // ParseUint parses uint from buf. 244 func ParseUint(buf []byte) (int, error) { 245 v, n, err := ParseUintBuf(buf) 246 if n != len(buf) { 247 return -1, errUnexpectedTrailingChar 248 } 249 return v, err 250 }