]> git.immae.eu Git - github/fretlink/terraform-provider-statuscake.git/blame - vendor/github.com/fsouza/go-dockerclient/external/github.com/gorilla/mux/mux.go
provider: Ensured Go 1.11 in TravisCI and README
[github/fretlink/terraform-provider-statuscake.git] / vendor / github.com / fsouza / go-dockerclient / external / github.com / gorilla / mux / mux.go
CommitLineData
9b12e4fe
JC
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
5package mux
6
7import (
8 "errors"
9 "fmt"
10 "net/http"
11 "path"
12 "regexp"
13
14 "github.com/fsouza/go-dockerclient/external/github.com/gorilla/context"
15)
16
17// NewRouter returns a new router instance.
18func NewRouter() *Router {
19 return &Router{namedRoutes: make(map[string]*Route), KeepContext: false}
20}
21
22// Router registers routes to be matched and dispatches a handler.
23//
24// It implements the http.Handler interface, so it can be registered to serve
25// requests:
26//
27// var router = mux.NewRouter()
28//
29// func main() {
30// http.Handle("/", router)
31// }
32//
33// Or, for Google App Engine, register it in a init() function:
34//
35// func init() {
36// http.Handle("/", router)
37// }
38//
39// This will send all incoming requests to the router.
40type Router struct {
41 // Configurable Handler to be used when no route matches.
42 NotFoundHandler http.Handler
43 // Parent route, if this is a subrouter.
44 parent parentRoute
45 // Routes to be matched, in order.
46 routes []*Route
47 // Routes by name for URL building.
48 namedRoutes map[string]*Route
49 // See Router.StrictSlash(). This defines the flag for new routes.
50 strictSlash bool
51 // If true, do not clear the request context after handling the request
52 KeepContext bool
53}
54
55// Match matches registered routes against the request.
56func (r *Router) Match(req *http.Request, match *RouteMatch) bool {
57 for _, route := range r.routes {
58 if route.Match(req, match) {
59 return true
60 }
61 }
62
63 // Closest match for a router (includes sub-routers)
64 if r.NotFoundHandler != nil {
65 match.Handler = r.NotFoundHandler
66 return true
67 }
68 return false
69}
70
71// ServeHTTP dispatches the handler registered in the matched route.
72//
73// When there is a match, the route variables can be retrieved calling
74// mux.Vars(request).
75func (r *Router) ServeHTTP(w http.ResponseWriter, req *http.Request) {
76 // Clean path to canonical form and redirect.
77 if p := cleanPath(req.URL.Path); p != req.URL.Path {
78
79 // Added 3 lines (Philip Schlump) - It was dropping the query string and #whatever from query.
80 // This matches with fix in go 1.2 r.c. 4 for same problem. Go Issue:
81 // http://code.google.com/p/go/issues/detail?id=5252
82 url := *req.URL
83 url.Path = p
84 p = url.String()
85
86 w.Header().Set("Location", p)
87 w.WriteHeader(http.StatusMovedPermanently)
88 return
89 }
90 var match RouteMatch
91 var handler http.Handler
92 if r.Match(req, &match) {
93 handler = match.Handler
94 setVars(req, match.Vars)
95 setCurrentRoute(req, match.Route)
96 }
97 if handler == nil {
98 handler = http.NotFoundHandler()
99 }
100 if !r.KeepContext {
101 defer context.Clear(req)
102 }
103 handler.ServeHTTP(w, req)
104}
105
106// Get returns a route registered with the given name.
107func (r *Router) Get(name string) *Route {
108 return r.getNamedRoutes()[name]
109}
110
111// GetRoute returns a route registered with the given name. This method
112// was renamed to Get() and remains here for backwards compatibility.
113func (r *Router) GetRoute(name string) *Route {
114 return r.getNamedRoutes()[name]
115}
116
117// StrictSlash defines the trailing slash behavior for new routes. The initial
118// value is false.
119//
120// When true, if the route path is "/path/", accessing "/path" will redirect
121// to the former and vice versa. In other words, your application will always
122// see the path as specified in the route.
123//
124// When false, if the route path is "/path", accessing "/path/" will not match
125// this route and vice versa.
126//
127// Special case: when a route sets a path prefix using the PathPrefix() method,
128// strict slash is ignored for that route because the redirect behavior can't
129// be determined from a prefix alone. However, any subrouters created from that
130// route inherit the original StrictSlash setting.
131func (r *Router) StrictSlash(value bool) *Router {
132 r.strictSlash = value
133 return r
134}
135
136// ----------------------------------------------------------------------------
137// parentRoute
138// ----------------------------------------------------------------------------
139
140// getNamedRoutes returns the map where named routes are registered.
141func (r *Router) getNamedRoutes() map[string]*Route {
142 if r.namedRoutes == nil {
143 if r.parent != nil {
144 r.namedRoutes = r.parent.getNamedRoutes()
145 } else {
146 r.namedRoutes = make(map[string]*Route)
147 }
148 }
149 return r.namedRoutes
150}
151
152// getRegexpGroup returns regexp definitions from the parent route, if any.
153func (r *Router) getRegexpGroup() *routeRegexpGroup {
154 if r.parent != nil {
155 return r.parent.getRegexpGroup()
156 }
157 return nil
158}
159
160func (r *Router) buildVars(m map[string]string) map[string]string {
161 if r.parent != nil {
162 m = r.parent.buildVars(m)
163 }
164 return m
165}
166
167// ----------------------------------------------------------------------------
168// Route factories
169// ----------------------------------------------------------------------------
170
171// NewRoute registers an empty route.
172func (r *Router) NewRoute() *Route {
173 route := &Route{parent: r, strictSlash: r.strictSlash}
174 r.routes = append(r.routes, route)
175 return route
176}
177
178// Handle registers a new route with a matcher for the URL path.
179// See Route.Path() and Route.Handler().
180func (r *Router) Handle(path string, handler http.Handler) *Route {
181 return r.NewRoute().Path(path).Handler(handler)
182}
183
184// HandleFunc registers a new route with a matcher for the URL path.
185// See Route.Path() and Route.HandlerFunc().
186func (r *Router) HandleFunc(path string, f func(http.ResponseWriter,
187 *http.Request)) *Route {
188 return r.NewRoute().Path(path).HandlerFunc(f)
189}
190
191// Headers registers a new route with a matcher for request header values.
192// See Route.Headers().
193func (r *Router) Headers(pairs ...string) *Route {
194 return r.NewRoute().Headers(pairs...)
195}
196
197// Host registers a new route with a matcher for the URL host.
198// See Route.Host().
199func (r *Router) Host(tpl string) *Route {
200 return r.NewRoute().Host(tpl)
201}
202
203// MatcherFunc registers a new route with a custom matcher function.
204// See Route.MatcherFunc().
205func (r *Router) MatcherFunc(f MatcherFunc) *Route {
206 return r.NewRoute().MatcherFunc(f)
207}
208
209// Methods registers a new route with a matcher for HTTP methods.
210// See Route.Methods().
211func (r *Router) Methods(methods ...string) *Route {
212 return r.NewRoute().Methods(methods...)
213}
214
215// Path registers a new route with a matcher for the URL path.
216// See Route.Path().
217func (r *Router) Path(tpl string) *Route {
218 return r.NewRoute().Path(tpl)
219}
220
221// PathPrefix registers a new route with a matcher for the URL path prefix.
222// See Route.PathPrefix().
223func (r *Router) PathPrefix(tpl string) *Route {
224 return r.NewRoute().PathPrefix(tpl)
225}
226
227// Queries registers a new route with a matcher for URL query values.
228// See Route.Queries().
229func (r *Router) Queries(pairs ...string) *Route {
230 return r.NewRoute().Queries(pairs...)
231}
232
233// Schemes registers a new route with a matcher for URL schemes.
234// See Route.Schemes().
235func (r *Router) Schemes(schemes ...string) *Route {
236 return r.NewRoute().Schemes(schemes...)
237}
238
239// BuildVars registers a new route with a custom function for modifying
240// route variables before building a URL.
241func (r *Router) BuildVarsFunc(f BuildVarsFunc) *Route {
242 return r.NewRoute().BuildVarsFunc(f)
243}
244
245// Walk walks the router and all its sub-routers, calling walkFn for each route
246// in the tree. The routes are walked in the order they were added. Sub-routers
247// are explored depth-first.
248func (r *Router) Walk(walkFn WalkFunc) error {
249 return r.walk(walkFn, []*Route{})
250}
251
252// SkipRouter is used as a return value from WalkFuncs to indicate that the
253// router that walk is about to descend down to should be skipped.
254var SkipRouter = errors.New("skip this router")
255
256// WalkFunc is the type of the function called for each route visited by Walk.
257// At every invocation, it is given the current route, and the current router,
258// and a list of ancestor routes that lead to the current route.
259type WalkFunc func(route *Route, router *Router, ancestors []*Route) error
260
261func (r *Router) walk(walkFn WalkFunc, ancestors []*Route) error {
262 for _, t := range r.routes {
263 if t.regexp == nil || t.regexp.path == nil || t.regexp.path.template == "" {
264 continue
265 }
266
267 err := walkFn(t, r, ancestors)
268 if err == SkipRouter {
269 continue
270 }
271 for _, sr := range t.matchers {
272 if h, ok := sr.(*Router); ok {
273 err := h.walk(walkFn, ancestors)
274 if err != nil {
275 return err
276 }
277 }
278 }
279 if h, ok := t.handler.(*Router); ok {
280 ancestors = append(ancestors, t)
281 err := h.walk(walkFn, ancestors)
282 if err != nil {
283 return err
284 }
285 ancestors = ancestors[:len(ancestors)-1]
286 }
287 }
288 return nil
289}
290
291// ----------------------------------------------------------------------------
292// Context
293// ----------------------------------------------------------------------------
294
295// RouteMatch stores information about a matched route.
296type RouteMatch struct {
297 Route *Route
298 Handler http.Handler
299 Vars map[string]string
300}
301
302type contextKey int
303
304const (
305 varsKey contextKey = iota
306 routeKey
307)
308
309// Vars returns the route variables for the current request, if any.
310func Vars(r *http.Request) map[string]string {
311 if rv := context.Get(r, varsKey); rv != nil {
312 return rv.(map[string]string)
313 }
314 return nil
315}
316
317// CurrentRoute returns the matched route for the current request, if any.
318// This only works when called inside the handler of the matched route
319// because the matched route is stored in the request context which is cleared
320// after the handler returns, unless the KeepContext option is set on the
321// Router.
322func CurrentRoute(r *http.Request) *Route {
323 if rv := context.Get(r, routeKey); rv != nil {
324 return rv.(*Route)
325 }
326 return nil
327}
328
329func setVars(r *http.Request, val interface{}) {
330 if val != nil {
331 context.Set(r, varsKey, val)
332 }
333}
334
335func setCurrentRoute(r *http.Request, val interface{}) {
336 if val != nil {
337 context.Set(r, routeKey, val)
338 }
339}
340
341// ----------------------------------------------------------------------------
342// Helpers
343// ----------------------------------------------------------------------------
344
345// cleanPath returns the canonical path for p, eliminating . and .. elements.
346// Borrowed from the net/http package.
347func cleanPath(p string) string {
348 if p == "" {
349 return "/"
350 }
351 if p[0] != '/' {
352 p = "/" + p
353 }
354 np := path.Clean(p)
355 // path.Clean removes trailing slash except for root;
356 // put the trailing slash back if necessary.
357 if p[len(p)-1] == '/' && np != "/" {
358 np += "/"
359 }
360 return np
361}
362
363// uniqueVars returns an error if two slices contain duplicated strings.
364func uniqueVars(s1, s2 []string) error {
365 for _, v1 := range s1 {
366 for _, v2 := range s2 {
367 if v1 == v2 {
368 return fmt.Errorf("mux: duplicated route variable %q", v2)
369 }
370 }
371 }
372 return nil
373}
374
375// checkPairs returns the count of strings passed in, and an error if
376// the count is not an even number.
377func checkPairs(pairs ...string) (int, error) {
378 length := len(pairs)
379 if length%2 != 0 {
380 return length, fmt.Errorf(
381 "mux: number of parameters must be multiple of 2, got %v", pairs)
382 }
383 return length, nil
384}
385
386// mapFromPairsToString converts variadic string parameters to a
387// string to string map.
388func mapFromPairsToString(pairs ...string) (map[string]string, error) {
389 length, err := checkPairs(pairs...)
390 if err != nil {
391 return nil, err
392 }
393 m := make(map[string]string, length/2)
394 for i := 0; i < length; i += 2 {
395 m[pairs[i]] = pairs[i+1]
396 }
397 return m, nil
398}
399
400// mapFromPairsToRegex converts variadic string paramers to a
401// string to regex map.
402func mapFromPairsToRegex(pairs ...string) (map[string]*regexp.Regexp, error) {
403 length, err := checkPairs(pairs...)
404 if err != nil {
405 return nil, err
406 }
407 m := make(map[string]*regexp.Regexp, length/2)
408 for i := 0; i < length; i += 2 {
409 regex, err := regexp.Compile(pairs[i+1])
410 if err != nil {
411 return nil, err
412 }
413 m[pairs[i]] = regex
414 }
415 return m, nil
416}
417
418// matchInArray returns true if the given string value is in the array.
419func matchInArray(arr []string, value string) bool {
420 for _, v := range arr {
421 if v == value {
422 return true
423 }
424 }
425 return false
426}
427
428// matchMapWithString returns true if the given key/value pairs exist in a given map.
429func matchMapWithString(toCheck map[string]string, toMatch map[string][]string, canonicalKey bool) bool {
430 for k, v := range toCheck {
431 // Check if key exists.
432 if canonicalKey {
433 k = http.CanonicalHeaderKey(k)
434 }
435 if values := toMatch[k]; values == nil {
436 return false
437 } else if v != "" {
438 // If value was defined as an empty string we only check that the
439 // key exists. Otherwise we also check for equality.
440 valueExists := false
441 for _, value := range values {
442 if v == value {
443 valueExists = true
444 break
445 }
446 }
447 if !valueExists {
448 return false
449 }
450 }
451 }
452 return true
453}
454
455// matchMapWithRegex returns true if the given key/value pairs exist in a given map compiled against
456// the given regex
457func matchMapWithRegex(toCheck map[string]*regexp.Regexp, toMatch map[string][]string, canonicalKey bool) bool {
458 for k, v := range toCheck {
459 // Check if key exists.
460 if canonicalKey {
461 k = http.CanonicalHeaderKey(k)
462 }
463 if values := toMatch[k]; values == nil {
464 return false
465 } else if v != nil {
466 // If value was defined as an empty string we only check that the
467 // key exists. Otherwise we also check for equality.
468 valueExists := false
469 for _, value := range values {
470 if v.MatchString(value) {
471 valueExists = true
472 break
473 }
474 }
475 if !valueExists {
476 return false
477 }
478 }
479 }
480 return true
481}