@@ -17,6 +17,7 @@ import (
17
17
var (
18
18
strColon = []byte (":" )
19
19
strStar = []byte ("*" )
20
+ strSlash = []byte ("/" )
20
21
)
21
22
22
23
// Param is a single URL parameter, consisting of a key and a value.
@@ -98,6 +99,11 @@ func countParams(path string) uint16 {
98
99
return n
99
100
}
100
101
102
+ func countSections (path string ) uint16 {
103
+ s := bytesconv .StringToBytes (path )
104
+ return uint16 (bytes .Count (s , strSlash ))
105
+ }
106
+
101
107
type nodeType uint8
102
108
103
109
const (
@@ -394,16 +400,19 @@ type nodeValue struct {
394
400
fullPath string
395
401
}
396
402
403
+ type skippedNode struct {
404
+ path string
405
+ node * node
406
+ paramsCount int16
407
+ }
408
+
397
409
// Returns the handle registered with the given path (key). The values of
398
410
// wildcards are saved to a map.
399
411
// If no handle can be found, a TSR (trailing slash redirect) recommendation is
400
412
// made if a handle exists with an extra (without the) trailing slash for the
401
413
// given path.
402
- func (n * node ) getValue (path string , params * Params , unescape bool ) (value nodeValue ) {
403
- var (
404
- skippedPath string
405
- latestNode = n // Caching the latest node
406
- )
414
+ func (n * node ) getValue (path string , params * Params , skippedNodes * []skippedNode , unescape bool ) (value nodeValue ) {
415
+ var globalParamsCount int16
407
416
408
417
walk: // Outer loop for walking the tree
409
418
for {
@@ -418,15 +427,20 @@ walk: // Outer loop for walking the tree
418
427
if c == idxc {
419
428
// strings.HasPrefix(n.children[len(n.children)-1].path, ":") == n.wildChild
420
429
if n .wildChild {
421
- skippedPath = prefix + path
422
- latestNode = & node {
423
- path : n .path ,
424
- wildChild : n .wildChild ,
425
- nType : n .nType ,
426
- priority : n .priority ,
427
- children : n .children ,
428
- handlers : n .handlers ,
429
- fullPath : n .fullPath ,
430
+ index := len (* skippedNodes )
431
+ * skippedNodes = (* skippedNodes )[:index + 1 ]
432
+ (* skippedNodes )[index ] = skippedNode {
433
+ path : prefix + path ,
434
+ node : & node {
435
+ path : n .path ,
436
+ wildChild : n .wildChild ,
437
+ nType : n .nType ,
438
+ priority : n .priority ,
439
+ children : n .children ,
440
+ handlers : n .handlers ,
441
+ fullPath : n .fullPath ,
442
+ },
443
+ paramsCount : globalParamsCount ,
430
444
}
431
445
}
432
446
@@ -435,10 +449,22 @@ walk: // Outer loop for walking the tree
435
449
}
436
450
}
437
451
// If the path at the end of the loop is not equal to '/' and the current node has no child nodes
438
- // the current node needs to be equal to the latest matching node
439
- matched := path != "/" && ! n .wildChild
440
- if matched {
441
- n = latestNode
452
+ // the current node needs to roll back to last vaild skippedNode
453
+
454
+ if path != "/" && ! n .wildChild {
455
+ for l := len (* skippedNodes ); l > 0 ; {
456
+ skippedNode := (* skippedNodes )[l - 1 ]
457
+ * skippedNodes = (* skippedNodes )[:l - 1 ]
458
+ if strings .HasSuffix (skippedNode .path , path ) {
459
+ path = skippedNode .path
460
+ n = skippedNode .node
461
+ if value .params != nil {
462
+ * value .params = (* value .params )[:skippedNode .paramsCount ]
463
+ }
464
+ globalParamsCount = skippedNode .paramsCount
465
+ continue walk
466
+ }
467
+ }
442
468
}
443
469
444
470
// If there is no wildcard pattern, recommend a redirection
@@ -452,18 +478,12 @@ walk: // Outer loop for walking the tree
452
478
453
479
// Handle wildcard child, which is always at the end of the array
454
480
n = n .children [len (n .children )- 1 ]
481
+ globalParamsCount ++
455
482
456
483
switch n .nType {
457
484
case param :
458
485
// fix truncate the parameter
459
486
// tree_test.go line: 204
460
- if matched {
461
- path = prefix + path
462
- // The saved path is used after the prefix route is intercepted by matching
463
- if n .indices == "/" {
464
- path = skippedPath [1 :]
465
- }
466
- }
467
487
468
488
// Find param end (either '/' or path end)
469
489
end := 0
@@ -549,9 +569,22 @@ walk: // Outer loop for walking the tree
549
569
550
570
if path == prefix {
551
571
// If the current path does not equal '/' and the node does not have a registered handle and the most recently matched node has a child node
552
- // the current node needs to be equal to the latest matching node
553
- if latestNode .wildChild && n .handlers == nil && path != "/" {
554
- n = latestNode .children [len (latestNode .children )- 1 ]
572
+ // the current node needs to roll back to last vaild skippedNode
573
+ if n .handlers == nil && path != "/" {
574
+ for l := len (* skippedNodes ); l > 0 ; {
575
+ skippedNode := (* skippedNodes )[l - 1 ]
576
+ * skippedNodes = (* skippedNodes )[:l - 1 ]
577
+ if strings .HasSuffix (skippedNode .path , path ) {
578
+ path = skippedNode .path
579
+ n = skippedNode .node
580
+ if value .params != nil {
581
+ * value .params = (* value .params )[:skippedNode .paramsCount ]
582
+ }
583
+ globalParamsCount = skippedNode .paramsCount
584
+ continue walk
585
+ }
586
+ }
587
+ // n = latestNode.children[len(latestNode.children)-1]
555
588
}
556
589
// We should have reached the node containing the handle.
557
590
// Check if this node has a handle registered.
@@ -582,19 +615,21 @@ walk: // Outer loop for walking the tree
582
615
return
583
616
}
584
617
585
- if path != "/" && len (skippedPath ) > 0 && strings .HasSuffix (skippedPath , path ) {
586
- path = skippedPath
587
- // Reduce the number of cycles
588
- n , latestNode = latestNode , n
589
- // skippedPath cannot execute
590
- // example:
591
- // * /:cc/cc
592
- // call /a/cc expectations:match/200 Actual:match/200
593
- // call /a/dd expectations:unmatch/404 Actual: panic
594
- // call /addr/dd/aa expectations:unmatch/404 Actual: panic
595
- // skippedPath: It can only be executed if the secondary route is not found
596
- skippedPath = ""
597
- continue walk
618
+ // roll back to last vaild skippedNode
619
+ if path != "/" {
620
+ for l := len (* skippedNodes ); l > 0 ; {
621
+ skippedNode := (* skippedNodes )[l - 1 ]
622
+ * skippedNodes = (* skippedNodes )[:l - 1 ]
623
+ if strings .HasSuffix (skippedNode .path , path ) {
624
+ path = skippedNode .path
625
+ n = skippedNode .node
626
+ if value .params != nil {
627
+ * value .params = (* value .params )[:skippedNode .paramsCount ]
628
+ }
629
+ globalParamsCount = skippedNode .paramsCount
630
+ continue walk
631
+ }
632
+ }
598
633
}
599
634
600
635
// Nothing found. We can recommend to redirect to the same URL with an
0 commit comments