1
0
mirror of https://github.com/labstack/echo.git synced 2025-04-23 12:18:53 +02:00

When route is registered with empty path it is normalized to /. Make sure that returned echo.Route structs reflect that behavior. (#2616)

This commit is contained in:
Martti T 2024-03-27 12:28:46 +02:00 committed by GitHub
parent d549290448
commit 447c92d842
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
3 changed files with 44 additions and 15 deletions

View File

@ -1598,6 +1598,11 @@ func TestEchoReverse(t *testing.T) {
whenParams []interface{} whenParams []interface{}
expect string expect string
}{ }{
{
name: "ok, not existing path returns empty url",
whenRouteName: "not-existing",
expect: "",
},
{ {
name: "ok,static with no params", name: "ok,static with no params",
whenRouteName: "/static", whenRouteName: "/static",

View File

@ -185,8 +185,18 @@ func (r *Router) Reverse(name string, params ...interface{}) string {
return uri.String() return uri.String()
} }
func normalizePathSlash(path string) string {
if path == "" {
path = "/"
} else if path[0] != '/' {
path = "/" + path
}
return path
}
func (r *Router) add(method, path, name string, h HandlerFunc) *Route { func (r *Router) add(method, path, name string, h HandlerFunc) *Route {
r.Add(method, path, h) path = normalizePathSlash(path)
r.insert(method, path, h)
route := &Route{ route := &Route{
Method: method, Method: method,
@ -199,13 +209,11 @@ func (r *Router) add(method, path, name string, h HandlerFunc) *Route {
// Add registers a new route for method and path with matching handler. // Add registers a new route for method and path with matching handler.
func (r *Router) Add(method, path string, h HandlerFunc) { func (r *Router) Add(method, path string, h HandlerFunc) {
// Validate path r.insert(method, normalizePathSlash(path), h)
if path == "" { }
path = "/"
} func (r *Router) insert(method, path string, h HandlerFunc) {
if path[0] != '/' { path = normalizePathSlash(path)
path = "/" + path
}
pnames := []string{} // Param names pnames := []string{} // Param names
ppath := path // Pristine path ppath := path // Pristine path
@ -224,7 +232,7 @@ func (r *Router) Add(method, path string, h HandlerFunc) {
} }
j := i + 1 j := i + 1
r.insert(method, path[:i], staticKind, routeMethod{}) r.insertNode(method, path[:i], staticKind, routeMethod{})
for ; i < lcpIndex && path[i] != '/'; i++ { for ; i < lcpIndex && path[i] != '/'; i++ {
} }
@ -234,21 +242,21 @@ func (r *Router) Add(method, path string, h HandlerFunc) {
if i == lcpIndex { if i == lcpIndex {
// path node is last fragment of route path. ie. `/users/:id` // path node is last fragment of route path. ie. `/users/:id`
r.insert(method, path[:i], paramKind, routeMethod{ppath, pnames, h}) r.insertNode(method, path[:i], paramKind, routeMethod{ppath, pnames, h})
} else { } else {
r.insert(method, path[:i], paramKind, routeMethod{}) r.insertNode(method, path[:i], paramKind, routeMethod{})
} }
} else if path[i] == '*' { } else if path[i] == '*' {
r.insert(method, path[:i], staticKind, routeMethod{}) r.insertNode(method, path[:i], staticKind, routeMethod{})
pnames = append(pnames, "*") pnames = append(pnames, "*")
r.insert(method, path[:i+1], anyKind, routeMethod{ppath, pnames, h}) r.insertNode(method, path[:i+1], anyKind, routeMethod{ppath, pnames, h})
} }
} }
r.insert(method, path, staticKind, routeMethod{ppath, pnames, h}) r.insertNode(method, path, staticKind, routeMethod{ppath, pnames, h})
} }
func (r *Router) insert(method, path string, t kind, rm routeMethod) { func (r *Router) insertNode(method, path string, t kind, rm routeMethod) {
// Adjust max param // Adjust max param
paramLen := len(rm.pnames) paramLen := len(rm.pnames)
if *r.echo.maxParam < paramLen { if *r.echo.maxParam < paramLen {

View File

@ -2770,6 +2770,22 @@ func TestRouter_Routes(t *testing.T) {
} }
} }
func TestRouter_addEmptyPathToSlashReverse(t *testing.T) {
e := New()
r := e.router
r.add(http.MethodGet, "", "empty", handlerFunc) // emtpy path is normalized to `/`
assert.Equal(t, "/", r.Reverse("empty"))
}
func TestRouter_ReverseNotFound(t *testing.T) {
e := New()
r := e.router
r.add(http.MethodGet, "", "empty", handlerFunc)
assert.Equal(t, "", r.Reverse("not-existing"))
}
func TestRouter_Reverse(t *testing.T) { func TestRouter_Reverse(t *testing.T) {
e := New() e := New()
r := e.router r := e.router