diff --git a/bench_test.go b/bench_test.go index d5916841..c1f86ca5 100644 --- a/bench_test.go +++ b/bench_test.go @@ -26,11 +26,30 @@ func BenchmarkMuxSimple(b *testing.B) { handler := func(w http.ResponseWriter, r *http.Request) {} router.HandleFunc("/status", handler) - request, _ := http.NewRequest("GET", "/status", nil) - b.ReportAllocs() - b.ResetTimer() - for i := 0; i < b.N; i++ { - router.ServeHTTP(nil, request) + testCases := []struct { + name string + omitRouteFromContext bool + }{ + { + name: "default", + omitRouteFromContext: false, + }, + { + name: "omit route from ctx", + omitRouteFromContext: true, + }, + } + for _, tc := range testCases { + b.Run(tc.name, func(b *testing.B) { + router.OmitRouteFromContext(tc.omitRouteFromContext) + + request, _ := http.NewRequest("GET", "/status", nil) + b.ReportAllocs() + b.ResetTimer() + for i := 0; i < b.N; i++ { + router.ServeHTTP(nil, request) + } + }) } } diff --git a/mux.go b/mux.go index 72d415a0..0f4511c7 100644 --- a/mux.go +++ b/mux.go @@ -85,6 +85,9 @@ type routeConf struct { // will not redirect skipClean bool + // If true, the http.Request context will not contain the Route. + omitRouteFromContext bool + // Manager for the variables from host and path. regexp routeRegexpGroup @@ -190,7 +193,14 @@ func (r *Router) ServeHTTP(w http.ResponseWriter, req *http.Request) { var handler http.Handler if r.Match(req, &match) { handler = match.Handler - req = requestWithRouteAndVars(req, match.Route, match.Vars) + if handler == nil { + // The default handlers do not make use of the context values. + } else if r.omitRouteFromContext { + // Only populate the match vars (if any) into the context. + req = requestWithVars(req, match.Vars) + } else { + req = requestWithRouteAndVars(req, match.Route, match.Vars) + } } if handler == nil && match.MatchErr == ErrMethodMismatch { @@ -252,6 +262,14 @@ func (r *Router) SkipClean(value bool) *Router { return r } +// OmitRouteFromContext defines the behavior of omitting the Route from the +// http.Request context. +// CurrentRoute will yield nil with this option. +func (r *Router) OmitRouteFromContext(value bool) *Router { + r.omitRouteFromContext = value + return r +} + // UseEncodedPath tells the router to match the encoded original path // to the routes. // For eg. "/path/foo%2Fbar/to" will match the path "/path/{var}/to". diff --git a/mux_test.go b/mux_test.go index f47d6899..cb3bbe0a 100644 --- a/mux_test.go +++ b/mux_test.go @@ -2914,18 +2914,20 @@ func TestGetVarNames(t *testing.T) { } func getPopulateContextTestCases() []struct { - name string - path string - wantVar string - wantStaticRoute bool - wantDynamicRoute bool + name string + path string + omitRouteFromContext bool + wantVar string + wantStaticRoute bool + wantDynamicRoute bool } { return []struct { - name string - path string - wantVar string - wantStaticRoute bool - wantDynamicRoute bool + name string + path string + omitRouteFromContext bool + wantVar string + wantStaticRoute bool + wantDynamicRoute bool }{ { name: "no populated vars", @@ -2938,12 +2940,27 @@ func getPopulateContextTestCases() []struct { path: "/dynamic/", wantVar: "", wantDynamicRoute: true, - }, { + }, + { name: "populated vars", path: "/dynamic/foo", wantVar: "foo", wantDynamicRoute: true, }, + { + name: "omit route /static", + path: "/static", + omitRouteFromContext: true, + wantVar: "", + wantStaticRoute: false, + }, + { + name: "omit route /dynamic", + path: "/dynamic/", + omitRouteFromContext: true, + wantVar: "", + wantDynamicRoute: false, + }, } } @@ -2953,6 +2970,7 @@ func TestPopulateContext(t *testing.T) { t.Run(tc.name, func(t *testing.T) { matched := false r := NewRouter() + r.OmitRouteFromContext(tc.omitRouteFromContext) var static *Route var dynamic *Route fn := func(w http.ResponseWriter, r *http.Request) { @@ -2996,6 +3014,7 @@ func BenchmarkPopulateContext(b *testing.B) { b.Run(tc.name, func(b *testing.B) { matched := false r := NewRouter() + r.OmitRouteFromContext(tc.omitRouteFromContext) fn := func(w http.ResponseWriter, r *http.Request) { matched = true w.WriteHeader(http.StatusNoContent)