From 2921582d11d517dff4cf0226bfbcd8bc7c63d536 Mon Sep 17 00:00:00 2001 From: Yue Yang Date: Wed, 19 May 2021 10:05:36 +0800 Subject: [PATCH 1/3] Fix conflict between param and exact path (#2706) * Fix conflict between param and exact path Signed-off-by: Yue Yang * Add test Signed-off-by: Yue Yang * Fix prefix conflict in exact paths Signed-off-by: Yue Yang * Use backtracking Signed-off-by: Yue Yang * Fix panic Signed-off-by: Yue Yang --- tree.go | 29 +++++++++++++++++++++++++++++ tree_test.go | 18 +++++++++++++++--- 2 files changed, 44 insertions(+), 3 deletions(-) diff --git a/tree.go b/tree.go index ca753e6d..0d082d05 100644 --- a/tree.go +++ b/tree.go @@ -118,6 +118,11 @@ type node struct { fullPath string } +type skip struct { + path string + paramNode *node +} + // Increments priority of the given child and reorders if necessary func (n *node) incrementChildPrio(pos int) int { cs := n.children @@ -400,6 +405,8 @@ type nodeValue struct { // made if a handle exists with an extra (without the) trailing slash for the // given path. func (n *node) getValue(path string, params *Params, unescape bool) (value nodeValue) { + var skipped *skip + walk: // Outer loop for walking the tree for { prefix := n.path @@ -411,6 +418,21 @@ walk: // Outer loop for walking the tree idxc := path[0] for i, c := range []byte(n.indices) { if c == idxc { + if strings.HasPrefix(n.children[len(n.children)-1].path, ":") { + skipped = &skip{ + path: prefix + path, + paramNode: &node{ + path: n.path, + wildChild: n.wildChild, + nType: n.nType, + priority: n.priority, + children: n.children, + handlers: n.handlers, + fullPath: n.fullPath, + }, + } + } + n = n.children[i] continue walk } @@ -542,6 +564,13 @@ walk: // Outer loop for walking the tree return } + if path != "/" && skipped != nil && strings.HasSuffix(skipped.path, path) { + path = skipped.path + n = skipped.paramNode + skipped = nil + continue walk + } + // Nothing found. We can recommend to redirect to the same URL with an // extra trailing slash if a leaf exists for that path value.tsr = (path == "/") || diff --git a/tree_test.go b/tree_test.go index d7c4fb0b..298c5ed0 100644 --- a/tree_test.go +++ b/tree_test.go @@ -135,13 +135,16 @@ func TestTreeWildcard(t *testing.T) { routes := [...]string{ "/", - "/cmd/:tool/:sub", "/cmd/:tool/", + "/cmd/:tool/:sub", "/cmd/whoami", + "/cmd/whoami/root", "/cmd/whoami/root/", "/src/*filepath", "/search/", "/search/:query", + "/search/gin-gonic", + "/search/google", "/user_:name", "/user_:name/about", "/files/:dir/*filepath", @@ -150,6 +153,7 @@ func TestTreeWildcard(t *testing.T) { "/doc/go1.html", "/info/:user/public", "/info/:user/project/:project", + "/info/:user/project/golang", } for _, route := range routes { tree.addRoute(route, fakeHandler(route)) @@ -159,21 +163,29 @@ func TestTreeWildcard(t *testing.T) { {"/", false, "/", nil}, {"/cmd/test", true, "/cmd/:tool/", Params{Param{"tool", "test"}}}, {"/cmd/test/", false, "/cmd/:tool/", Params{Param{"tool", "test"}}}, + {"/cmd/test/3", false, "/cmd/:tool/:sub", Params{Param{Key: "tool", Value: "test"}, Param{Key: "sub", Value: "3"}}}, + {"/cmd/who", true, "/cmd/:tool/", Params{Param{"tool", "who"}}}, + {"/cmd/who/", false, "/cmd/:tool/", Params{Param{"tool", "who"}}}, {"/cmd/whoami", false, "/cmd/whoami", nil}, {"/cmd/whoami/", true, "/cmd/whoami", nil}, + {"/cmd/whoami/r", false, "/cmd/:tool/:sub", Params{Param{Key: "tool", Value: "whoami"}, Param{Key: "sub", Value: "r"}}}, + {"/cmd/whoami/r/", true, "/cmd/:tool/:sub", Params{Param{Key: "tool", Value: "whoami"}, Param{Key: "sub", Value: "r"}}}, + {"/cmd/whoami/root", false, "/cmd/whoami/root", nil}, {"/cmd/whoami/root/", false, "/cmd/whoami/root/", nil}, - {"/cmd/whoami/root", true, "/cmd/whoami/root/", nil}, - {"/cmd/test/3", false, "/cmd/:tool/:sub", Params{Param{Key: "tool", Value: "test"}, Param{Key: "sub", Value: "3"}}}, {"/src/", false, "/src/*filepath", Params{Param{Key: "filepath", Value: "/"}}}, {"/src/some/file.png", false, "/src/*filepath", Params{Param{Key: "filepath", Value: "/some/file.png"}}}, {"/search/", false, "/search/", nil}, {"/search/someth!ng+in+ünìcodé", false, "/search/:query", Params{Param{Key: "query", Value: "someth!ng+in+ünìcodé"}}}, {"/search/someth!ng+in+ünìcodé/", true, "", Params{Param{Key: "query", Value: "someth!ng+in+ünìcodé"}}}, + {"/search/gin", false, "/search/:query", Params{Param{"query", "gin"}}}, + {"/search/gin-gonic", false, "/search/gin-gonic", nil}, + {"/search/google", false, "/search/google", nil}, {"/user_gopher", false, "/user_:name", Params{Param{Key: "name", Value: "gopher"}}}, {"/user_gopher/about", false, "/user_:name/about", Params{Param{Key: "name", Value: "gopher"}}}, {"/files/js/inc/framework.js", false, "/files/:dir/*filepath", Params{Param{Key: "dir", Value: "js"}, Param{Key: "filepath", Value: "/inc/framework.js"}}}, {"/info/gordon/public", false, "/info/:user/public", Params{Param{Key: "user", Value: "gordon"}}}, {"/info/gordon/project/go", false, "/info/:user/project/:project", Params{Param{Key: "user", Value: "gordon"}, Param{Key: "project", Value: "go"}}}, + {"/info/gordon/project/golang", false, "/info/:user/project/golang", Params{Param{Key: "user", Value: "gordon"}}}, }) checkPriorities(t, tree) From d7091e7decc336b13a68c648433312778704692d Mon Sep 17 00:00:00 2001 From: yugu Date: Wed, 19 May 2021 10:57:23 +0800 Subject: [PATCH 2/3] README.md update (#2715) Co-authored-by: Bo-Yi Wu --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 6f9178ca..38c67487 100644 --- a/README.md +++ b/README.md @@ -702,7 +702,7 @@ func main() { // Example for binding XML ( // // - // user + // manu // 123 // ) router.POST("/loginXML", func(c *gin.Context) { From e72e584d1abae00fb42ef9aba1ea262c062ba2dc Mon Sep 17 00:00:00 2001 From: Bo-Yi Wu Date: Thu, 20 May 2021 07:57:55 +0800 Subject: [PATCH 3/3] chore(docs): bump to v1.7.2 (#2724) * chore(docs): bump to v1.7.2 Signed-off-by: Bo-Yi Wu * chore: add change log Signed-off-by: Bo-Yi Wu --- CHANGELOG.md | 6 ++++++ version.go | 2 +- 2 files changed, 7 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index dc2c2f55..a28edc84 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,11 @@ # Gin ChangeLog +## Gin v1.7.2 + +### BUGFIXES + +* Fix conflict between param and exact path [#2706](https://github.com/gin-gonic/gin/issues/2706). Close issue [#2682](https://github.com/gin-gonic/gin/issues/2682) [#2696](https://github.com/gin-gonic/gin/issues/2696). + ## Gin v1.7.1 ### BUGFIXES diff --git a/version.go b/version.go index 3647461b..a80ab69a 100644 --- a/version.go +++ b/version.go @@ -5,4 +5,4 @@ package gin // Version is the current gin framework's version. -const Version = "v1.7.1" +const Version = "v1.7.2"