diff --git a/route.go b/route.go index 0135731..63cde96 100644 --- a/route.go +++ b/route.go @@ -16,7 +16,7 @@ type Route struct { // Pattern is the URI pattern to match Pattern string // TrailingSlash if set to true, the URI will be matched with or without - // a trailing slash. Note: It does not *do* a redirect. + // a trailing slash. IMPORTANT: It does not redirect. TrailingSlash bool // FallThroughPostResponse if enabled will execute all the handlers even if a response was already sent to the client @@ -44,6 +44,9 @@ func (r *Route) computePatternStr(patternString string, hasWildcard bool, key st if hasWildcard { patternKey = fmt.Sprintf(":%s*", key) regexPattern = urlwildcard + if r.TrailingSlash { + regexPattern = urlwildcardWithTrailslash + } } else { patternKey = fmt.Sprintf(":%s", key) regexPattern = urlchars diff --git a/router.go b/router.go index a5c30ab..ea8ce29 100644 --- a/router.go +++ b/router.go @@ -16,12 +16,11 @@ import ( // https://tools.ietf.org/html/rfc3986 // Though the current one allows invalid characters in the URI parameter, it has better performance. const ( - urlchars = `([^/]+)` - urlwildcard = `(.*)` - trailingSlash = `[\/]?` - errMultiHeaderWrite = `http: multiple response.WriteHeader calls` - errMultiWrite = `http: multiple response.Write calls` - errDuplicateKey = `Error: Duplicate URI keys found` + urlchars = `([^/]+)` + urlwildcard = `(.*)[^/]` + urlwildcardWithTrailslash = `(.*)[/]?` + trailingSlash = `[/]?` + errDuplicateKey = `Error: Duplicate URI keys found` ) var ( diff --git a/router_test.go b/router_test.go index 6117e1c..694d54f 100644 --- a/router_test.go +++ b/router_test.go @@ -36,14 +36,17 @@ func TestRouter_ServeHTTP(t *testing.T) { url := baseAPI if l.Path != "" { switch l.TestType { - case "checkpath", "checkpathnotrailingslash", "chaining", "chaining-nofallthrough": + case "checkpath", + "checkpathnotrailingslash", + "chaining", + "chaining-nofallthrough": { url = strings.Join([]string{url, l.Path}, "") } - case "checkparams": + case "checkparams", "widlcardwithouttrailingslash": { for idx, key := range l.ParamKeys { - // in case of wildcard params, they have to replaced first for proper URL construction + // in case of wildcard params, they have to be replaced first for proper URL construction l.Path = strings.Replace(l.Path, ":"+key+"*", l.Params[idx], 1) l.Path = strings.Replace(l.Path, ":"+key, l.Params[idx], 1) } @@ -60,7 +63,7 @@ func TestRouter_ServeHTTP(t *testing.T) { router.ServeHTTP(respRec, req) switch l.TestType { - case "checkpath", "checkpathnotrailingslash": + case "checkpath", "checkpathnotrailingslash", "widlcardwithouttrailingslash": { err = checkPath(req, respRec) } @@ -99,7 +102,15 @@ func TestRouter_ServeHTTP(t *testing.T) { ) } } + } else if err == nil && l.WantErr { + t.Errorf( + "'%s' (%s '%s') expected error, but received nil", + l.Name, + l.Method, + url, + ) } + err = checkMiddleware(req, respRec) if err != nil { t.Error(err.Error()) @@ -138,7 +149,7 @@ func getRoutes() []*Route { }, ) } - case "checkpathnotrailingslash": + case "checkpathnotrailingslash", "widlcardwithouttrailingslash": { rr = append(rr, &Route{ @@ -152,6 +163,7 @@ func getRoutes() []*Route { ) } + case "chaining": { rr = append( @@ -462,6 +474,24 @@ func testTable() []struct { Params: []string{"hello/world/hi/there/-/~/./again"}, WantErr: false, }, + { + Name: "Check with wildcard - 3", + TestType: "widlcardwithouttrailingslash", + Path: "/wildcard3/:a*", + Method: http.MethodGet, + ParamKeys: []string{"a"}, + Params: []string{"hello/world/hi/there/-/~/./again/"}, + WantErr: true, + }, + { + Name: "Check with wildcard - 4", + TestType: "widlcardwithouttrailingslash", + Path: "/wildcard3/:a*", + Method: http.MethodGet, + ParamKeys: []string{"a"}, + Params: []string{"hello/world/hi/there/-/~/./again"}, + WantErr: false, + }, { Name: "Check not implemented", TestType: "notimplemented",