diff --git a/router.go b/router.go index ee6f3fa48..a0b8f0f65 100644 --- a/router.go +++ b/router.go @@ -165,7 +165,7 @@ func (r *Router) Reverse(name string, params ...interface{}) string { } if n < ln && (route.Path[i] == '*' || (!hasBackslash && route.Path[i] == ':')) { // in case of `*` wildcard or `:` (unescaped colon) param we replace everything till next slash or end of path - for ; i < l && route.Path[i] != '/'; i++ { + for ; i < l && route.Path[i] != '/' && route.Path[i] != '-'; i++ { } uri.WriteString(fmt.Sprintf("%v", params[n])) n++ @@ -210,7 +210,11 @@ func (r *Router) Add(method, path string, h HandlerFunc) { } for i, lcpIndex := 0, len(path); i < lcpIndex; i++ { - if path[i] == ':' { + if path[i] == ':' || path[i] == '{' { + bracketsOpen := false + if path[i] == '{' { + bracketsOpen = true + } if i > 0 && path[i-1] == '\\' { path = path[:i-1] + path[i:] i-- @@ -220,11 +224,15 @@ func (r *Router) Add(method, path string, h HandlerFunc) { j := i + 1 r.insert(method, path[:i], staticKind, routeMethod{}) - for ; i < lcpIndex && path[i] != '/'; i++ { + for ; i < lcpIndex && (path[i] != '/' && !(path[j-1] == '{' && path[i] == '}')); i++ { } pnames = append(pnames, path[j:i]) - path = path[:j] + path[i:] + if bracketsOpen { + path = path[:j-1] + ":" + path[i+1:] + } else { + path = path[:j] + path[i:] + } i, lcpIndex = j, len(path) if i == lcpIndex { @@ -661,7 +669,13 @@ func (r *Router) Find(method, path string, c Context) { i = l } else { for ; i < l && search[i] != '/'; i++ { + for _, static := range currentNode.staticChildren { + if search[i] == static.label { + goto Done + } + } } + Done: } paramValues[paramIndex] = search[:i] @@ -714,7 +728,6 @@ func (r *Router) Find(method, path string, c Context) { if currentNode == nil && previousBestMatchNode == nil { return // nothing matched at all } - // matchedHandler could be method+path handler that we matched or notFoundHandler from node with matching path // user provided not found (404) handler has priority over generic method not found (405) handler or global 404 handler var rPath string diff --git a/router_test.go b/router_test.go index 619cce092..275447f4a 100644 --- a/router_test.go +++ b/router_test.go @@ -728,6 +728,49 @@ func TestRouterParam(t *testing.T) { } } +func TestRouterRangeParam(t *testing.T) { + e := New() + r := e.router + + r.Add(http.MethodGet, "/flights/{from}.{to}", handlerFunc) + r.Add(http.MethodGet, "/flights/{from}to{to}", handlerFunc) + + var testCases = []struct { + name string + whenURL string + expectRoute interface{} + expectParam map[string]string + }{ + { + name: "route /flights/LAX.DEN to /flights/{from}.{to}", + whenURL: "/flights/LAX.DEN", + expectRoute: "/flights/{from}.{to}", + expectParam: map[string]string{"from": "LAX", "to": "DEN"}, + }, + { + name: "route /flights/LAXtoDEN to /flights/{from}to{to}", + whenURL: "/flights/LAXtoDEN", + expectRoute: "/flights/{from}to{to}", + expectParam: map[string]string{"from": "LAX", "to": "DEN"}, + }, + } + + for _, tc := range testCases { + t.Run(tc.name, func(t *testing.T) { + + c := e.NewContext(nil, nil).(*context) + r.Find(http.MethodGet, tc.whenURL, c) + + c.handler(c) + assert.Equal(t, tc.expectRoute, c.Get("path")) + for param, expectedValue := range tc.expectParam { + assert.Equal(t, expectedValue, c.Param(param)) + } + checkUnusedParamValues(t, c, tc.expectParam) + }) + } +} + func TestRouter_addAndMatchAllSupportedMethods(t *testing.T) { var testCases = []struct { name string