From 5ddc3a68ba1678147e3779bc80d3b744125d22fc Mon Sep 17 00:00:00 2001 From: Roland Lammel Date: Mon, 24 Feb 2020 17:26:49 +0100 Subject: [PATCH] Fix routing conflict for dynamic routes and static route with common prefix (#1509) (#1512) * Add test for issue #1509 for dynamic routes and multiple static routes with common prefix * Fix #1509: routing conflict for dynamic routes and static route with common prefix * Improve routing performance for static only route trees --- router.go | 13 ++++++++----- router_test.go | 26 ++++++++++++++++++++++++++ 2 files changed, 34 insertions(+), 5 deletions(-) diff --git a/router.go b/router.go index cb2cc16c8..15a3398f2 100644 --- a/router.go +++ b/router.go @@ -347,7 +347,14 @@ func (r *Router) Find(method, path string, c Context) { if l == pl { // Continue search search = search[l:] - } else { + // Finish routing if no remaining search and we are on an leaf node + if search == "" && (nn == nil || cn.parent == nil || cn.ppath != "") { + break + } + } + + // Attempt to go back up the tree on no matching prefix or no remaining search + if l != pl || search == "" { if nn == nil { // Issue #1348 return // Not found } @@ -360,10 +367,6 @@ func (r *Router) Find(method, path string, c Context) { } } - if search == "" { - break - } - // Static node if child = cn.findChild(search[0], skind); child != nil { // Save next diff --git a/router_test.go b/router_test.go index 92db9d9d2..8c27b9f72 100644 --- a/router_test.go +++ b/router_test.go @@ -567,6 +567,32 @@ func TestRouterParamWithSlash(t *testing.T) { }) } +// Issue #1509 +func TestRouterParamStaticConflict(t *testing.T) { + e := New() + r := e.router + handler := func(c Context) error { + c.Set("path", c.Path()) + return nil + } + + g := e.Group("/g") + g.GET("/skills", handler) + g.GET("/status", handler) + g.GET("/:name", handler) + + c := e.NewContext(nil, nil).(*context) + r.Find(http.MethodGet, "/g/s", c) + c.handler(c) + assert.Equal(t, "s", c.Param("name")) + assert.Equal(t, "/g/:name", c.Get("path")) + + c = e.NewContext(nil, nil).(*context) + r.Find(http.MethodGet, "/g/status", c) + c.handler(c) + assert.Equal(t, "/g/status", c.Get("path")) +} + func TestRouterMatchAny(t *testing.T) { e := New() r := e.router