Skip to content

Commit a64188c

Browse files
committed
Merge branch 'neotel-at-bugfix/1412-route-matchany-multilevel'
2 parents 5c7c87d + 8f69b47 commit a64188c

File tree

3 files changed

+273
-56
lines changed

3 files changed

+273
-56
lines changed

group_test.go

Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -65,3 +65,42 @@ func TestGroupRouteMiddleware(t *testing.T) {
6565
c, _ = request(http.MethodGet, "/group/405", e)
6666
assert.Equal(t, 405, c)
6767
}
68+
69+
func TestGroupRouteMiddlewareWithMatchAny(t *testing.T) {
70+
// Ensure middleware and match any routes do not conflict
71+
e := New()
72+
g := e.Group("/group")
73+
m1 := func(next HandlerFunc) HandlerFunc {
74+
return func(c Context) error {
75+
return next(c)
76+
}
77+
}
78+
m2 := func(next HandlerFunc) HandlerFunc {
79+
return func(c Context) error {
80+
return c.String(http.StatusOK, c.Path())
81+
}
82+
}
83+
h := func(c Context) error {
84+
return c.String(http.StatusOK, c.Path())
85+
}
86+
g.Use(m1)
87+
g.GET("/help", h, m2)
88+
g.GET("/*", h, m2)
89+
g.GET("", h, m2)
90+
e.GET("unrelated", h, m2)
91+
e.GET("*", h, m2)
92+
93+
_, m := request(http.MethodGet, "/group/help", e)
94+
assert.Equal(t, "/group/help", m)
95+
_, m = request(http.MethodGet, "/group/help/other", e)
96+
assert.Equal(t, "/group/*", m)
97+
_, m = request(http.MethodGet, "/group/404", e)
98+
assert.Equal(t, "/group/*", m)
99+
_, m = request(http.MethodGet, "/group", e)
100+
assert.Equal(t, "/group", m)
101+
_, m = request(http.MethodGet, "/other", e)
102+
assert.Equal(t, "/*", m)
103+
_, m = request(http.MethodGet, "/", e)
104+
assert.Equal(t, "/*", m)
105+
106+
}

router.go

Lines changed: 36 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,9 @@
11
package echo
22

3-
import "net/http"
3+
import (
4+
"net/http"
5+
"strings"
6+
)
47

58
type (
69
// Router is the registry of all registered routes for an `Echo` instance for
@@ -20,8 +23,8 @@ type (
2023
pnames []string
2124
methodHandler *methodHandler
2225
}
23-
kind uint8
24-
children []*node
26+
kind uint8
27+
children []*node
2528
methodHandler struct {
2629
connect HandlerFunc
2730
delete HandlerFunc
@@ -133,6 +136,11 @@ func (r *Router) insert(method, path string, h HandlerFunc, t kind, ppath string
133136
// Split node
134137
n := newNode(cn.kind, cn.prefix[l:], cn, cn.children, cn.methodHandler, cn.ppath, cn.pnames)
135138

139+
// Update parent path for all children to new node
140+
for _, child := range cn.children {
141+
child.parent = n
142+
}
143+
136144
// Reset parent node
137145
cn.kind = skind
138146
cn.label = cn.prefix[0]
@@ -336,7 +344,6 @@ func (r *Router) Find(method, path string, c Context) {
336344
}
337345
}
338346

339-
340347
if l == pl {
341348
// Continue search
342349
search = search[l:]
@@ -398,16 +405,32 @@ func (r *Router) Find(method, path string, c Context) {
398405
Any:
399406
if cn = cn.findChildByKind(akind); cn == nil {
400407
if nn != nil {
401-
cn = nn
402-
nn = cn.parent // Next (Issue #954)
403-
if nn != nil {
404-
nk = nn.kind
405-
}
408+
// No next node to go down in routing (issue #954)
409+
// Find nearest "any" route going up the routing tree
406410
search = ns
407-
if nk == pkind {
408-
goto Param
409-
} else if nk == akind {
410-
goto Any
411+
np := nn.parent
412+
// Consider param route one level up only
413+
// if no slash is remaining in search string
414+
if cn = nn.findChildByKind(pkind); cn != nil && strings.IndexByte(ns, '/') == -1 {
415+
break
416+
}
417+
for {
418+
np = nn.parent
419+
if cn = nn.findChildByKind(akind); cn != nil {
420+
break
421+
}
422+
if np == nil {
423+
break // no further parent nodes in tree, abort
424+
}
425+
var str strings.Builder
426+
str.WriteString(nn.prefix)
427+
str.WriteString(search)
428+
search = str.String()
429+
nn = np
430+
}
431+
if cn != nil { // use the found "any" route and update path
432+
pvalues[len(cn.pnames)-1] = search
433+
break
411434
}
412435
}
413436
return // Not found

0 commit comments

Comments
 (0)