[145] | 1 | package fasthttp
|
---|
| 2 |
|
---|
| 3 | import (
|
---|
| 4 | "bytes"
|
---|
| 5 | "errors"
|
---|
| 6 | "io"
|
---|
| 7 | "sort"
|
---|
| 8 | "sync"
|
---|
| 9 |
|
---|
| 10 | "github.com/valyala/bytebufferpool"
|
---|
| 11 | )
|
---|
| 12 |
|
---|
| 13 | const (
|
---|
| 14 | argsNoValue = true
|
---|
| 15 | argsHasValue = false
|
---|
| 16 | )
|
---|
| 17 |
|
---|
| 18 | // AcquireArgs returns an empty Args object from the pool.
|
---|
| 19 | //
|
---|
| 20 | // The returned Args may be returned to the pool with ReleaseArgs
|
---|
| 21 | // when no longer needed. This allows reducing GC load.
|
---|
| 22 | func AcquireArgs() *Args {
|
---|
| 23 | return argsPool.Get().(*Args)
|
---|
| 24 | }
|
---|
| 25 |
|
---|
| 26 | // ReleaseArgs returns the object acquired via AcquireArgs to the pool.
|
---|
| 27 | //
|
---|
| 28 | // Do not access the released Args object, otherwise data races may occur.
|
---|
| 29 | func ReleaseArgs(a *Args) {
|
---|
| 30 | a.Reset()
|
---|
| 31 | argsPool.Put(a)
|
---|
| 32 | }
|
---|
| 33 |
|
---|
| 34 | var argsPool = &sync.Pool{
|
---|
| 35 | New: func() interface{} {
|
---|
| 36 | return &Args{}
|
---|
| 37 | },
|
---|
| 38 | }
|
---|
| 39 |
|
---|
| 40 | // Args represents query arguments.
|
---|
| 41 | //
|
---|
| 42 | // It is forbidden copying Args instances. Create new instances instead
|
---|
| 43 | // and use CopyTo().
|
---|
| 44 | //
|
---|
| 45 | // Args instance MUST NOT be used from concurrently running goroutines.
|
---|
| 46 | type Args struct {
|
---|
| 47 | noCopy noCopy //nolint:unused,structcheck
|
---|
| 48 |
|
---|
| 49 | args []argsKV
|
---|
| 50 | buf []byte
|
---|
| 51 | }
|
---|
| 52 |
|
---|
| 53 | type argsKV struct {
|
---|
| 54 | key []byte
|
---|
| 55 | value []byte
|
---|
| 56 | noValue bool
|
---|
| 57 | }
|
---|
| 58 |
|
---|
| 59 | // Reset clears query args.
|
---|
| 60 | func (a *Args) Reset() {
|
---|
| 61 | a.args = a.args[:0]
|
---|
| 62 | }
|
---|
| 63 |
|
---|
| 64 | // CopyTo copies all args to dst.
|
---|
| 65 | func (a *Args) CopyTo(dst *Args) {
|
---|
| 66 | dst.Reset()
|
---|
| 67 | dst.args = copyArgs(dst.args, a.args)
|
---|
| 68 | }
|
---|
| 69 |
|
---|
| 70 | // VisitAll calls f for each existing arg.
|
---|
| 71 | //
|
---|
| 72 | // f must not retain references to key and value after returning.
|
---|
| 73 | // Make key and/or value copies if you need storing them after returning.
|
---|
| 74 | func (a *Args) VisitAll(f func(key, value []byte)) {
|
---|
| 75 | visitArgs(a.args, f)
|
---|
| 76 | }
|
---|
| 77 |
|
---|
| 78 | // Len returns the number of query args.
|
---|
| 79 | func (a *Args) Len() int {
|
---|
| 80 | return len(a.args)
|
---|
| 81 | }
|
---|
| 82 |
|
---|
| 83 | // Parse parses the given string containing query args.
|
---|
| 84 | func (a *Args) Parse(s string) {
|
---|
| 85 | a.buf = append(a.buf[:0], s...)
|
---|
| 86 | a.ParseBytes(a.buf)
|
---|
| 87 | }
|
---|
| 88 |
|
---|
| 89 | // ParseBytes parses the given b containing query args.
|
---|
| 90 | func (a *Args) ParseBytes(b []byte) {
|
---|
| 91 | a.Reset()
|
---|
| 92 |
|
---|
| 93 | var s argsScanner
|
---|
| 94 | s.b = b
|
---|
| 95 |
|
---|
| 96 | var kv *argsKV
|
---|
| 97 | a.args, kv = allocArg(a.args)
|
---|
| 98 | for s.next(kv) {
|
---|
| 99 | if len(kv.key) > 0 || len(kv.value) > 0 {
|
---|
| 100 | a.args, kv = allocArg(a.args)
|
---|
| 101 | }
|
---|
| 102 | }
|
---|
| 103 | a.args = releaseArg(a.args)
|
---|
| 104 | }
|
---|
| 105 |
|
---|
| 106 | // String returns string representation of query args.
|
---|
| 107 | func (a *Args) String() string {
|
---|
| 108 | return string(a.QueryString())
|
---|
| 109 | }
|
---|
| 110 |
|
---|
| 111 | // QueryString returns query string for the args.
|
---|
| 112 | //
|
---|
| 113 | // The returned value is valid until the Args is reused or released (ReleaseArgs).
|
---|
| 114 | // Do not store references to the returned value. Make copies instead.
|
---|
| 115 | func (a *Args) QueryString() []byte {
|
---|
| 116 | a.buf = a.AppendBytes(a.buf[:0])
|
---|
| 117 | return a.buf
|
---|
| 118 | }
|
---|
| 119 |
|
---|
| 120 | // Sort sorts Args by key and then value using 'f' as comparison function.
|
---|
| 121 | //
|
---|
| 122 | // For example args.Sort(bytes.Compare)
|
---|
| 123 | func (a *Args) Sort(f func(x, y []byte) int) {
|
---|
| 124 | sort.SliceStable(a.args, func(i, j int) bool {
|
---|
| 125 | n := f(a.args[i].key, a.args[j].key)
|
---|
| 126 | if n == 0 {
|
---|
| 127 | return f(a.args[i].value, a.args[j].value) == -1
|
---|
| 128 | }
|
---|
| 129 | return n == -1
|
---|
| 130 | })
|
---|
| 131 | }
|
---|
| 132 |
|
---|
| 133 | // AppendBytes appends query string to dst and returns the extended dst.
|
---|
| 134 | func (a *Args) AppendBytes(dst []byte) []byte {
|
---|
| 135 | for i, n := 0, len(a.args); i < n; i++ {
|
---|
| 136 | kv := &a.args[i]
|
---|
| 137 | dst = AppendQuotedArg(dst, kv.key)
|
---|
| 138 | if !kv.noValue {
|
---|
| 139 | dst = append(dst, '=')
|
---|
| 140 | if len(kv.value) > 0 {
|
---|
| 141 | dst = AppendQuotedArg(dst, kv.value)
|
---|
| 142 | }
|
---|
| 143 | }
|
---|
| 144 | if i+1 < n {
|
---|
| 145 | dst = append(dst, '&')
|
---|
| 146 | }
|
---|
| 147 | }
|
---|
| 148 | return dst
|
---|
| 149 | }
|
---|
| 150 |
|
---|
| 151 | // WriteTo writes query string to w.
|
---|
| 152 | //
|
---|
| 153 | // WriteTo implements io.WriterTo interface.
|
---|
| 154 | func (a *Args) WriteTo(w io.Writer) (int64, error) {
|
---|
| 155 | n, err := w.Write(a.QueryString())
|
---|
| 156 | return int64(n), err
|
---|
| 157 | }
|
---|
| 158 |
|
---|
| 159 | // Del deletes argument with the given key from query args.
|
---|
| 160 | func (a *Args) Del(key string) {
|
---|
| 161 | a.args = delAllArgs(a.args, key)
|
---|
| 162 | }
|
---|
| 163 |
|
---|
| 164 | // DelBytes deletes argument with the given key from query args.
|
---|
| 165 | func (a *Args) DelBytes(key []byte) {
|
---|
| 166 | a.args = delAllArgs(a.args, b2s(key))
|
---|
| 167 | }
|
---|
| 168 |
|
---|
| 169 | // Add adds 'key=value' argument.
|
---|
| 170 | //
|
---|
| 171 | // Multiple values for the same key may be added.
|
---|
| 172 | func (a *Args) Add(key, value string) {
|
---|
| 173 | a.args = appendArg(a.args, key, value, argsHasValue)
|
---|
| 174 | }
|
---|
| 175 |
|
---|
| 176 | // AddBytesK adds 'key=value' argument.
|
---|
| 177 | //
|
---|
| 178 | // Multiple values for the same key may be added.
|
---|
| 179 | func (a *Args) AddBytesK(key []byte, value string) {
|
---|
| 180 | a.args = appendArg(a.args, b2s(key), value, argsHasValue)
|
---|
| 181 | }
|
---|
| 182 |
|
---|
| 183 | // AddBytesV adds 'key=value' argument.
|
---|
| 184 | //
|
---|
| 185 | // Multiple values for the same key may be added.
|
---|
| 186 | func (a *Args) AddBytesV(key string, value []byte) {
|
---|
| 187 | a.args = appendArg(a.args, key, b2s(value), argsHasValue)
|
---|
| 188 | }
|
---|
| 189 |
|
---|
| 190 | // AddBytesKV adds 'key=value' argument.
|
---|
| 191 | //
|
---|
| 192 | // Multiple values for the same key may be added.
|
---|
| 193 | func (a *Args) AddBytesKV(key, value []byte) {
|
---|
| 194 | a.args = appendArg(a.args, b2s(key), b2s(value), argsHasValue)
|
---|
| 195 | }
|
---|
| 196 |
|
---|
| 197 | // AddNoValue adds only 'key' as argument without the '='.
|
---|
| 198 | //
|
---|
| 199 | // Multiple values for the same key may be added.
|
---|
| 200 | func (a *Args) AddNoValue(key string) {
|
---|
| 201 | a.args = appendArg(a.args, key, "", argsNoValue)
|
---|
| 202 | }
|
---|
| 203 |
|
---|
| 204 | // AddBytesKNoValue adds only 'key' as argument without the '='.
|
---|
| 205 | //
|
---|
| 206 | // Multiple values for the same key may be added.
|
---|
| 207 | func (a *Args) AddBytesKNoValue(key []byte) {
|
---|
| 208 | a.args = appendArg(a.args, b2s(key), "", argsNoValue)
|
---|
| 209 | }
|
---|
| 210 |
|
---|
| 211 | // Set sets 'key=value' argument.
|
---|
| 212 | func (a *Args) Set(key, value string) {
|
---|
| 213 | a.args = setArg(a.args, key, value, argsHasValue)
|
---|
| 214 | }
|
---|
| 215 |
|
---|
| 216 | // SetBytesK sets 'key=value' argument.
|
---|
| 217 | func (a *Args) SetBytesK(key []byte, value string) {
|
---|
| 218 | a.args = setArg(a.args, b2s(key), value, argsHasValue)
|
---|
| 219 | }
|
---|
| 220 |
|
---|
| 221 | // SetBytesV sets 'key=value' argument.
|
---|
| 222 | func (a *Args) SetBytesV(key string, value []byte) {
|
---|
| 223 | a.args = setArg(a.args, key, b2s(value), argsHasValue)
|
---|
| 224 | }
|
---|
| 225 |
|
---|
| 226 | // SetBytesKV sets 'key=value' argument.
|
---|
| 227 | func (a *Args) SetBytesKV(key, value []byte) {
|
---|
| 228 | a.args = setArgBytes(a.args, key, value, argsHasValue)
|
---|
| 229 | }
|
---|
| 230 |
|
---|
| 231 | // SetNoValue sets only 'key' as argument without the '='.
|
---|
| 232 | //
|
---|
| 233 | // Only key in argumemt, like key1&key2
|
---|
| 234 | func (a *Args) SetNoValue(key string) {
|
---|
| 235 | a.args = setArg(a.args, key, "", argsNoValue)
|
---|
| 236 | }
|
---|
| 237 |
|
---|
| 238 | // SetBytesKNoValue sets 'key' argument.
|
---|
| 239 | func (a *Args) SetBytesKNoValue(key []byte) {
|
---|
| 240 | a.args = setArg(a.args, b2s(key), "", argsNoValue)
|
---|
| 241 | }
|
---|
| 242 |
|
---|
| 243 | // Peek returns query arg value for the given key.
|
---|
| 244 | //
|
---|
| 245 | // The returned value is valid until the Args is reused or released (ReleaseArgs).
|
---|
| 246 | // Do not store references to the returned value. Make copies instead.
|
---|
| 247 | func (a *Args) Peek(key string) []byte {
|
---|
| 248 | return peekArgStr(a.args, key)
|
---|
| 249 | }
|
---|
| 250 |
|
---|
| 251 | // PeekBytes returns query arg value for the given key.
|
---|
| 252 | //
|
---|
| 253 | // The returned value is valid until the Args is reused or released (ReleaseArgs).
|
---|
| 254 | // Do not store references to the returned value. Make copies instead.
|
---|
| 255 | func (a *Args) PeekBytes(key []byte) []byte {
|
---|
| 256 | return peekArgBytes(a.args, key)
|
---|
| 257 | }
|
---|
| 258 |
|
---|
| 259 | // PeekMulti returns all the arg values for the given key.
|
---|
| 260 | func (a *Args) PeekMulti(key string) [][]byte {
|
---|
| 261 | var values [][]byte
|
---|
| 262 | a.VisitAll(func(k, v []byte) {
|
---|
| 263 | if string(k) == key {
|
---|
| 264 | values = append(values, v)
|
---|
| 265 | }
|
---|
| 266 | })
|
---|
| 267 | return values
|
---|
| 268 | }
|
---|
| 269 |
|
---|
| 270 | // PeekMultiBytes returns all the arg values for the given key.
|
---|
| 271 | func (a *Args) PeekMultiBytes(key []byte) [][]byte {
|
---|
| 272 | return a.PeekMulti(b2s(key))
|
---|
| 273 | }
|
---|
| 274 |
|
---|
| 275 | // Has returns true if the given key exists in Args.
|
---|
| 276 | func (a *Args) Has(key string) bool {
|
---|
| 277 | return hasArg(a.args, key)
|
---|
| 278 | }
|
---|
| 279 |
|
---|
| 280 | // HasBytes returns true if the given key exists in Args.
|
---|
| 281 | func (a *Args) HasBytes(key []byte) bool {
|
---|
| 282 | return hasArg(a.args, b2s(key))
|
---|
| 283 | }
|
---|
| 284 |
|
---|
| 285 | // ErrNoArgValue is returned when Args value with the given key is missing.
|
---|
| 286 | var ErrNoArgValue = errors.New("no Args value for the given key")
|
---|
| 287 |
|
---|
| 288 | // GetUint returns uint value for the given key.
|
---|
| 289 | func (a *Args) GetUint(key string) (int, error) {
|
---|
| 290 | value := a.Peek(key)
|
---|
| 291 | if len(value) == 0 {
|
---|
| 292 | return -1, ErrNoArgValue
|
---|
| 293 | }
|
---|
| 294 | return ParseUint(value)
|
---|
| 295 | }
|
---|
| 296 |
|
---|
| 297 | // SetUint sets uint value for the given key.
|
---|
| 298 | func (a *Args) SetUint(key string, value int) {
|
---|
| 299 | bb := bytebufferpool.Get()
|
---|
| 300 | bb.B = AppendUint(bb.B[:0], value)
|
---|
| 301 | a.SetBytesV(key, bb.B)
|
---|
| 302 | bytebufferpool.Put(bb)
|
---|
| 303 | }
|
---|
| 304 |
|
---|
| 305 | // SetUintBytes sets uint value for the given key.
|
---|
| 306 | func (a *Args) SetUintBytes(key []byte, value int) {
|
---|
| 307 | a.SetUint(b2s(key), value)
|
---|
| 308 | }
|
---|
| 309 |
|
---|
| 310 | // GetUintOrZero returns uint value for the given key.
|
---|
| 311 | //
|
---|
| 312 | // Zero (0) is returned on error.
|
---|
| 313 | func (a *Args) GetUintOrZero(key string) int {
|
---|
| 314 | n, err := a.GetUint(key)
|
---|
| 315 | if err != nil {
|
---|
| 316 | n = 0
|
---|
| 317 | }
|
---|
| 318 | return n
|
---|
| 319 | }
|
---|
| 320 |
|
---|
| 321 | // GetUfloat returns ufloat value for the given key.
|
---|
| 322 | func (a *Args) GetUfloat(key string) (float64, error) {
|
---|
| 323 | value := a.Peek(key)
|
---|
| 324 | if len(value) == 0 {
|
---|
| 325 | return -1, ErrNoArgValue
|
---|
| 326 | }
|
---|
| 327 | return ParseUfloat(value)
|
---|
| 328 | }
|
---|
| 329 |
|
---|
| 330 | // GetUfloatOrZero returns ufloat value for the given key.
|
---|
| 331 | //
|
---|
| 332 | // Zero (0) is returned on error.
|
---|
| 333 | func (a *Args) GetUfloatOrZero(key string) float64 {
|
---|
| 334 | f, err := a.GetUfloat(key)
|
---|
| 335 | if err != nil {
|
---|
| 336 | f = 0
|
---|
| 337 | }
|
---|
| 338 | return f
|
---|
| 339 | }
|
---|
| 340 |
|
---|
| 341 | // GetBool returns boolean value for the given key.
|
---|
| 342 | //
|
---|
| 343 | // true is returned for "1", "t", "T", "true", "TRUE", "True", "y", "yes", "Y", "YES", "Yes",
|
---|
| 344 | // otherwise false is returned.
|
---|
| 345 | func (a *Args) GetBool(key string) bool {
|
---|
| 346 | switch b2s(a.Peek(key)) {
|
---|
| 347 | // Support the same true cases as strconv.ParseBool
|
---|
| 348 | // See: https://github.com/golang/go/blob/4e1b11e2c9bdb0ddea1141eed487be1a626ff5be/src/strconv/atob.go#L12
|
---|
| 349 | // and Y and Yes versions.
|
---|
| 350 | case "1", "t", "T", "true", "TRUE", "True", "y", "yes", "Y", "YES", "Yes":
|
---|
| 351 | return true
|
---|
| 352 | default:
|
---|
| 353 | return false
|
---|
| 354 | }
|
---|
| 355 | }
|
---|
| 356 |
|
---|
| 357 | func visitArgs(args []argsKV, f func(k, v []byte)) {
|
---|
| 358 | for i, n := 0, len(args); i < n; i++ {
|
---|
| 359 | kv := &args[i]
|
---|
| 360 | f(kv.key, kv.value)
|
---|
| 361 | }
|
---|
| 362 | }
|
---|
| 363 |
|
---|
| 364 | func visitArgsKey(args []argsKV, f func(k []byte)) {
|
---|
| 365 | for i, n := 0, len(args); i < n; i++ {
|
---|
| 366 | kv := &args[i]
|
---|
| 367 | f(kv.key)
|
---|
| 368 | }
|
---|
| 369 | }
|
---|
| 370 |
|
---|
| 371 | func copyArgs(dst, src []argsKV) []argsKV {
|
---|
| 372 | if cap(dst) < len(src) {
|
---|
| 373 | tmp := make([]argsKV, len(src))
|
---|
| 374 | dst = dst[:cap(dst)] // copy all of dst.
|
---|
| 375 | copy(tmp, dst)
|
---|
| 376 | for i := len(dst); i < len(tmp); i++ {
|
---|
| 377 | // Make sure nothing is nil.
|
---|
| 378 | tmp[i].key = []byte{}
|
---|
| 379 | tmp[i].value = []byte{}
|
---|
| 380 | }
|
---|
| 381 | dst = tmp
|
---|
| 382 | }
|
---|
| 383 | n := len(src)
|
---|
| 384 | dst = dst[:n]
|
---|
| 385 | for i := 0; i < n; i++ {
|
---|
| 386 | dstKV := &dst[i]
|
---|
| 387 | srcKV := &src[i]
|
---|
| 388 | dstKV.key = append(dstKV.key[:0], srcKV.key...)
|
---|
| 389 | if srcKV.noValue {
|
---|
| 390 | dstKV.value = dstKV.value[:0]
|
---|
| 391 | } else {
|
---|
| 392 | dstKV.value = append(dstKV.value[:0], srcKV.value...)
|
---|
| 393 | }
|
---|
| 394 | dstKV.noValue = srcKV.noValue
|
---|
| 395 | }
|
---|
| 396 | return dst
|
---|
| 397 | }
|
---|
| 398 |
|
---|
| 399 | func delAllArgsBytes(args []argsKV, key []byte) []argsKV {
|
---|
| 400 | return delAllArgs(args, b2s(key))
|
---|
| 401 | }
|
---|
| 402 |
|
---|
| 403 | func delAllArgs(args []argsKV, key string) []argsKV {
|
---|
| 404 | for i, n := 0, len(args); i < n; i++ {
|
---|
| 405 | kv := &args[i]
|
---|
| 406 | if key == string(kv.key) {
|
---|
| 407 | tmp := *kv
|
---|
| 408 | copy(args[i:], args[i+1:])
|
---|
| 409 | n--
|
---|
| 410 | i--
|
---|
| 411 | args[n] = tmp
|
---|
| 412 | args = args[:n]
|
---|
| 413 | }
|
---|
| 414 | }
|
---|
| 415 | return args
|
---|
| 416 | }
|
---|
| 417 |
|
---|
| 418 | func setArgBytes(h []argsKV, key, value []byte, noValue bool) []argsKV {
|
---|
| 419 | return setArg(h, b2s(key), b2s(value), noValue)
|
---|
| 420 | }
|
---|
| 421 |
|
---|
| 422 | func setArg(h []argsKV, key, value string, noValue bool) []argsKV {
|
---|
| 423 | n := len(h)
|
---|
| 424 | for i := 0; i < n; i++ {
|
---|
| 425 | kv := &h[i]
|
---|
| 426 | if key == string(kv.key) {
|
---|
| 427 | if noValue {
|
---|
| 428 | kv.value = kv.value[:0]
|
---|
| 429 | } else {
|
---|
| 430 | kv.value = append(kv.value[:0], value...)
|
---|
| 431 | }
|
---|
| 432 | kv.noValue = noValue
|
---|
| 433 | return h
|
---|
| 434 | }
|
---|
| 435 | }
|
---|
| 436 | return appendArg(h, key, value, noValue)
|
---|
| 437 | }
|
---|
| 438 |
|
---|
| 439 | func appendArgBytes(h []argsKV, key, value []byte, noValue bool) []argsKV {
|
---|
| 440 | return appendArg(h, b2s(key), b2s(value), noValue)
|
---|
| 441 | }
|
---|
| 442 |
|
---|
| 443 | func appendArg(args []argsKV, key, value string, noValue bool) []argsKV {
|
---|
| 444 | var kv *argsKV
|
---|
| 445 | args, kv = allocArg(args)
|
---|
| 446 | kv.key = append(kv.key[:0], key...)
|
---|
| 447 | if noValue {
|
---|
| 448 | kv.value = kv.value[:0]
|
---|
| 449 | } else {
|
---|
| 450 | kv.value = append(kv.value[:0], value...)
|
---|
| 451 | }
|
---|
| 452 | kv.noValue = noValue
|
---|
| 453 | return args
|
---|
| 454 | }
|
---|
| 455 |
|
---|
| 456 | func allocArg(h []argsKV) ([]argsKV, *argsKV) {
|
---|
| 457 | n := len(h)
|
---|
| 458 | if cap(h) > n {
|
---|
| 459 | h = h[:n+1]
|
---|
| 460 | } else {
|
---|
| 461 | h = append(h, argsKV{
|
---|
| 462 | value: []byte{},
|
---|
| 463 | })
|
---|
| 464 | }
|
---|
| 465 | return h, &h[n]
|
---|
| 466 | }
|
---|
| 467 |
|
---|
| 468 | func releaseArg(h []argsKV) []argsKV {
|
---|
| 469 | return h[:len(h)-1]
|
---|
| 470 | }
|
---|
| 471 |
|
---|
| 472 | func hasArg(h []argsKV, key string) bool {
|
---|
| 473 | for i, n := 0, len(h); i < n; i++ {
|
---|
| 474 | kv := &h[i]
|
---|
| 475 | if key == string(kv.key) {
|
---|
| 476 | return true
|
---|
| 477 | }
|
---|
| 478 | }
|
---|
| 479 | return false
|
---|
| 480 | }
|
---|
| 481 |
|
---|
| 482 | func peekArgBytes(h []argsKV, k []byte) []byte {
|
---|
| 483 | for i, n := 0, len(h); i < n; i++ {
|
---|
| 484 | kv := &h[i]
|
---|
| 485 | if bytes.Equal(kv.key, k) {
|
---|
| 486 | return kv.value
|
---|
| 487 | }
|
---|
| 488 | }
|
---|
| 489 | return nil
|
---|
| 490 | }
|
---|
| 491 |
|
---|
| 492 | func peekArgStr(h []argsKV, k string) []byte {
|
---|
| 493 | for i, n := 0, len(h); i < n; i++ {
|
---|
| 494 | kv := &h[i]
|
---|
| 495 | if string(kv.key) == k {
|
---|
| 496 | return kv.value
|
---|
| 497 | }
|
---|
| 498 | }
|
---|
| 499 | return nil
|
---|
| 500 | }
|
---|
| 501 |
|
---|
| 502 | type argsScanner struct {
|
---|
| 503 | b []byte
|
---|
| 504 | }
|
---|
| 505 |
|
---|
| 506 | func (s *argsScanner) next(kv *argsKV) bool {
|
---|
| 507 | if len(s.b) == 0 {
|
---|
| 508 | return false
|
---|
| 509 | }
|
---|
| 510 | kv.noValue = argsHasValue
|
---|
| 511 |
|
---|
| 512 | isKey := true
|
---|
| 513 | k := 0
|
---|
| 514 | for i, c := range s.b {
|
---|
| 515 | switch c {
|
---|
| 516 | case '=':
|
---|
| 517 | if isKey {
|
---|
| 518 | isKey = false
|
---|
| 519 | kv.key = decodeArgAppend(kv.key[:0], s.b[:i])
|
---|
| 520 | k = i + 1
|
---|
| 521 | }
|
---|
| 522 | case '&':
|
---|
| 523 | if isKey {
|
---|
| 524 | kv.key = decodeArgAppend(kv.key[:0], s.b[:i])
|
---|
| 525 | kv.value = kv.value[:0]
|
---|
| 526 | kv.noValue = argsNoValue
|
---|
| 527 | } else {
|
---|
| 528 | kv.value = decodeArgAppend(kv.value[:0], s.b[k:i])
|
---|
| 529 | }
|
---|
| 530 | s.b = s.b[i+1:]
|
---|
| 531 | return true
|
---|
| 532 | }
|
---|
| 533 | }
|
---|
| 534 |
|
---|
| 535 | if isKey {
|
---|
| 536 | kv.key = decodeArgAppend(kv.key[:0], s.b)
|
---|
| 537 | kv.value = kv.value[:0]
|
---|
| 538 | kv.noValue = argsNoValue
|
---|
| 539 | } else {
|
---|
| 540 | kv.value = decodeArgAppend(kv.value[:0], s.b[k:])
|
---|
| 541 | }
|
---|
| 542 | s.b = s.b[len(s.b):]
|
---|
| 543 | return true
|
---|
| 544 | }
|
---|
| 545 |
|
---|
| 546 | func decodeArgAppend(dst, src []byte) []byte {
|
---|
| 547 | if bytes.IndexByte(src, '%') < 0 && bytes.IndexByte(src, '+') < 0 {
|
---|
| 548 | // fast path: src doesn't contain encoded chars
|
---|
| 549 | return append(dst, src...)
|
---|
| 550 | }
|
---|
| 551 |
|
---|
| 552 | // slow path
|
---|
| 553 | for i := 0; i < len(src); i++ {
|
---|
| 554 | c := src[i]
|
---|
| 555 | if c == '%' {
|
---|
| 556 | if i+2 >= len(src) {
|
---|
| 557 | return append(dst, src[i:]...)
|
---|
| 558 | }
|
---|
| 559 | x2 := hex2intTable[src[i+2]]
|
---|
| 560 | x1 := hex2intTable[src[i+1]]
|
---|
| 561 | if x1 == 16 || x2 == 16 {
|
---|
| 562 | dst = append(dst, '%')
|
---|
| 563 | } else {
|
---|
| 564 | dst = append(dst, x1<<4|x2)
|
---|
| 565 | i += 2
|
---|
| 566 | }
|
---|
| 567 | } else if c == '+' {
|
---|
| 568 | dst = append(dst, ' ')
|
---|
| 569 | } else {
|
---|
| 570 | dst = append(dst, c)
|
---|
| 571 | }
|
---|
| 572 | }
|
---|
| 573 | return dst
|
---|
| 574 | }
|
---|
| 575 |
|
---|
| 576 | // decodeArgAppendNoPlus is almost identical to decodeArgAppend, but it doesn't
|
---|
| 577 | // substitute '+' with ' '.
|
---|
| 578 | //
|
---|
| 579 | // The function is copy-pasted from decodeArgAppend due to the performance
|
---|
| 580 | // reasons only.
|
---|
| 581 | func decodeArgAppendNoPlus(dst, src []byte) []byte {
|
---|
| 582 | if bytes.IndexByte(src, '%') < 0 {
|
---|
| 583 | // fast path: src doesn't contain encoded chars
|
---|
| 584 | return append(dst, src...)
|
---|
| 585 | }
|
---|
| 586 |
|
---|
| 587 | // slow path
|
---|
| 588 | for i := 0; i < len(src); i++ {
|
---|
| 589 | c := src[i]
|
---|
| 590 | if c == '%' {
|
---|
| 591 | if i+2 >= len(src) {
|
---|
| 592 | return append(dst, src[i:]...)
|
---|
| 593 | }
|
---|
| 594 | x2 := hex2intTable[src[i+2]]
|
---|
| 595 | x1 := hex2intTable[src[i+1]]
|
---|
| 596 | if x1 == 16 || x2 == 16 {
|
---|
| 597 | dst = append(dst, '%')
|
---|
| 598 | } else {
|
---|
| 599 | dst = append(dst, x1<<4|x2)
|
---|
| 600 | i += 2
|
---|
| 601 | }
|
---|
| 602 | } else {
|
---|
| 603 | dst = append(dst, c)
|
---|
| 604 | }
|
---|
| 605 | }
|
---|
| 606 | return dst
|
---|
| 607 | }
|
---|