Use vendored dependencies
[bloat] / vendor / github.com / gorilla / mux / mux.go
1 // Copyright 2012 The Gorilla Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style
3 // license that can be found in the LICENSE file.
4
5 package mux
6
7 import (
8         "errors"
9         "fmt"
10         "net/http"
11         "path"
12         "regexp"
13 )
14
15 var (
16         // ErrMethodMismatch is returned when the method in the request does not match
17         // the method defined against the route.
18         ErrMethodMismatch = errors.New("method is not allowed")
19         // ErrNotFound is returned when no route match is found.
20         ErrNotFound = errors.New("no matching route was found")
21 )
22
23 // NewRouter returns a new router instance.
24 func NewRouter() *Router {
25         return &Router{namedRoutes: make(map[string]*Route)}
26 }
27
28 // Router registers routes to be matched and dispatches a handler.
29 //
30 // It implements the http.Handler interface, so it can be registered to serve
31 // requests:
32 //
33 //     var router = mux.NewRouter()
34 //
35 //     func main() {
36 //         http.Handle("/", router)
37 //     }
38 //
39 // Or, for Google App Engine, register it in a init() function:
40 //
41 //     func init() {
42 //         http.Handle("/", router)
43 //     }
44 //
45 // This will send all incoming requests to the router.
46 type Router struct {
47         // Configurable Handler to be used when no route matches.
48         NotFoundHandler http.Handler
49
50         // Configurable Handler to be used when the request method does not match the route.
51         MethodNotAllowedHandler http.Handler
52
53         // Routes to be matched, in order.
54         routes []*Route
55
56         // Routes by name for URL building.
57         namedRoutes map[string]*Route
58
59         // If true, do not clear the request context after handling the request.
60         //
61         // Deprecated: No effect when go1.7+ is used, since the context is stored
62         // on the request itself.
63         KeepContext bool
64
65         // Slice of middlewares to be called after a match is found
66         middlewares []middleware
67
68         // configuration shared with `Route`
69         routeConf
70 }
71
72 // common route configuration shared between `Router` and `Route`
73 type routeConf struct {
74         // If true, "/path/foo%2Fbar/to" will match the path "/path/{var}/to"
75         useEncodedPath bool
76
77         // If true, when the path pattern is "/path/", accessing "/path" will
78         // redirect to the former and vice versa.
79         strictSlash bool
80
81         // If true, when the path pattern is "/path//to", accessing "/path//to"
82         // will not redirect
83         skipClean bool
84
85         // Manager for the variables from host and path.
86         regexp routeRegexpGroup
87
88         // List of matchers.
89         matchers []matcher
90
91         // The scheme used when building URLs.
92         buildScheme string
93
94         buildVarsFunc BuildVarsFunc
95 }
96
97 // returns an effective deep copy of `routeConf`
98 func copyRouteConf(r routeConf) routeConf {
99         c := r
100
101         if r.regexp.path != nil {
102                 c.regexp.path = copyRouteRegexp(r.regexp.path)
103         }
104
105         if r.regexp.host != nil {
106                 c.regexp.host = copyRouteRegexp(r.regexp.host)
107         }
108
109         c.regexp.queries = make([]*routeRegexp, 0, len(r.regexp.queries))
110         for _, q := range r.regexp.queries {
111                 c.regexp.queries = append(c.regexp.queries, copyRouteRegexp(q))
112         }
113
114         c.matchers = make([]matcher, 0, len(r.matchers))
115         for _, m := range r.matchers {
116                 c.matchers = append(c.matchers, m)
117         }
118
119         return c
120 }
121
122 func copyRouteRegexp(r *routeRegexp) *routeRegexp {
123         c := *r
124         return &c
125 }
126
127 // Match attempts to match the given request against the router's registered routes.
128 //
129 // If the request matches a route of this router or one of its subrouters the Route,
130 // Handler, and Vars fields of the the match argument are filled and this function
131 // returns true.
132 //
133 // If the request does not match any of this router's or its subrouters' routes
134 // then this function returns false. If available, a reason for the match failure
135 // will be filled in the match argument's MatchErr field. If the match failure type
136 // (eg: not found) has a registered handler, the handler is assigned to the Handler
137 // field of the match argument.
138 func (r *Router) Match(req *http.Request, match *RouteMatch) bool {
139         for _, route := range r.routes {
140                 if route.Match(req, match) {
141                         // Build middleware chain if no error was found
142                         if match.MatchErr == nil {
143                                 for i := len(r.middlewares) - 1; i >= 0; i-- {
144                                         match.Handler = r.middlewares[i].Middleware(match.Handler)
145                                 }
146                         }
147                         return true
148                 }
149         }
150
151         if match.MatchErr == ErrMethodMismatch {
152                 if r.MethodNotAllowedHandler != nil {
153                         match.Handler = r.MethodNotAllowedHandler
154                         return true
155                 }
156
157                 return false
158         }
159
160         // Closest match for a router (includes sub-routers)
161         if r.NotFoundHandler != nil {
162                 match.Handler = r.NotFoundHandler
163                 match.MatchErr = ErrNotFound
164                 return true
165         }
166
167         match.MatchErr = ErrNotFound
168         return false
169 }
170
171 // ServeHTTP dispatches the handler registered in the matched route.
172 //
173 // When there is a match, the route variables can be retrieved calling
174 // mux.Vars(request).
175 func (r *Router) ServeHTTP(w http.ResponseWriter, req *http.Request) {
176         if !r.skipClean {
177                 path := req.URL.Path
178                 if r.useEncodedPath {
179                         path = req.URL.EscapedPath()
180                 }
181                 // Clean path to canonical form and redirect.
182                 if p := cleanPath(path); p != path {
183
184                         // Added 3 lines (Philip Schlump) - It was dropping the query string and #whatever from query.
185                         // This matches with fix in go 1.2 r.c. 4 for same problem.  Go Issue:
186                         // http://code.google.com/p/go/issues/detail?id=5252
187                         url := *req.URL
188                         url.Path = p
189                         p = url.String()
190
191                         w.Header().Set("Location", p)
192                         w.WriteHeader(http.StatusMovedPermanently)
193                         return
194                 }
195         }
196         var match RouteMatch
197         var handler http.Handler
198         if r.Match(req, &match) {
199                 handler = match.Handler
200                 req = setVars(req, match.Vars)
201                 req = setCurrentRoute(req, match.Route)
202         }
203
204         if handler == nil && match.MatchErr == ErrMethodMismatch {
205                 handler = methodNotAllowedHandler()
206         }
207
208         if handler == nil {
209                 handler = http.NotFoundHandler()
210         }
211
212         handler.ServeHTTP(w, req)
213 }
214
215 // Get returns a route registered with the given name.
216 func (r *Router) Get(name string) *Route {
217         return r.namedRoutes[name]
218 }
219
220 // GetRoute returns a route registered with the given name. This method
221 // was renamed to Get() and remains here for backwards compatibility.
222 func (r *Router) GetRoute(name string) *Route {
223         return r.namedRoutes[name]
224 }
225
226 // StrictSlash defines the trailing slash behavior for new routes. The initial
227 // value is false.
228 //
229 // When true, if the route path is "/path/", accessing "/path" will perform a redirect
230 // to the former and vice versa. In other words, your application will always
231 // see the path as specified in the route.
232 //
233 // When false, if the route path is "/path", accessing "/path/" will not match
234 // this route and vice versa.
235 //
236 // The re-direct is a HTTP 301 (Moved Permanently). Note that when this is set for
237 // routes with a non-idempotent method (e.g. POST, PUT), the subsequent re-directed
238 // request will be made as a GET by most clients. Use middleware or client settings
239 // to modify this behaviour as needed.
240 //
241 // Special case: when a route sets a path prefix using the PathPrefix() method,
242 // strict slash is ignored for that route because the redirect behavior can't
243 // be determined from a prefix alone. However, any subrouters created from that
244 // route inherit the original StrictSlash setting.
245 func (r *Router) StrictSlash(value bool) *Router {
246         r.strictSlash = value
247         return r
248 }
249
250 // SkipClean defines the path cleaning behaviour for new routes. The initial
251 // value is false. Users should be careful about which routes are not cleaned
252 //
253 // When true, if the route path is "/path//to", it will remain with the double
254 // slash. This is helpful if you have a route like: /fetch/http://xkcd.com/534/
255 //
256 // When false, the path will be cleaned, so /fetch/http://xkcd.com/534/ will
257 // become /fetch/http/xkcd.com/534
258 func (r *Router) SkipClean(value bool) *Router {
259         r.skipClean = value
260         return r
261 }
262
263 // UseEncodedPath tells the router to match the encoded original path
264 // to the routes.
265 // For eg. "/path/foo%2Fbar/to" will match the path "/path/{var}/to".
266 //
267 // If not called, the router will match the unencoded path to the routes.
268 // For eg. "/path/foo%2Fbar/to" will match the path "/path/foo/bar/to"
269 func (r *Router) UseEncodedPath() *Router {
270         r.useEncodedPath = true
271         return r
272 }
273
274 // ----------------------------------------------------------------------------
275 // Route factories
276 // ----------------------------------------------------------------------------
277
278 // NewRoute registers an empty route.
279 func (r *Router) NewRoute() *Route {
280         // initialize a route with a copy of the parent router's configuration
281         route := &Route{routeConf: copyRouteConf(r.routeConf), namedRoutes: r.namedRoutes}
282         r.routes = append(r.routes, route)
283         return route
284 }
285
286 // Name registers a new route with a name.
287 // See Route.Name().
288 func (r *Router) Name(name string) *Route {
289         return r.NewRoute().Name(name)
290 }
291
292 // Handle registers a new route with a matcher for the URL path.
293 // See Route.Path() and Route.Handler().
294 func (r *Router) Handle(path string, handler http.Handler) *Route {
295         return r.NewRoute().Path(path).Handler(handler)
296 }
297
298 // HandleFunc registers a new route with a matcher for the URL path.
299 // See Route.Path() and Route.HandlerFunc().
300 func (r *Router) HandleFunc(path string, f func(http.ResponseWriter,
301         *http.Request)) *Route {
302         return r.NewRoute().Path(path).HandlerFunc(f)
303 }
304
305 // Headers registers a new route with a matcher for request header values.
306 // See Route.Headers().
307 func (r *Router) Headers(pairs ...string) *Route {
308         return r.NewRoute().Headers(pairs...)
309 }
310
311 // Host registers a new route with a matcher for the URL host.
312 // See Route.Host().
313 func (r *Router) Host(tpl string) *Route {
314         return r.NewRoute().Host(tpl)
315 }
316
317 // MatcherFunc registers a new route with a custom matcher function.
318 // See Route.MatcherFunc().
319 func (r *Router) MatcherFunc(f MatcherFunc) *Route {
320         return r.NewRoute().MatcherFunc(f)
321 }
322
323 // Methods registers a new route with a matcher for HTTP methods.
324 // See Route.Methods().
325 func (r *Router) Methods(methods ...string) *Route {
326         return r.NewRoute().Methods(methods...)
327 }
328
329 // Path registers a new route with a matcher for the URL path.
330 // See Route.Path().
331 func (r *Router) Path(tpl string) *Route {
332         return r.NewRoute().Path(tpl)
333 }
334
335 // PathPrefix registers a new route with a matcher for the URL path prefix.
336 // See Route.PathPrefix().
337 func (r *Router) PathPrefix(tpl string) *Route {
338         return r.NewRoute().PathPrefix(tpl)
339 }
340
341 // Queries registers a new route with a matcher for URL query values.
342 // See Route.Queries().
343 func (r *Router) Queries(pairs ...string) *Route {
344         return r.NewRoute().Queries(pairs...)
345 }
346
347 // Schemes registers a new route with a matcher for URL schemes.
348 // See Route.Schemes().
349 func (r *Router) Schemes(schemes ...string) *Route {
350         return r.NewRoute().Schemes(schemes...)
351 }
352
353 // BuildVarsFunc registers a new route with a custom function for modifying
354 // route variables before building a URL.
355 func (r *Router) BuildVarsFunc(f BuildVarsFunc) *Route {
356         return r.NewRoute().BuildVarsFunc(f)
357 }
358
359 // Walk walks the router and all its sub-routers, calling walkFn for each route
360 // in the tree. The routes are walked in the order they were added. Sub-routers
361 // are explored depth-first.
362 func (r *Router) Walk(walkFn WalkFunc) error {
363         return r.walk(walkFn, []*Route{})
364 }
365
366 // SkipRouter is used as a return value from WalkFuncs to indicate that the
367 // router that walk is about to descend down to should be skipped.
368 var SkipRouter = errors.New("skip this router")
369
370 // WalkFunc is the type of the function called for each route visited by Walk.
371 // At every invocation, it is given the current route, and the current router,
372 // and a list of ancestor routes that lead to the current route.
373 type WalkFunc func(route *Route, router *Router, ancestors []*Route) error
374
375 func (r *Router) walk(walkFn WalkFunc, ancestors []*Route) error {
376         for _, t := range r.routes {
377                 err := walkFn(t, r, ancestors)
378                 if err == SkipRouter {
379                         continue
380                 }
381                 if err != nil {
382                         return err
383                 }
384                 for _, sr := range t.matchers {
385                         if h, ok := sr.(*Router); ok {
386                                 ancestors = append(ancestors, t)
387                                 err := h.walk(walkFn, ancestors)
388                                 if err != nil {
389                                         return err
390                                 }
391                                 ancestors = ancestors[:len(ancestors)-1]
392                         }
393                 }
394                 if h, ok := t.handler.(*Router); ok {
395                         ancestors = append(ancestors, t)
396                         err := h.walk(walkFn, ancestors)
397                         if err != nil {
398                                 return err
399                         }
400                         ancestors = ancestors[:len(ancestors)-1]
401                 }
402         }
403         return nil
404 }
405
406 // ----------------------------------------------------------------------------
407 // Context
408 // ----------------------------------------------------------------------------
409
410 // RouteMatch stores information about a matched route.
411 type RouteMatch struct {
412         Route   *Route
413         Handler http.Handler
414         Vars    map[string]string
415
416         // MatchErr is set to appropriate matching error
417         // It is set to ErrMethodMismatch if there is a mismatch in
418         // the request method and route method
419         MatchErr error
420 }
421
422 type contextKey int
423
424 const (
425         varsKey contextKey = iota
426         routeKey
427 )
428
429 // Vars returns the route variables for the current request, if any.
430 func Vars(r *http.Request) map[string]string {
431         if rv := contextGet(r, varsKey); rv != nil {
432                 return rv.(map[string]string)
433         }
434         return nil
435 }
436
437 // CurrentRoute returns the matched route for the current request, if any.
438 // This only works when called inside the handler of the matched route
439 // because the matched route is stored in the request context which is cleared
440 // after the handler returns, unless the KeepContext option is set on the
441 // Router.
442 func CurrentRoute(r *http.Request) *Route {
443         if rv := contextGet(r, routeKey); rv != nil {
444                 return rv.(*Route)
445         }
446         return nil
447 }
448
449 func setVars(r *http.Request, val interface{}) *http.Request {
450         return contextSet(r, varsKey, val)
451 }
452
453 func setCurrentRoute(r *http.Request, val interface{}) *http.Request {
454         return contextSet(r, routeKey, val)
455 }
456
457 // ----------------------------------------------------------------------------
458 // Helpers
459 // ----------------------------------------------------------------------------
460
461 // cleanPath returns the canonical path for p, eliminating . and .. elements.
462 // Borrowed from the net/http package.
463 func cleanPath(p string) string {
464         if p == "" {
465                 return "/"
466         }
467         if p[0] != '/' {
468                 p = "/" + p
469         }
470         np := path.Clean(p)
471         // path.Clean removes trailing slash except for root;
472         // put the trailing slash back if necessary.
473         if p[len(p)-1] == '/' && np != "/" {
474                 np += "/"
475         }
476
477         return np
478 }
479
480 // uniqueVars returns an error if two slices contain duplicated strings.
481 func uniqueVars(s1, s2 []string) error {
482         for _, v1 := range s1 {
483                 for _, v2 := range s2 {
484                         if v1 == v2 {
485                                 return fmt.Errorf("mux: duplicated route variable %q", v2)
486                         }
487                 }
488         }
489         return nil
490 }
491
492 // checkPairs returns the count of strings passed in, and an error if
493 // the count is not an even number.
494 func checkPairs(pairs ...string) (int, error) {
495         length := len(pairs)
496         if length%2 != 0 {
497                 return length, fmt.Errorf(
498                         "mux: number of parameters must be multiple of 2, got %v", pairs)
499         }
500         return length, nil
501 }
502
503 // mapFromPairsToString converts variadic string parameters to a
504 // string to string map.
505 func mapFromPairsToString(pairs ...string) (map[string]string, error) {
506         length, err := checkPairs(pairs...)
507         if err != nil {
508                 return nil, err
509         }
510         m := make(map[string]string, length/2)
511         for i := 0; i < length; i += 2 {
512                 m[pairs[i]] = pairs[i+1]
513         }
514         return m, nil
515 }
516
517 // mapFromPairsToRegex converts variadic string parameters to a
518 // string to regex map.
519 func mapFromPairsToRegex(pairs ...string) (map[string]*regexp.Regexp, error) {
520         length, err := checkPairs(pairs...)
521         if err != nil {
522                 return nil, err
523         }
524         m := make(map[string]*regexp.Regexp, length/2)
525         for i := 0; i < length; i += 2 {
526                 regex, err := regexp.Compile(pairs[i+1])
527                 if err != nil {
528                         return nil, err
529                 }
530                 m[pairs[i]] = regex
531         }
532         return m, nil
533 }
534
535 // matchInArray returns true if the given string value is in the array.
536 func matchInArray(arr []string, value string) bool {
537         for _, v := range arr {
538                 if v == value {
539                         return true
540                 }
541         }
542         return false
543 }
544
545 // matchMapWithString returns true if the given key/value pairs exist in a given map.
546 func matchMapWithString(toCheck map[string]string, toMatch map[string][]string, canonicalKey bool) bool {
547         for k, v := range toCheck {
548                 // Check if key exists.
549                 if canonicalKey {
550                         k = http.CanonicalHeaderKey(k)
551                 }
552                 if values := toMatch[k]; values == nil {
553                         return false
554                 } else if v != "" {
555                         // If value was defined as an empty string we only check that the
556                         // key exists. Otherwise we also check for equality.
557                         valueExists := false
558                         for _, value := range values {
559                                 if v == value {
560                                         valueExists = true
561                                         break
562                                 }
563                         }
564                         if !valueExists {
565                                 return false
566                         }
567                 }
568         }
569         return true
570 }
571
572 // matchMapWithRegex returns true if the given key/value pairs exist in a given map compiled against
573 // the given regex
574 func matchMapWithRegex(toCheck map[string]*regexp.Regexp, toMatch map[string][]string, canonicalKey bool) bool {
575         for k, v := range toCheck {
576                 // Check if key exists.
577                 if canonicalKey {
578                         k = http.CanonicalHeaderKey(k)
579                 }
580                 if values := toMatch[k]; values == nil {
581                         return false
582                 } else if v != nil {
583                         // If value was defined as an empty string we only check that the
584                         // key exists. Otherwise we also check for equality.
585                         valueExists := false
586                         for _, value := range values {
587                                 if v.MatchString(value) {
588                                         valueExists = true
589                                         break
590                                 }
591                         }
592                         if !valueExists {
593                                 return false
594                         }
595                 }
596         }
597         return true
598 }
599
600 // methodNotAllowed replies to the request with an HTTP status code 405.
601 func methodNotAllowed(w http.ResponseWriter, r *http.Request) {
602         w.WriteHeader(http.StatusMethodNotAllowed)
603 }
604
605 // methodNotAllowedHandler returns a simple request handler
606 // that replies to each request with a status code 405.
607 func methodNotAllowedHandler() http.Handler { return http.HandlerFunc(methodNotAllowed) }