From 8ac5cf967fbadf2522625826070379e0fd6e2f98 Mon Sep 17 00:00:00 2001 From: Dave Newman Date: Tue, 20 May 2014 14:59:54 -0700 Subject: [PATCH] Add SkipClean option By default paths are run through the cleanPath method which prevents using fancier paths like /fetch/http://xkcd.com/534 This adds a SkipClean option so that this path isn't redirected to /fetch/http/xkcd.com/534 --- mux.go | 30 ++++++++++++++++++++++++------ route.go | 9 ++++++--- 2 files changed, 30 insertions(+), 9 deletions(-) diff --git a/mux.go b/mux.go index fbb7f19..b399699 100644 --- a/mux.go +++ b/mux.go @@ -48,6 +48,8 @@ type Router struct { namedRoutes map[string]*Route // See Router.StrictSlash(). This defines the flag for new routes. strictSlash bool + // See Router.SkipClean(). This defines the flag for new routes. + skipClean bool // If true, do not clear the request context after handling the request KeepContext bool } @@ -73,8 +75,9 @@ func (r *Router) Match(req *http.Request, match *RouteMatch) bool { // When there is a match, the route variables can be retrieved calling // mux.Vars(request). func (r *Router) ServeHTTP(w http.ResponseWriter, req *http.Request) { - // Clean path to canonical form and redirect. - if p := cleanPath(req.URL.Path); p != req.URL.Path { + if !r.skipClean { + // Clean path to canonical form and redirect. + if p := cleanPath(req.URL.Path); p != req.URL.Path { // Added 3 lines (Philip Schlump) - It was dropping the query string and #whatever from query. // This matches with fix in go 1.2 r.c. 4 for same problem. Go Issue: @@ -83,9 +86,10 @@ func (r *Router) ServeHTTP(w http.ResponseWriter, req *http.Request) { url.Path = p p = url.String() - w.Header().Set("Location", p) - w.WriteHeader(http.StatusMovedPermanently) - return + w.Header().Set("Location", p) + w.WriteHeader(http.StatusMovedPermanently) + return + } } var match RouteMatch var handler http.Handler @@ -133,6 +137,19 @@ func (r *Router) StrictSlash(value bool) *Router { return r } +// SkipClean defines the path cleaning behaviour for new routes. The initial +// value is false. +// +// When true, if the route path is "/path//to", it will remain with the double +// slash. This is helpful if you have a route like: /fetch/http://xkcd.com/534/ +// +// When false, the path will be cleaned, so /fetch/http://xkcd.com/534/ will +// become /fetch/http/xkcd.com/534 +func (r *Router) SkipClean(value bool) *Router { + r.skipClean = value + return r +} + // ---------------------------------------------------------------------------- // parentRoute // ---------------------------------------------------------------------------- @@ -170,7 +187,7 @@ func (r *Router) buildVars(m map[string]string) map[string]string { // NewRoute registers an empty route. func (r *Router) NewRoute() *Route { - route := &Route{parent: r, strictSlash: r.strictSlash} + route := &Route{parent: r, strictSlash: r.strictSlash, skipClean: r.skipClean} r.routes = append(r.routes, route) return route } @@ -357,6 +374,7 @@ func cleanPath(p string) string { if p[len(p)-1] == '/' && np != "/" { np += "/" } + return np } diff --git a/route.go b/route.go index bf92af2..6f1ef38 100644 --- a/route.go +++ b/route.go @@ -23,9 +23,12 @@ type Route struct { matchers []matcher // Manager for the variables from host and path. regexp *routeRegexpGroup - // If true, when the path pattern is "/path/", accessing "/path" will - // redirect to the former and vice versa. - strictSlash bool + // If true, when the path pattern is "/path/", accessing "/path" will + // redirect to the former and vice versa. + strictSlash bool + // If true, when the path pattern is "/path//to", accessing "/path//to" + // will not redirect + skipClean bool // If true, this route never matches: it is only used to build URLs. buildOnly bool // The name used to build URLs.