1
2
3
4
5 package gin
6
7 import (
8 "bytes"
9 "net/url"
10 "strings"
11 "unicode"
12 "unicode/utf8"
13
14 "github.com/gin-gonic/gin/internal/bytesconv"
15 )
16
17 var (
18 strColon = []byte(":")
19 strStar = []byte("*")
20 strSlash = []byte("/")
21 )
22
23
24 type Param struct {
25 Key string
26 Value string
27 }
28
29
30
31
32 type Params []Param
33
34
35
36 func (ps Params) Get(name string) (string, bool) {
37 for _, entry := range ps {
38 if entry.Key == name {
39 return entry.Value, true
40 }
41 }
42 return "", false
43 }
44
45
46
47 func (ps Params) ByName(name string) (va string) {
48 va, _ = ps.Get(name)
49 return
50 }
51
52 type methodTree struct {
53 method string
54 root *node
55 }
56
57 type methodTrees []methodTree
58
59 func (trees methodTrees) get(method string) *node {
60 for _, tree := range trees {
61 if tree.method == method {
62 return tree.root
63 }
64 }
65 return nil
66 }
67
68 func min(a, b int) int {
69 if a <= b {
70 return a
71 }
72 return b
73 }
74
75 func longestCommonPrefix(a, b string) int {
76 i := 0
77 max := min(len(a), len(b))
78 for i < max && a[i] == b[i] {
79 i++
80 }
81 return i
82 }
83
84
85 func (n *node) addChild(child *node) {
86 if n.wildChild && len(n.children) > 0 {
87 wildcardChild := n.children[len(n.children)-1]
88 n.children = append(n.children[:len(n.children)-1], child, wildcardChild)
89 } else {
90 n.children = append(n.children, child)
91 }
92 }
93
94 func countParams(path string) uint16 {
95 var n uint16
96 s := bytesconv.StringToBytes(path)
97 n += uint16(bytes.Count(s, strColon))
98 n += uint16(bytes.Count(s, strStar))
99 return n
100 }
101
102 func countSections(path string) uint16 {
103 s := bytesconv.StringToBytes(path)
104 return uint16(bytes.Count(s, strSlash))
105 }
106
107 type nodeType uint8
108
109 const (
110 static nodeType = iota
111 root
112 param
113 catchAll
114 )
115
116 type node struct {
117 path string
118 indices string
119 wildChild bool
120 nType nodeType
121 priority uint32
122 children []*node
123 handlers HandlersChain
124 fullPath string
125 }
126
127
128 func (n *node) incrementChildPrio(pos int) int {
129 cs := n.children
130 cs[pos].priority++
131 prio := cs[pos].priority
132
133
134 newPos := pos
135 for ; newPos > 0 && cs[newPos-1].priority < prio; newPos-- {
136
137 cs[newPos-1], cs[newPos] = cs[newPos], cs[newPos-1]
138 }
139
140
141 if newPos != pos {
142 n.indices = n.indices[:newPos] +
143 n.indices[pos:pos+1] +
144 n.indices[newPos:pos] + n.indices[pos+1:]
145 }
146
147 return newPos
148 }
149
150
151
152 func (n *node) addRoute(path string, handlers HandlersChain) {
153 fullPath := path
154 n.priority++
155
156
157 if len(n.path) == 0 && len(n.children) == 0 {
158 n.insertChild(path, fullPath, handlers)
159 n.nType = root
160 return
161 }
162
163 parentFullPathIndex := 0
164
165 walk:
166 for {
167
168
169
170 i := longestCommonPrefix(path, n.path)
171
172
173 if i < len(n.path) {
174 child := node{
175 path: n.path[i:],
176 wildChild: n.wildChild,
177 nType: static,
178 indices: n.indices,
179 children: n.children,
180 handlers: n.handlers,
181 priority: n.priority - 1,
182 fullPath: n.fullPath,
183 }
184
185 n.children = []*node{&child}
186
187 n.indices = bytesconv.BytesToString([]byte{n.path[i]})
188 n.path = path[:i]
189 n.handlers = nil
190 n.wildChild = false
191 n.fullPath = fullPath[:parentFullPathIndex+i]
192 }
193
194
195 if i < len(path) {
196 path = path[i:]
197 c := path[0]
198
199
200 if n.nType == param && c == '/' && len(n.children) == 1 {
201 parentFullPathIndex += len(n.path)
202 n = n.children[0]
203 n.priority++
204 continue walk
205 }
206
207
208 for i, max := 0, len(n.indices); i < max; i++ {
209 if c == n.indices[i] {
210 parentFullPathIndex += len(n.path)
211 i = n.incrementChildPrio(i)
212 n = n.children[i]
213 continue walk
214 }
215 }
216
217
218 if c != ':' && c != '*' && n.nType != catchAll {
219
220 n.indices += bytesconv.BytesToString([]byte{c})
221 child := &node{
222 fullPath: fullPath,
223 }
224 n.addChild(child)
225 n.incrementChildPrio(len(n.indices) - 1)
226 n = child
227 } else if n.wildChild {
228
229 n = n.children[len(n.children)-1]
230 n.priority++
231
232
233 if len(path) >= len(n.path) && n.path == path[:len(n.path)] &&
234
235 n.nType != catchAll &&
236
237 (len(n.path) >= len(path) || path[len(n.path)] == '/') {
238 continue walk
239 }
240
241
242 pathSeg := path
243 if n.nType != catchAll {
244 pathSeg = strings.SplitN(pathSeg, "/", 2)[0]
245 }
246 prefix := fullPath[:strings.Index(fullPath, pathSeg)] + n.path
247 panic("'" + pathSeg +
248 "' in new path '" + fullPath +
249 "' conflicts with existing wildcard '" + n.path +
250 "' in existing prefix '" + prefix +
251 "'")
252 }
253
254 n.insertChild(path, fullPath, handlers)
255 return
256 }
257
258
259 if n.handlers != nil {
260 panic("handlers are already registered for path '" + fullPath + "'")
261 }
262 n.handlers = handlers
263 n.fullPath = fullPath
264 return
265 }
266 }
267
268
269
270 func findWildcard(path string) (wildcard string, i int, valid bool) {
271
272 for start, c := range []byte(path) {
273
274 if c != ':' && c != '*' {
275 continue
276 }
277
278
279 valid = true
280 for end, c := range []byte(path[start+1:]) {
281 switch c {
282 case '/':
283 return path[start : start+1+end], start, valid
284 case ':', '*':
285 valid = false
286 }
287 }
288 return path[start:], start, valid
289 }
290 return "", -1, false
291 }
292
293 func (n *node) insertChild(path string, fullPath string, handlers HandlersChain) {
294 for {
295
296 wildcard, i, valid := findWildcard(path)
297 if i < 0 {
298 break
299 }
300
301
302 if !valid {
303 panic("only one wildcard per path segment is allowed, has: '" +
304 wildcard + "' in path '" + fullPath + "'")
305 }
306
307
308 if len(wildcard) < 2 {
309 panic("wildcards must be named with a non-empty name in path '" + fullPath + "'")
310 }
311
312 if wildcard[0] == ':' {
313 if i > 0 {
314
315 n.path = path[:i]
316 path = path[i:]
317 }
318
319 child := &node{
320 nType: param,
321 path: wildcard,
322 fullPath: fullPath,
323 }
324 n.addChild(child)
325 n.wildChild = true
326 n = child
327 n.priority++
328
329
330
331 if len(wildcard) < len(path) {
332 path = path[len(wildcard):]
333
334 child := &node{
335 priority: 1,
336 fullPath: fullPath,
337 }
338 n.addChild(child)
339 n = child
340 continue
341 }
342
343
344 n.handlers = handlers
345 return
346 }
347
348
349 if i+len(wildcard) != len(path) {
350 panic("catch-all routes are only allowed at the end of the path in path '" + fullPath + "'")
351 }
352
353 if len(n.path) > 0 && n.path[len(n.path)-1] == '/' {
354 pathSeg := strings.SplitN(n.children[0].path, "/", 2)[0]
355 panic("catch-all wildcard '" + path +
356 "' in new path '" + fullPath +
357 "' conflicts with existing path segment '" + pathSeg +
358 "' in existing prefix '" + n.path + pathSeg +
359 "'")
360 }
361
362
363 i--
364 if path[i] != '/' {
365 panic("no / before catch-all in path '" + fullPath + "'")
366 }
367
368 n.path = path[:i]
369
370
371 child := &node{
372 wildChild: true,
373 nType: catchAll,
374 fullPath: fullPath,
375 }
376
377 n.addChild(child)
378 n.indices = string('/')
379 n = child
380 n.priority++
381
382
383 child = &node{
384 path: path[i:],
385 nType: catchAll,
386 handlers: handlers,
387 priority: 1,
388 fullPath: fullPath,
389 }
390 n.children = []*node{child}
391
392 return
393 }
394
395
396 n.path = path
397 n.handlers = handlers
398 n.fullPath = fullPath
399 }
400
401
402 type nodeValue struct {
403 handlers HandlersChain
404 params *Params
405 tsr bool
406 fullPath string
407 }
408
409 type skippedNode struct {
410 path string
411 node *node
412 paramsCount int16
413 }
414
415
416
417
418
419
420 func (n *node) getValue(path string, params *Params, skippedNodes *[]skippedNode, unescape bool) (value nodeValue) {
421 var globalParamsCount int16
422
423 walk:
424 for {
425 prefix := n.path
426 if len(path) > len(prefix) {
427 if path[:len(prefix)] == prefix {
428 path = path[len(prefix):]
429
430
431 idxc := path[0]
432 for i, c := range []byte(n.indices) {
433 if c == idxc {
434
435 if n.wildChild {
436 index := len(*skippedNodes)
437 *skippedNodes = (*skippedNodes)[:index+1]
438 (*skippedNodes)[index] = skippedNode{
439 path: prefix + path,
440 node: &node{
441 path: n.path,
442 wildChild: n.wildChild,
443 nType: n.nType,
444 priority: n.priority,
445 children: n.children,
446 handlers: n.handlers,
447 fullPath: n.fullPath,
448 },
449 paramsCount: globalParamsCount,
450 }
451 }
452
453 n = n.children[i]
454 continue walk
455 }
456 }
457
458 if !n.wildChild {
459
460
461 if path != "/" {
462 for length := len(*skippedNodes); length > 0; length-- {
463 skippedNode := (*skippedNodes)[length-1]
464 *skippedNodes = (*skippedNodes)[:length-1]
465 if strings.HasSuffix(skippedNode.path, path) {
466 path = skippedNode.path
467 n = skippedNode.node
468 if value.params != nil {
469 *value.params = (*value.params)[:skippedNode.paramsCount]
470 }
471 globalParamsCount = skippedNode.paramsCount
472 continue walk
473 }
474 }
475 }
476
477
478
479
480 value.tsr = path == "/" && n.handlers != nil
481 return
482 }
483
484
485 n = n.children[len(n.children)-1]
486 globalParamsCount++
487
488 switch n.nType {
489 case param:
490
491
492
493
494 end := 0
495 for end < len(path) && path[end] != '/' {
496 end++
497 }
498
499
500 if params != nil && cap(*params) > 0 {
501 if value.params == nil {
502 value.params = params
503 }
504
505 i := len(*value.params)
506 *value.params = (*value.params)[:i+1]
507 val := path[:end]
508 if unescape {
509 if v, err := url.QueryUnescape(val); err == nil {
510 val = v
511 }
512 }
513 (*value.params)[i] = Param{
514 Key: n.path[1:],
515 Value: val,
516 }
517 }
518
519
520 if end < len(path) {
521 if len(n.children) > 0 {
522 path = path[end:]
523 n = n.children[0]
524 continue walk
525 }
526
527
528 value.tsr = len(path) == end+1
529 return
530 }
531
532 if value.handlers = n.handlers; value.handlers != nil {
533 value.fullPath = n.fullPath
534 return
535 }
536 if len(n.children) == 1 {
537
538
539 n = n.children[0]
540 value.tsr = (n.path == "/" && n.handlers != nil) || (n.path == "" && n.indices == "/")
541 }
542 return
543
544 case catchAll:
545
546 if params != nil {
547 if value.params == nil {
548 value.params = params
549 }
550
551 i := len(*value.params)
552 *value.params = (*value.params)[:i+1]
553 val := path
554 if unescape {
555 if v, err := url.QueryUnescape(path); err == nil {
556 val = v
557 }
558 }
559 (*value.params)[i] = Param{
560 Key: n.path[2:],
561 Value: val,
562 }
563 }
564
565 value.handlers = n.handlers
566 value.fullPath = n.fullPath
567 return
568
569 default:
570 panic("invalid node type")
571 }
572 }
573 }
574
575 if path == prefix {
576
577
578 if n.handlers == nil && path != "/" {
579 for length := len(*skippedNodes); length > 0; length-- {
580 skippedNode := (*skippedNodes)[length-1]
581 *skippedNodes = (*skippedNodes)[:length-1]
582 if strings.HasSuffix(skippedNode.path, path) {
583 path = skippedNode.path
584 n = skippedNode.node
585 if value.params != nil {
586 *value.params = (*value.params)[:skippedNode.paramsCount]
587 }
588 globalParamsCount = skippedNode.paramsCount
589 continue walk
590 }
591 }
592
593 }
594
595
596 if value.handlers = n.handlers; value.handlers != nil {
597 value.fullPath = n.fullPath
598 return
599 }
600
601
602
603
604 if path == "/" && n.wildChild && n.nType != root {
605 value.tsr = true
606 return
607 }
608
609 if path == "/" && n.nType == static {
610 value.tsr = true
611 return
612 }
613
614
615
616 for i, c := range []byte(n.indices) {
617 if c == '/' {
618 n = n.children[i]
619 value.tsr = (len(n.path) == 1 && n.handlers != nil) ||
620 (n.nType == catchAll && n.children[0].handlers != nil)
621 return
622 }
623 }
624
625 return
626 }
627
628
629
630 value.tsr = path == "/" ||
631 (len(prefix) == len(path)+1 && prefix[len(path)] == '/' &&
632 path == prefix[:len(prefix)-1] && n.handlers != nil)
633
634
635 if !value.tsr && path != "/" {
636 for length := len(*skippedNodes); length > 0; length-- {
637 skippedNode := (*skippedNodes)[length-1]
638 *skippedNodes = (*skippedNodes)[:length-1]
639 if strings.HasSuffix(skippedNode.path, path) {
640 path = skippedNode.path
641 n = skippedNode.node
642 if value.params != nil {
643 *value.params = (*value.params)[:skippedNode.paramsCount]
644 }
645 globalParamsCount = skippedNode.paramsCount
646 continue walk
647 }
648 }
649 }
650
651 return
652 }
653 }
654
655
656
657
658
659 func (n *node) findCaseInsensitivePath(path string, fixTrailingSlash bool) ([]byte, bool) {
660 const stackBufSize = 128
661
662
663
664 buf := make([]byte, 0, stackBufSize)
665 if length := len(path) + 1; length > stackBufSize {
666 buf = make([]byte, 0, length)
667 }
668
669 ciPath := n.findCaseInsensitivePathRec(
670 path,
671 buf,
672 [4]byte{},
673 fixTrailingSlash,
674 )
675
676 return ciPath, ciPath != nil
677 }
678
679
680 func shiftNRuneBytes(rb [4]byte, n int) [4]byte {
681 switch n {
682 case 0:
683 return rb
684 case 1:
685 return [4]byte{rb[1], rb[2], rb[3], 0}
686 case 2:
687 return [4]byte{rb[2], rb[3]}
688 case 3:
689 return [4]byte{rb[3]}
690 default:
691 return [4]byte{}
692 }
693 }
694
695
696 func (n *node) findCaseInsensitivePathRec(path string, ciPath []byte, rb [4]byte, fixTrailingSlash bool) []byte {
697 npLen := len(n.path)
698
699 walk:
700 for len(path) >= npLen && (npLen == 0 || strings.EqualFold(path[1:npLen], n.path[1:])) {
701
702 oldPath := path
703 path = path[npLen:]
704 ciPath = append(ciPath, n.path...)
705
706 if len(path) == 0 {
707
708
709 if n.handlers != nil {
710 return ciPath
711 }
712
713
714
715 if fixTrailingSlash {
716 for i, c := range []byte(n.indices) {
717 if c == '/' {
718 n = n.children[i]
719 if (len(n.path) == 1 && n.handlers != nil) ||
720 (n.nType == catchAll && n.children[0].handlers != nil) {
721 return append(ciPath, '/')
722 }
723 return nil
724 }
725 }
726 }
727 return nil
728 }
729
730
731
732
733 if !n.wildChild {
734
735 rb = shiftNRuneBytes(rb, npLen)
736
737 if rb[0] != 0 {
738
739 idxc := rb[0]
740 for i, c := range []byte(n.indices) {
741 if c == idxc {
742
743 n = n.children[i]
744 npLen = len(n.path)
745 continue walk
746 }
747 }
748 } else {
749
750 var rv rune
751
752
753
754
755 var off int
756 for max := min(npLen, 3); off < max; off++ {
757 if i := npLen - off; utf8.RuneStart(oldPath[i]) {
758
759 rv, _ = utf8.DecodeRuneInString(oldPath[i:])
760 break
761 }
762 }
763
764
765 lo := unicode.ToLower(rv)
766 utf8.EncodeRune(rb[:], lo)
767
768
769 rb = shiftNRuneBytes(rb, off)
770
771 idxc := rb[0]
772 for i, c := range []byte(n.indices) {
773
774 if c == idxc {
775
776
777
778 if out := n.children[i].findCaseInsensitivePathRec(
779 path, ciPath, rb, fixTrailingSlash,
780 ); out != nil {
781 return out
782 }
783 break
784 }
785 }
786
787
788
789 if up := unicode.ToUpper(rv); up != lo {
790 utf8.EncodeRune(rb[:], up)
791 rb = shiftNRuneBytes(rb, off)
792
793 idxc := rb[0]
794 for i, c := range []byte(n.indices) {
795
796 if c == idxc {
797
798 n = n.children[i]
799 npLen = len(n.path)
800 continue walk
801 }
802 }
803 }
804 }
805
806
807
808 if fixTrailingSlash && path == "/" && n.handlers != nil {
809 return ciPath
810 }
811 return nil
812 }
813
814 n = n.children[0]
815 switch n.nType {
816 case param:
817
818 end := 0
819 for end < len(path) && path[end] != '/' {
820 end++
821 }
822
823
824 ciPath = append(ciPath, path[:end]...)
825
826
827 if end < len(path) {
828 if len(n.children) > 0 {
829
830 n = n.children[0]
831 npLen = len(n.path)
832 path = path[end:]
833 continue
834 }
835
836
837 if fixTrailingSlash && len(path) == end+1 {
838 return ciPath
839 }
840 return nil
841 }
842
843 if n.handlers != nil {
844 return ciPath
845 }
846
847 if fixTrailingSlash && len(n.children) == 1 {
848
849
850 n = n.children[0]
851 if n.path == "/" && n.handlers != nil {
852 return append(ciPath, '/')
853 }
854 }
855
856 return nil
857
858 case catchAll:
859 return append(ciPath, path...)
860
861 default:
862 panic("invalid node type")
863 }
864 }
865
866
867
868 if fixTrailingSlash {
869 if path == "/" {
870 return ciPath
871 }
872 if len(path)+1 == npLen && n.path[len(path)] == '/' &&
873 strings.EqualFold(path[1:], n.path[1:len(path)]) && n.handlers != nil {
874 return append(ciPath, n.path...)
875 }
876 }
877 return nil
878 }
879
View as plain text