From 43e32ba83d638c73a415609f26d513eda30033ee Mon Sep 17 00:00:00 2001 From: Roland Lammel Date: Wed, 6 May 2020 23:01:28 +0200 Subject: [PATCH] Fix #1526 trailing slash to any route (#1563) * refs #1526: Add tests for trailing slash requests with nested any routes * refs #1526: Handle specual router case with trailing slash for non-root any route * refs #1526: Fix accidential lookup for any route without trailing slash in request --- router.go | 4 +++ router_test.go | 73 +++++++++++++++++++++++++++++++++++++++++++++++++- 2 files changed, 76 insertions(+), 1 deletion(-) diff --git a/router.go b/router.go index 15a3398f..ed728d6a 100644 --- a/router.go +++ b/router.go @@ -355,6 +355,10 @@ func (r *Router) Find(method, path string, c Context) { // Attempt to go back up the tree on no matching prefix or no remaining search if l != pl || search == "" { + // Handle special case of trailing slash route with existing any route (see #1526) + if path[len(path)-1] == '/' && cn.findChildByKind(akind) != nil { + goto Any + } if nn == nil { // Issue #1348 return // Not found } diff --git a/router_test.go b/router_test.go index 8c27b9f7..0e883233 100644 --- a/router_test.go +++ b/router_test.go @@ -608,7 +608,6 @@ func TestRouterMatchAny(t *testing.T) { return nil }) c := e.NewContext(nil, nil).(*context) - r.Find(http.MethodGet, "/", c) assert.Equal(t, "", c.Param("*")) @@ -619,6 +618,78 @@ func TestRouterMatchAny(t *testing.T) { assert.Equal(t, "joe", c.Param("*")) } +// TestRouterMatchAnySlash shall verify finding the best route +// for any routes with trailing slash requests +func TestRouterMatchAnySlash(t *testing.T) { + e := New() + r := e.router + + handler := func(c Context) error { + c.Set("path", c.Path()) + return nil + } + + // Routes + r.Add(http.MethodGet, "/users", handler) + r.Add(http.MethodGet, "/users/*", handler) + r.Add(http.MethodGet, "/img/*", handler) + r.Add(http.MethodGet, "/img/load", handler) + r.Add(http.MethodGet, "/img/load/*", handler) + r.Add(http.MethodGet, "/assets/*", handler) + + c := e.NewContext(nil, nil).(*context) + r.Find(http.MethodGet, "/", c) + assert.Equal(t, "", c.Param("*")) + + // Test trailing slash request for simple any route (see #1526) + c = e.NewContext(nil, nil).(*context) + r.Find(http.MethodGet, "/users/", c) + c.handler(c) + assert.Equal(t, "/users/*", c.Get("path")) + assert.Equal(t, "", c.Param("*")) + + c = e.NewContext(nil, nil).(*context) + r.Find(http.MethodGet, "/users/joe", c) + c.handler(c) + assert.Equal(t, "/users/*", c.Get("path")) + assert.Equal(t, "joe", c.Param("*")) + + // Test trailing slash request for nested any route (see #1526) + c = e.NewContext(nil, nil).(*context) + r.Find(http.MethodGet, "/img/load", c) + c.handler(c) + assert.Equal(t, "/img/load", c.Get("path")) + assert.Equal(t, "", c.Param("*")) + + c = e.NewContext(nil, nil).(*context) + r.Find(http.MethodGet, "/img/load/", c) + c.handler(c) + assert.Equal(t, "/img/load/*", c.Get("path")) + assert.Equal(t, "", c.Param("*")) + + c = e.NewContext(nil, nil).(*context) + r.Find(http.MethodGet, "/img/load/ben", c) + c.handler(c) + assert.Equal(t, "/img/load/*", c.Get("path")) + assert.Equal(t, "ben", c.Param("*")) + + // Test /assets/* any route + // ... without trailing slash must not match + c = e.NewContext(nil, nil).(*context) + r.Find(http.MethodGet, "/assets", c) + c.handler(c) + assert.Equal(t, nil, c.Get("path")) + assert.Equal(t, "", c.Param("*")) + + // ... with trailing slash must match + c = e.NewContext(nil, nil).(*context) + r.Find(http.MethodGet, "/assets/", c) + c.handler(c) + assert.Equal(t, "/assets/*", c.Get("path")) + assert.Equal(t, "", c.Param("*")) + +} + func TestRouterMatchAnyMultiLevel(t *testing.T) { e := New() r := e.router