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