taler-mailbox

Service for asynchronous wallet-to-wallet payment messages
Log | Files | Refs | Submodules | README | LICENSE

mux.go (17782B)


      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 	"context"
      9 	"errors"
     10 	"fmt"
     11 	"net/http"
     12 	"path"
     13 	"regexp"
     14 )
     15 
     16 var (
     17 	// ErrMethodMismatch is returned when the method in the request does not match
     18 	// the method defined against the route.
     19 	ErrMethodMismatch = errors.New("method is not allowed")
     20 	// ErrNotFound is returned when no route match is found.
     21 	ErrNotFound = errors.New("no matching route was found")
     22 )
     23 
     24 // NewRouter returns a new router instance.
     25 func NewRouter() *Router {
     26 	return &Router{namedRoutes: make(map[string]*Route)}
     27 }
     28 
     29 // Router registers routes to be matched and dispatches a handler.
     30 //
     31 // It implements the http.Handler interface, so it can be registered to serve
     32 // requests:
     33 //
     34 //	var router = mux.NewRouter()
     35 //
     36 //	func main() {
     37 //	    http.Handle("/", router)
     38 //	}
     39 //
     40 // Or, for Google App Engine, register it in a init() function:
     41 //
     42 //	func init() {
     43 //	    http.Handle("/", router)
     44 //	}
     45 //
     46 // This will send all incoming requests to the router.
     47 type Router struct {
     48 	// Configurable Handler to be used when no route matches.
     49 	// This can be used to render your own 404 Not Found errors.
     50 	NotFoundHandler http.Handler
     51 
     52 	// Configurable Handler to be used when the request method does not match the route.
     53 	// This can be used to render your own 405 Method Not Allowed errors.
     54 	MethodNotAllowedHandler http.Handler
     55 
     56 	// Routes to be matched, in order.
     57 	routes []*Route
     58 
     59 	// Routes by name for URL building.
     60 	namedRoutes map[string]*Route
     61 
     62 	// If true, do not clear the request context after handling the request.
     63 	//
     64 	// Deprecated: No effect, since the context is stored on the request itself.
     65 	KeepContext bool
     66 
     67 	// Slice of middlewares to be called after a match is found
     68 	middlewares []middleware
     69 
     70 	// configuration shared with `Route`
     71 	routeConf
     72 }
     73 
     74 // common route configuration shared between `Router` and `Route`
     75 type routeConf struct {
     76 	// If true, "/path/foo%2Fbar/to" will match the path "/path/{var}/to"
     77 	useEncodedPath bool
     78 
     79 	// If true, when the path pattern is "/path/", accessing "/path" will
     80 	// redirect to the former and vice versa.
     81 	strictSlash bool
     82 
     83 	// If true, when the path pattern is "/path//to", accessing "/path//to"
     84 	// will not redirect
     85 	skipClean bool
     86 
     87 	// Manager for the variables from host and path.
     88 	regexp routeRegexpGroup
     89 
     90 	// List of matchers.
     91 	matchers []matcher
     92 
     93 	// The scheme used when building URLs.
     94 	buildScheme string
     95 
     96 	buildVarsFunc BuildVarsFunc
     97 }
     98 
     99 // returns an effective deep copy of `routeConf`
    100 func copyRouteConf(r routeConf) routeConf {
    101 	c := r
    102 
    103 	if r.regexp.path != nil {
    104 		c.regexp.path = copyRouteRegexp(r.regexp.path)
    105 	}
    106 
    107 	if r.regexp.host != nil {
    108 		c.regexp.host = copyRouteRegexp(r.regexp.host)
    109 	}
    110 
    111 	c.regexp.queries = make([]*routeRegexp, 0, len(r.regexp.queries))
    112 	for _, q := range r.regexp.queries {
    113 		c.regexp.queries = append(c.regexp.queries, copyRouteRegexp(q))
    114 	}
    115 
    116 	c.matchers = make([]matcher, len(r.matchers))
    117 	copy(c.matchers, r.matchers)
    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 = requestWithVars(req, match.Vars)
    201 		req = requestWithRoute(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 := r.Context().Value(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.
    441 func CurrentRoute(r *http.Request) *Route {
    442 	if rv := r.Context().Value(routeKey); rv != nil {
    443 		return rv.(*Route)
    444 	}
    445 	return nil
    446 }
    447 
    448 func requestWithVars(r *http.Request, vars map[string]string) *http.Request {
    449 	ctx := context.WithValue(r.Context(), varsKey, vars)
    450 	return r.WithContext(ctx)
    451 }
    452 
    453 func requestWithRoute(r *http.Request, route *Route) *http.Request {
    454 	ctx := context.WithValue(r.Context(), routeKey, route)
    455 	return r.WithContext(ctx)
    456 }
    457 
    458 // ----------------------------------------------------------------------------
    459 // Helpers
    460 // ----------------------------------------------------------------------------
    461 
    462 // cleanPath returns the canonical path for p, eliminating . and .. elements.
    463 // Borrowed from the net/http package.
    464 func cleanPath(p string) string {
    465 	if p == "" {
    466 		return "/"
    467 	}
    468 	if p[0] != '/' {
    469 		p = "/" + p
    470 	}
    471 	np := path.Clean(p)
    472 	// path.Clean removes trailing slash except for root;
    473 	// put the trailing slash back if necessary.
    474 	if p[len(p)-1] == '/' && np != "/" {
    475 		np += "/"
    476 	}
    477 
    478 	return np
    479 }
    480 
    481 // uniqueVars returns an error if two slices contain duplicated strings.
    482 func uniqueVars(s1, s2 []string) error {
    483 	for _, v1 := range s1 {
    484 		for _, v2 := range s2 {
    485 			if v1 == v2 {
    486 				return fmt.Errorf("mux: duplicated route variable %q", v2)
    487 			}
    488 		}
    489 	}
    490 	return nil
    491 }
    492 
    493 // checkPairs returns the count of strings passed in, and an error if
    494 // the count is not an even number.
    495 func checkPairs(pairs ...string) (int, error) {
    496 	length := len(pairs)
    497 	if length%2 != 0 {
    498 		return length, fmt.Errorf(
    499 			"mux: number of parameters must be multiple of 2, got %v", pairs)
    500 	}
    501 	return length, nil
    502 }
    503 
    504 // mapFromPairsToString converts variadic string parameters to a
    505 // string to string map.
    506 func mapFromPairsToString(pairs ...string) (map[string]string, error) {
    507 	length, err := checkPairs(pairs...)
    508 	if err != nil {
    509 		return nil, err
    510 	}
    511 	m := make(map[string]string, length/2)
    512 	for i := 0; i < length; i += 2 {
    513 		m[pairs[i]] = pairs[i+1]
    514 	}
    515 	return m, nil
    516 }
    517 
    518 // mapFromPairsToRegex converts variadic string parameters to a
    519 // string to regex map.
    520 func mapFromPairsToRegex(pairs ...string) (map[string]*regexp.Regexp, error) {
    521 	length, err := checkPairs(pairs...)
    522 	if err != nil {
    523 		return nil, err
    524 	}
    525 	m := make(map[string]*regexp.Regexp, length/2)
    526 	for i := 0; i < length; i += 2 {
    527 		regex, err := regexp.Compile(pairs[i+1])
    528 		if err != nil {
    529 			return nil, err
    530 		}
    531 		m[pairs[i]] = regex
    532 	}
    533 	return m, nil
    534 }
    535 
    536 // matchInArray returns true if the given string value is in the array.
    537 func matchInArray(arr []string, value string) bool {
    538 	for _, v := range arr {
    539 		if v == value {
    540 			return true
    541 		}
    542 	}
    543 	return false
    544 }
    545 
    546 // matchMapWithString returns true if the given key/value pairs exist in a given map.
    547 func matchMapWithString(toCheck map[string]string, toMatch map[string][]string, canonicalKey bool) bool {
    548 	for k, v := range toCheck {
    549 		// Check if key exists.
    550 		if canonicalKey {
    551 			k = http.CanonicalHeaderKey(k)
    552 		}
    553 		if values := toMatch[k]; values == nil {
    554 			return false
    555 		} else if v != "" {
    556 			// If value was defined as an empty string we only check that the
    557 			// key exists. Otherwise we also check for equality.
    558 			valueExists := false
    559 			for _, value := range values {
    560 				if v == value {
    561 					valueExists = true
    562 					break
    563 				}
    564 			}
    565 			if !valueExists {
    566 				return false
    567 			}
    568 		}
    569 	}
    570 	return true
    571 }
    572 
    573 // matchMapWithRegex returns true if the given key/value pairs exist in a given map compiled against
    574 // the given regex
    575 func matchMapWithRegex(toCheck map[string]*regexp.Regexp, toMatch map[string][]string, canonicalKey bool) bool {
    576 	for k, v := range toCheck {
    577 		// Check if key exists.
    578 		if canonicalKey {
    579 			k = http.CanonicalHeaderKey(k)
    580 		}
    581 		if values := toMatch[k]; values == nil {
    582 			return false
    583 		} else if v != nil {
    584 			// If value was defined as an empty string we only check that the
    585 			// key exists. Otherwise we also check for equality.
    586 			valueExists := false
    587 			for _, value := range values {
    588 				if v.MatchString(value) {
    589 					valueExists = true
    590 					break
    591 				}
    592 			}
    593 			if !valueExists {
    594 				return false
    595 			}
    596 		}
    597 	}
    598 	return true
    599 }
    600 
    601 // methodNotAllowed replies to the request with an HTTP status code 405.
    602 func methodNotAllowed(w http.ResponseWriter, r *http.Request) {
    603 	w.WriteHeader(http.StatusMethodNotAllowed)
    604 }
    605 
    606 // methodNotAllowedHandler returns a simple request handler
    607 // that replies to each request with a status code 405.
    608 func methodNotAllowedHandler() http.Handler { return http.HandlerFunc(methodNotAllowed) }