diff --git a/gin_integration_test.go b/gin_integration_test.go index b0532a25..aa692aa7 100644 --- a/gin_integration_test.go +++ b/gin_integration_test.go @@ -463,6 +463,8 @@ func TestTreeRunDynamicRouting(t *testing.T) { testRequest(t, ts.URL+"/a/cc", "", "/:cc/cc") testRequest(t, ts.URL+"/c1/d/e", "", "/c1/:dd/e") testRequest(t, ts.URL+"/c1/d/e1", "", "/c1/:dd/e1") + testRequest(t, ts.URL+"/c1/dd/ee", "", "/:cc/:dd/ee") + testRequest(t, ts.URL+"/c1/dd/ee/", "", "/:cc/:dd/ee") testRequest(t, ts.URL+"/c1/d/ee", "", "/:cc/:dd/ee") testRequest(t, ts.URL+"/c1/d/f", "", "/:cc/:dd/f") testRequest(t, ts.URL+"/c/d/ee", "", "/:cc/:dd/ee") @@ -480,6 +482,7 @@ func TestTreeRunDynamicRouting(t *testing.T) { testRequest(t, ts.URL+"/ab", "", "/:cc") testRequest(t, ts.URL+"/abb", "", "/:cc") testRequest(t, ts.URL+"/abb/cc", "", "/:cc/cc") + testRequest(t, ts.URL+"/c1/cc", "", "/:cc/cc") testRequest(t, ts.URL+"/dddaa", "", "/:cc") testRequest(t, ts.URL+"/allxxxx", "", "/:cc") testRequest(t, ts.URL+"/alldd", "", "/:cc") diff --git a/tree.go b/tree.go index 956bf4dd..9ab3e761 100644 --- a/tree.go +++ b/tree.go @@ -418,6 +418,23 @@ type skippedNode struct { func (n *node) getValue(path string, params *Params, skippedNodes *[]skippedNode, unescape bool) (value nodeValue) { var globalParamsCount int16 + rollbackSkipped := func() bool { + for l := len(*skippedNodes); l > 0; { + skippedNode := (*skippedNodes)[l-1] + *skippedNodes = (*skippedNodes)[:l-1] + if strings.HasSuffix(skippedNode.path, path) { + path = skippedNode.path + n = skippedNode.node + if value.params != nil { + *value.params = (*value.params)[:skippedNode.paramsCount] + } + globalParamsCount = skippedNode.paramsCount + return true + } + } + return false + } + walk: // Outer loop for walking the tree for { prefix := n.path @@ -457,18 +474,8 @@ walk: // Outer loop for walking the tree // If the path at the end of the loop is not equal to '/' and the current node has no child nodes // the current node needs to roll back to last valid skippedNode if path != "/" { - for l := len(*skippedNodes); l > 0; { - skippedNode := (*skippedNodes)[l-1] - *skippedNodes = (*skippedNodes)[:l-1] - if strings.HasSuffix(skippedNode.path, path) { - path = skippedNode.path - n = skippedNode.node - if value.params != nil { - *value.params = (*value.params)[:skippedNode.paramsCount] - } - globalParamsCount = skippedNode.paramsCount - continue walk - } + if rollbackSkipped() { + continue walk } } @@ -535,7 +542,11 @@ walk: // Outer loop for walking the tree // No handle found. Check if a handle for this path + a // trailing slash exists for TSR recommendation n = n.children[0] - value.tsr = (n.path == "/" && n.handlers != nil) || (n.path == "" && n.indices == "/") + if (n.path == "/" && n.handlers != nil) || (n.path == "" && n.indices == "/") { + value.tsr = true + } else if rollbackSkipped() { + continue walk + } } return @@ -574,20 +585,9 @@ walk: // Outer loop for walking the tree // 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 // the current node needs to roll back to last valid skippedNode if n.handlers == nil && path != "/" { - for l := len(*skippedNodes); l > 0; { - skippedNode := (*skippedNodes)[l-1] - *skippedNodes = (*skippedNodes)[:l-1] - if strings.HasSuffix(skippedNode.path, path) { - path = skippedNode.path - n = skippedNode.node - if value.params != nil { - *value.params = (*value.params)[:skippedNode.paramsCount] - } - globalParamsCount = skippedNode.paramsCount - continue walk - } + if rollbackSkipped() { + continue walk } - // n = latestNode.children[len(latestNode.children)-1] } // We should have reached the node containing the handle. // Check if this node has a handle registered. @@ -626,18 +626,8 @@ walk: // Outer loop for walking the tree // roll back to last valid skippedNode if !value.tsr && path != "/" { - for l := len(*skippedNodes); l > 0; { - skippedNode := (*skippedNodes)[l-1] - *skippedNodes = (*skippedNodes)[:l-1] - if strings.HasSuffix(skippedNode.path, path) { - path = skippedNode.path - n = skippedNode.node - if value.params != nil { - *value.params = (*value.params)[:skippedNode.paramsCount] - } - globalParamsCount = skippedNode.paramsCount - continue walk - } + if rollbackSkipped() { + continue walk } } diff --git a/tree_test.go b/tree_test.go index 085b5803..1da6f23f 100644 --- a/tree_test.go +++ b/tree_test.go @@ -240,6 +240,7 @@ func TestTreeWildcard(t *testing.T) { {"/aaa/cc", false, "/:cc/cc", Params{Param{Key: "cc", Value: "aaa"}}}, {"/ab", false, "/:cc", Params{Param{Key: "cc", Value: "ab"}}}, {"/abb", false, "/:cc", Params{Param{Key: "cc", Value: "abb"}}}, + {"/c1/cc", false, "/:cc/cc", Params{Param{Key: "cc", Value: "c1"}}}, {"/abb/cc", false, "/:cc/cc", Params{Param{Key: "cc", Value: "abb"}}}, {"/allxxxx", false, "/:cc", Params{Param{Key: "cc", Value: "allxxxx"}}}, {"/alldd", false, "/:cc", Params{Param{Key: "cc", Value: "alldd"}}}, @@ -266,6 +267,8 @@ func TestTreeWildcard(t *testing.T) { {"/something/secondthingaaaa/thirdthing", false, "/something/:paramname/thirdthing", Params{Param{Key: "paramname", Value: "secondthingaaaa"}}}, {"/something/se/thirdthing", false, "/something/:paramname/thirdthing", Params{Param{Key: "paramname", Value: "se"}}}, {"/something/s/thirdthing", false, "/something/:paramname/thirdthing", Params{Param{Key: "paramname", Value: "s"}}}, + {"/c1/dd/ee", false, "/:cc/:dd/ee", Params{Param{Key: "cc", Value: "c1"}, Param{Key: "dd", Value: "dd"}}}, + {"/c1/dd/ee/", true, "/:cc/:dd/ee", Params{Param{Key: "cc", Value: "c1"}, Param{Key: "dd", Value: "dd"}}}, {"/c/d/ee", false, "/:cc/:dd/ee", Params{Param{Key: "cc", Value: "c"}, Param{Key: "dd", Value: "d"}}}, {"/c/d/e/ff", false, "/:cc/:dd/:ee/ff", Params{Param{Key: "cc", Value: "c"}, Param{Key: "dd", Value: "d"}, Param{Key: "ee", Value: "e"}}}, {"/c/d/e/f/gg", false, "/:cc/:dd/:ee/:ff/gg", Params{Param{Key: "cc", Value: "c"}, Param{Key: "dd", Value: "d"}, Param{Key: "ee", Value: "e"}, Param{Key: "ff", Value: "f"}}}, @@ -474,7 +477,7 @@ func TestTreeDuplicatePath(t *testing.T) { } } - //printChildren(tree, "") + // printChildren(tree, "") checkRequests(t, tree, testRequests{ {"/", false, "/", nil},