Skip to content

Commit 43e32ba

Browse files
authored
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
1 parent c08f303 commit 43e32ba

File tree

2 files changed

+76
-1
lines changed

2 files changed

+76
-1
lines changed

router.go

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -355,6 +355,10 @@ func (r *Router) Find(method, path string, c Context) {
355355

356356
// Attempt to go back up the tree on no matching prefix or no remaining search
357357
if l != pl || search == "" {
358+
// Handle special case of trailing slash route with existing any route (see #1526)
359+
if path[len(path)-1] == '/' && cn.findChildByKind(akind) != nil {
360+
goto Any
361+
}
358362
if nn == nil { // Issue #1348
359363
return // Not found
360364
}

router_test.go

Lines changed: 72 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -608,7 +608,6 @@ func TestRouterMatchAny(t *testing.T) {
608608
return nil
609609
})
610610
c := e.NewContext(nil, nil).(*context)
611-
612611
r.Find(http.MethodGet, "/", c)
613612
assert.Equal(t, "", c.Param("*"))
614613

@@ -619,6 +618,78 @@ func TestRouterMatchAny(t *testing.T) {
619618
assert.Equal(t, "joe", c.Param("*"))
620619
}
621620

621+
// TestRouterMatchAnySlash shall verify finding the best route
622+
// for any routes with trailing slash requests
623+
func TestRouterMatchAnySlash(t *testing.T) {
624+
e := New()
625+
r := e.router
626+
627+
handler := func(c Context) error {
628+
c.Set("path", c.Path())
629+
return nil
630+
}
631+
632+
// Routes
633+
r.Add(http.MethodGet, "/users", handler)
634+
r.Add(http.MethodGet, "/users/*", handler)
635+
r.Add(http.MethodGet, "/img/*", handler)
636+
r.Add(http.MethodGet, "/img/load", handler)
637+
r.Add(http.MethodGet, "/img/load/*", handler)
638+
r.Add(http.MethodGet, "/assets/*", handler)
639+
640+
c := e.NewContext(nil, nil).(*context)
641+
r.Find(http.MethodGet, "/", c)
642+
assert.Equal(t, "", c.Param("*"))
643+
644+
// Test trailing slash request for simple any route (see #1526)
645+
c = e.NewContext(nil, nil).(*context)
646+
r.Find(http.MethodGet, "/users/", c)
647+
c.handler(c)
648+
assert.Equal(t, "/users/*", c.Get("path"))
649+
assert.Equal(t, "", c.Param("*"))
650+
651+
c = e.NewContext(nil, nil).(*context)
652+
r.Find(http.MethodGet, "/users/joe", c)
653+
c.handler(c)
654+
assert.Equal(t, "/users/*", c.Get("path"))
655+
assert.Equal(t, "joe", c.Param("*"))
656+
657+
// Test trailing slash request for nested any route (see #1526)
658+
c = e.NewContext(nil, nil).(*context)
659+
r.Find(http.MethodGet, "/img/load", c)
660+
c.handler(c)
661+
assert.Equal(t, "/img/load", c.Get("path"))
662+
assert.Equal(t, "", c.Param("*"))
663+
664+
c = e.NewContext(nil, nil).(*context)
665+
r.Find(http.MethodGet, "/img/load/", c)
666+
c.handler(c)
667+
assert.Equal(t, "/img/load/*", c.Get("path"))
668+
assert.Equal(t, "", c.Param("*"))
669+
670+
c = e.NewContext(nil, nil).(*context)
671+
r.Find(http.MethodGet, "/img/load/ben", c)
672+
c.handler(c)
673+
assert.Equal(t, "/img/load/*", c.Get("path"))
674+
assert.Equal(t, "ben", c.Param("*"))
675+
676+
// Test /assets/* any route
677+
// ... without trailing slash must not match
678+
c = e.NewContext(nil, nil).(*context)
679+
r.Find(http.MethodGet, "/assets", c)
680+
c.handler(c)
681+
assert.Equal(t, nil, c.Get("path"))
682+
assert.Equal(t, "", c.Param("*"))
683+
684+
// ... with trailing slash must match
685+
c = e.NewContext(nil, nil).(*context)
686+
r.Find(http.MethodGet, "/assets/", c)
687+
c.handler(c)
688+
assert.Equal(t, "/assets/*", c.Get("path"))
689+
assert.Equal(t, "", c.Param("*"))
690+
691+
}
692+
622693
func TestRouterMatchAnyMultiLevel(t *testing.T) {
623694
e := New()
624695
r := e.router

0 commit comments

Comments
 (0)