Fix: 404 bug with param

This commit is contained in:
Stephano George 2022-08-17 11:47:37 +08:00
parent 1c48977cca
commit cee994f045
3 changed files with 35 additions and 39 deletions

View File

@ -463,6 +463,8 @@ func TestTreeRunDynamicRouting(t *testing.T) {
testRequest(t, ts.URL+"/a/cc", "", "/:cc/cc") testRequest(t, ts.URL+"/a/cc", "", "/:cc/cc")
testRequest(t, ts.URL+"/c1/d/e", "", "/c1/:dd/e") 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/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/ee", "", "/:cc/:dd/ee")
testRequest(t, ts.URL+"/c1/d/f", "", "/:cc/:dd/f") testRequest(t, ts.URL+"/c1/d/f", "", "/:cc/:dd/f")
testRequest(t, ts.URL+"/c/d/ee", "", "/:cc/:dd/ee") 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+"/ab", "", "/:cc")
testRequest(t, ts.URL+"/abb", "", "/:cc") testRequest(t, ts.URL+"/abb", "", "/:cc")
testRequest(t, ts.URL+"/abb/cc", "", "/:cc/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+"/dddaa", "", "/:cc")
testRequest(t, ts.URL+"/allxxxx", "", "/:cc") testRequest(t, ts.URL+"/allxxxx", "", "/:cc")
testRequest(t, ts.URL+"/alldd", "", "/:cc") testRequest(t, ts.URL+"/alldd", "", "/:cc")

60
tree.go
View File

@ -418,6 +418,23 @@ type skippedNode struct {
func (n *node) getValue(path string, params *Params, skippedNodes *[]skippedNode, unescape bool) (value nodeValue) { func (n *node) getValue(path string, params *Params, skippedNodes *[]skippedNode, unescape bool) (value nodeValue) {
var globalParamsCount int16 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 walk: // Outer loop for walking the tree
for { for {
prefix := n.path prefix := n.path
@ -457,20 +474,10 @@ 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 // 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 // the current node needs to roll back to last valid skippedNode
if path != "/" { if path != "/" {
for l := len(*skippedNodes); l > 0; { if rollbackSkipped() {
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 continue walk
} }
} }
}
// Nothing found. // Nothing found.
// We can recommend to redirect to the same URL without a // We can recommend to redirect to the same URL without a
@ -535,7 +542,11 @@ walk: // Outer loop for walking the tree
// No handle found. Check if a handle for this path + a // No handle found. Check if a handle for this path + a
// trailing slash exists for TSR recommendation // trailing slash exists for TSR recommendation
n = n.children[0] 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 return
@ -574,21 +585,10 @@ 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 // 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 // the current node needs to roll back to last valid skippedNode
if n.handlers == nil && path != "/" { if n.handlers == nil && path != "/" {
for l := len(*skippedNodes); l > 0; { if rollbackSkipped() {
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 continue walk
} }
} }
// n = latestNode.children[len(latestNode.children)-1]
}
// We should have reached the node containing the handle. // We should have reached the node containing the handle.
// Check if this node has a handle registered. // Check if this node has a handle registered.
if value.handlers = n.handlers; value.handlers != nil { if value.handlers = n.handlers; value.handlers != nil {
@ -626,20 +626,10 @@ walk: // Outer loop for walking the tree
// roll back to last valid skippedNode // roll back to last valid skippedNode
if !value.tsr && path != "/" { if !value.tsr && path != "/" {
for l := len(*skippedNodes); l > 0; { if rollbackSkipped() {
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 continue walk
} }
} }
}
return return
} }

View File

@ -240,6 +240,7 @@ func TestTreeWildcard(t *testing.T) {
{"/aaa/cc", false, "/:cc/cc", Params{Param{Key: "cc", Value: "aaa"}}}, {"/aaa/cc", false, "/:cc/cc", Params{Param{Key: "cc", Value: "aaa"}}},
{"/ab", false, "/:cc", Params{Param{Key: "cc", Value: "ab"}}}, {"/ab", false, "/:cc", Params{Param{Key: "cc", Value: "ab"}}},
{"/abb", false, "/:cc", Params{Param{Key: "cc", Value: "abb"}}}, {"/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"}}}, {"/abb/cc", false, "/:cc/cc", Params{Param{Key: "cc", Value: "abb"}}},
{"/allxxxx", false, "/:cc", Params{Param{Key: "cc", Value: "allxxxx"}}}, {"/allxxxx", false, "/:cc", Params{Param{Key: "cc", Value: "allxxxx"}}},
{"/alldd", false, "/:cc", Params{Param{Key: "cc", Value: "alldd"}}}, {"/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/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/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"}}}, {"/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/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/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"}}}, {"/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"}}},