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