source: code/trunk/vendor/github.com/valyala/fasthttp/args.go@ 145

Last change on this file since 145 was 145, checked in by Izuru Yakumo, 22 months ago

Updated the Makefile and vendored depedencies

Signed-off-by: Izuru Yakumo <yakumo.izuru@…>

File size: 13.7 KB
RevLine 
[145]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 //nolint:unused,structcheck
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 Args is reused or released (ReleaseArgs).
114// Do not store references to the returned value. Make copies instead.
115func (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)
123func (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.
134func (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.
154func (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.
160func (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.
165func (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.
172func (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.
179func (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.
186func (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.
193func (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.
200func (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.
207func (a *Args) AddBytesKNoValue(key []byte) {
208 a.args = appendArg(a.args, b2s(key), "", argsNoValue)
209}
210
211// Set sets 'key=value' argument.
212func (a *Args) Set(key, value string) {
213 a.args = setArg(a.args, key, value, argsHasValue)
214}
215
216// SetBytesK sets 'key=value' argument.
217func (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.
222func (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.
227func (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
234func (a *Args) SetNoValue(key string) {
235 a.args = setArg(a.args, key, "", argsNoValue)
236}
237
238// SetBytesKNoValue sets 'key' argument.
239func (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.
247func (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.
255func (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.
260func (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.
271func (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.
276func (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.
281func (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.
286var ErrNoArgValue = errors.New("no Args value for the given key")
287
288// GetUint returns uint value for the given key.
289func (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.
298func (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.
306func (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.
313func (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.
322func (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.
333func (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.
345func (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
357func 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
364func 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
371func 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
399func delAllArgsBytes(args []argsKV, key []byte) []argsKV {
400 return delAllArgs(args, b2s(key))
401}
402
403func 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
418func setArgBytes(h []argsKV, key, value []byte, noValue bool) []argsKV {
419 return setArg(h, b2s(key), b2s(value), noValue)
420}
421
422func 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
439func appendArgBytes(h []argsKV, key, value []byte, noValue bool) []argsKV {
440 return appendArg(h, b2s(key), b2s(value), noValue)
441}
442
443func 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
456func 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
468func releaseArg(h []argsKV) []argsKV {
469 return h[:len(h)-1]
470}
471
472func 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
482func 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
492func 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
502type argsScanner struct {
503 b []byte
504}
505
506func (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
546func 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.
581func 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}
Note: See TracBrowser for help on using the repository browser.