taldir

Directory service to resolve wallet mailboxes by messenger addresses
Log | Files | Refs | Submodules | README | LICENSE

route.go (22678B)


      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 	"net/url"
     12 	"regexp"
     13 	"strings"
     14 )
     15 
     16 // Route stores information to match a request and build URLs.
     17 type Route struct {
     18 	// Request handler for the route.
     19 	handler http.Handler
     20 	// If true, this route never matches: it is only used to build URLs.
     21 	buildOnly bool
     22 	// The name used to build URLs.
     23 	name string
     24 	// Error resulted from building a route.
     25 	err error
     26 
     27 	// "global" reference to all named routes
     28 	namedRoutes map[string]*Route
     29 
     30 	// config possibly passed in from `Router`
     31 	routeConf
     32 }
     33 
     34 // SkipClean reports whether path cleaning is enabled for this route via
     35 // Router.SkipClean.
     36 func (r *Route) SkipClean() bool {
     37 	return r.skipClean
     38 }
     39 
     40 // Match matches the route against the request.
     41 func (r *Route) Match(req *http.Request, match *RouteMatch) bool {
     42 	if r.buildOnly || r.err != nil {
     43 		return false
     44 	}
     45 
     46 	var matchErr error
     47 
     48 	// Match everything.
     49 	for _, m := range r.matchers {
     50 		if matched := m.Match(req, match); !matched {
     51 			if _, ok := m.(methodMatcher); ok {
     52 				matchErr = ErrMethodMismatch
     53 				continue
     54 			}
     55 
     56 			// Ignore ErrNotFound errors. These errors arise from match call
     57 			// to Subrouters.
     58 			//
     59 			// This prevents subsequent matching subrouters from failing to
     60 			// run middleware. If not ignored, the middleware would see a
     61 			// non-nil MatchErr and be skipped, even when there was a
     62 			// matching route.
     63 			if match.MatchErr == ErrNotFound {
     64 				match.MatchErr = nil
     65 			}
     66 
     67 			matchErr = nil // nolint:ineffassign
     68 			return false
     69 		} else {
     70 			// Multiple routes may share the same path but use different HTTP methods. For instance:
     71 			// Route 1: POST "/users/{id}".
     72 			// Route 2: GET "/users/{id}", parameters: "id": "[0-9]+".
     73 			//
     74 			// The router must handle these cases correctly. For a GET request to "/users/abc" with "id" as "-2",
     75 			// The router should return a "Not Found" error as no route fully matches this request.
     76 			if match.MatchErr == ErrMethodMismatch {
     77 				match.MatchErr = nil
     78 			}
     79 		}
     80 	}
     81 
     82 	if matchErr != nil {
     83 		match.MatchErr = matchErr
     84 		return false
     85 	}
     86 
     87 	if match.MatchErr == ErrMethodMismatch && r.handler != nil {
     88 		// We found a route which matches request method, clear MatchErr
     89 		match.MatchErr = nil
     90 		// Then override the mis-matched handler
     91 		match.Handler = r.handler
     92 	}
     93 
     94 	// Yay, we have a match. Let's collect some info about it.
     95 	if match.Route == nil {
     96 		match.Route = r
     97 	}
     98 	if match.Handler == nil {
     99 		match.Handler = r.handler
    100 	}
    101 	if match.Vars == nil {
    102 		match.Vars = make(map[string]string)
    103 	}
    104 
    105 	// Set variables.
    106 	r.regexp.setMatch(req, match, r)
    107 	return true
    108 }
    109 
    110 // ----------------------------------------------------------------------------
    111 // Route attributes
    112 // ----------------------------------------------------------------------------
    113 
    114 // GetError returns an error resulted from building the route, if any.
    115 func (r *Route) GetError() error {
    116 	return r.err
    117 }
    118 
    119 // BuildOnly sets the route to never match: it is only used to build URLs.
    120 func (r *Route) BuildOnly() *Route {
    121 	r.buildOnly = true
    122 	return r
    123 }
    124 
    125 // Handler --------------------------------------------------------------------
    126 
    127 // Handler sets a handler for the route.
    128 func (r *Route) Handler(handler http.Handler) *Route {
    129 	if r.err == nil {
    130 		r.handler = handler
    131 	}
    132 	return r
    133 }
    134 
    135 // HandlerFunc sets a handler function for the route.
    136 func (r *Route) HandlerFunc(f func(http.ResponseWriter, *http.Request)) *Route {
    137 	return r.Handler(http.HandlerFunc(f))
    138 }
    139 
    140 // GetHandler returns the handler for the route, if any.
    141 func (r *Route) GetHandler() http.Handler {
    142 	return r.handler
    143 }
    144 
    145 // Name -----------------------------------------------------------------------
    146 
    147 // Name sets the name for the route, used to build URLs.
    148 // It is an error to call Name more than once on a route.
    149 func (r *Route) Name(name string) *Route {
    150 	if r.name != "" {
    151 		r.err = fmt.Errorf("mux: route already has name %q, can't set %q",
    152 			r.name, name)
    153 	}
    154 	if r.err == nil {
    155 		r.name = name
    156 		r.namedRoutes[name] = r
    157 	}
    158 	return r
    159 }
    160 
    161 // GetName returns the name for the route, if any.
    162 func (r *Route) GetName() string {
    163 	return r.name
    164 }
    165 
    166 // ----------------------------------------------------------------------------
    167 // Matchers
    168 // ----------------------------------------------------------------------------
    169 
    170 // matcher types try to match a request.
    171 type matcher interface {
    172 	Match(*http.Request, *RouteMatch) bool
    173 }
    174 
    175 // addMatcher adds a matcher to the route.
    176 func (r *Route) addMatcher(m matcher) *Route {
    177 	if r.err == nil {
    178 		r.matchers = append(r.matchers, m)
    179 	}
    180 	return r
    181 }
    182 
    183 // addRegexpMatcher adds a host or path matcher and builder to a route.
    184 func (r *Route) addRegexpMatcher(tpl string, typ regexpType) error {
    185 	if r.err != nil {
    186 		return r.err
    187 	}
    188 	if typ == regexpTypePath || typ == regexpTypePrefix {
    189 		if len(tpl) > 0 && tpl[0] != '/' {
    190 			return fmt.Errorf("mux: path must start with a slash, got %q", tpl)
    191 		}
    192 		if r.regexp.path != nil {
    193 			tpl = strings.TrimRight(r.regexp.path.template, "/") + tpl
    194 		}
    195 	}
    196 	rr, err := newRouteRegexp(tpl, typ, routeRegexpOptions{
    197 		strictSlash:    r.strictSlash,
    198 		useEncodedPath: r.useEncodedPath,
    199 	})
    200 	if err != nil {
    201 		return err
    202 	}
    203 	for _, q := range r.regexp.queries {
    204 		if err = uniqueVars(rr.varsN, q.varsN); err != nil {
    205 			return err
    206 		}
    207 	}
    208 	if typ == regexpTypeHost {
    209 		if r.regexp.path != nil {
    210 			if err = uniqueVars(rr.varsN, r.regexp.path.varsN); err != nil {
    211 				return err
    212 			}
    213 		}
    214 		r.regexp.host = rr
    215 	} else {
    216 		if r.regexp.host != nil {
    217 			if err = uniqueVars(rr.varsN, r.regexp.host.varsN); err != nil {
    218 				return err
    219 			}
    220 		}
    221 		if typ == regexpTypeQuery {
    222 			r.regexp.queries = append(r.regexp.queries, rr)
    223 		} else {
    224 			r.regexp.path = rr
    225 		}
    226 	}
    227 	r.addMatcher(rr)
    228 	return nil
    229 }
    230 
    231 // Headers --------------------------------------------------------------------
    232 
    233 // headerMatcher matches the request against header values.
    234 type headerMatcher map[string]string
    235 
    236 func (m headerMatcher) Match(r *http.Request, match *RouteMatch) bool {
    237 	return matchMapWithString(m, r.Header, true)
    238 }
    239 
    240 // Headers adds a matcher for request header values.
    241 // It accepts a sequence of key/value pairs to be matched. For example:
    242 //
    243 //	r := mux.NewRouter().NewRoute()
    244 //	r.Headers("Content-Type", "application/json",
    245 //	          "X-Requested-With", "XMLHttpRequest")
    246 //
    247 // The above route will only match if both request header values match.
    248 // If the value is an empty string, it will match any value if the key is set.
    249 func (r *Route) Headers(pairs ...string) *Route {
    250 	if r.err == nil {
    251 		var headers map[string]string
    252 		headers, r.err = mapFromPairsToString(pairs...)
    253 		return r.addMatcher(headerMatcher(headers))
    254 	}
    255 	return r
    256 }
    257 
    258 // headerRegexMatcher matches the request against the route given a regex for the header
    259 type headerRegexMatcher map[string]*regexp.Regexp
    260 
    261 func (m headerRegexMatcher) Match(r *http.Request, match *RouteMatch) bool {
    262 	return matchMapWithRegex(m, r.Header, true)
    263 }
    264 
    265 // HeadersRegexp accepts a sequence of key/value pairs, where the value has regex
    266 // support. For example:
    267 //
    268 //	r := mux.NewRouter().NewRoute()
    269 //	r.HeadersRegexp("Content-Type", "application/(text|json)",
    270 //	          "X-Requested-With", "XMLHttpRequest")
    271 //
    272 // The above route will only match if both the request header matches both regular expressions.
    273 // If the value is an empty string, it will match any value if the key is set.
    274 // Use the start and end of string anchors (^ and $) to match an exact value.
    275 func (r *Route) HeadersRegexp(pairs ...string) *Route {
    276 	if r.err == nil {
    277 		var headers map[string]*regexp.Regexp
    278 		headers, r.err = mapFromPairsToRegex(pairs...)
    279 		return r.addMatcher(headerRegexMatcher(headers))
    280 	}
    281 	return r
    282 }
    283 
    284 // Host -----------------------------------------------------------------------
    285 
    286 // Host adds a matcher for the URL host.
    287 // It accepts a template with zero or more URL variables enclosed by {}.
    288 // Variables can define an optional regexp pattern to be matched:
    289 //
    290 // - {name} matches anything until the next dot.
    291 //
    292 // - {name:pattern} matches the given regexp pattern.
    293 //
    294 // For example:
    295 //
    296 //	r := mux.NewRouter().NewRoute()
    297 //	r.Host("www.example.com")
    298 //	r.Host("{subdomain}.domain.com")
    299 //	r.Host("{subdomain:[a-z]+}.domain.com")
    300 //
    301 // Variable names must be unique in a given route. They can be retrieved
    302 // calling mux.Vars(request).
    303 func (r *Route) Host(tpl string) *Route {
    304 	r.err = r.addRegexpMatcher(tpl, regexpTypeHost)
    305 	return r
    306 }
    307 
    308 // MatcherFunc ----------------------------------------------------------------
    309 
    310 // MatcherFunc is the function signature used by custom matchers.
    311 type MatcherFunc func(*http.Request, *RouteMatch) bool
    312 
    313 // Match returns the match for a given request.
    314 func (m MatcherFunc) Match(r *http.Request, match *RouteMatch) bool {
    315 	return m(r, match)
    316 }
    317 
    318 // MatcherFunc adds a custom function to be used as request matcher.
    319 func (r *Route) MatcherFunc(f MatcherFunc) *Route {
    320 	return r.addMatcher(f)
    321 }
    322 
    323 // Methods --------------------------------------------------------------------
    324 
    325 // methodMatcher matches the request against HTTP methods.
    326 type methodMatcher []string
    327 
    328 func (m methodMatcher) Match(r *http.Request, match *RouteMatch) bool {
    329 	return matchInArray(m, r.Method)
    330 }
    331 
    332 // Methods adds a matcher for HTTP methods.
    333 // It accepts a sequence of one or more methods to be matched, e.g.:
    334 // "GET", "POST", "PUT".
    335 func (r *Route) Methods(methods ...string) *Route {
    336 	for k, v := range methods {
    337 		methods[k] = strings.ToUpper(v)
    338 	}
    339 	return r.addMatcher(methodMatcher(methods))
    340 }
    341 
    342 // Path -----------------------------------------------------------------------
    343 
    344 // Path adds a matcher for the URL path.
    345 // It accepts a template with zero or more URL variables enclosed by {}. The
    346 // template must start with a "/".
    347 // Variables can define an optional regexp pattern to be matched:
    348 //
    349 // - {name} matches anything until the next slash.
    350 //
    351 // - {name:pattern} matches the given regexp pattern.
    352 //
    353 // For example:
    354 //
    355 //	r := mux.NewRouter().NewRoute()
    356 //	r.Path("/products/").Handler(ProductsHandler)
    357 //	r.Path("/products/{key}").Handler(ProductsHandler)
    358 //	r.Path("/articles/{category}/{id:[0-9]+}").
    359 //	  Handler(ArticleHandler)
    360 //
    361 // Variable names must be unique in a given route. They can be retrieved
    362 // calling mux.Vars(request).
    363 func (r *Route) Path(tpl string) *Route {
    364 	r.err = r.addRegexpMatcher(tpl, regexpTypePath)
    365 	return r
    366 }
    367 
    368 // PathPrefix -----------------------------------------------------------------
    369 
    370 // PathPrefix adds a matcher for the URL path prefix. This matches if the given
    371 // template is a prefix of the full URL path. See Route.Path() for details on
    372 // the tpl argument.
    373 //
    374 // Note that it does not treat slashes specially ("/foobar/" will be matched by
    375 // the prefix "/foo") so you may want to use a trailing slash here.
    376 //
    377 // Also note that the setting of Router.StrictSlash() has no effect on routes
    378 // with a PathPrefix matcher.
    379 func (r *Route) PathPrefix(tpl string) *Route {
    380 	r.err = r.addRegexpMatcher(tpl, regexpTypePrefix)
    381 	return r
    382 }
    383 
    384 // Query ----------------------------------------------------------------------
    385 
    386 // Queries adds a matcher for URL query values.
    387 // It accepts a sequence of key/value pairs. Values may define variables.
    388 // For example:
    389 //
    390 //	r := mux.NewRouter().NewRoute()
    391 //	r.Queries("foo", "bar", "id", "{id:[0-9]+}")
    392 //
    393 // The above route will only match if the URL contains the defined queries
    394 // values, e.g.: ?foo=bar&id=42.
    395 //
    396 // If the value is an empty string, it will match any value if the key is set.
    397 //
    398 // Variables can define an optional regexp pattern to be matched:
    399 //
    400 // - {name} matches anything until the next slash.
    401 //
    402 // - {name:pattern} matches the given regexp pattern.
    403 func (r *Route) Queries(pairs ...string) *Route {
    404 	length := len(pairs)
    405 	if length%2 != 0 {
    406 		r.err = fmt.Errorf(
    407 			"mux: number of parameters must be multiple of 2, got %v", pairs)
    408 		return nil
    409 	}
    410 	for i := 0; i < length; i += 2 {
    411 		if r.err = r.addRegexpMatcher(pairs[i]+"="+pairs[i+1], regexpTypeQuery); r.err != nil {
    412 			return r
    413 		}
    414 	}
    415 
    416 	return r
    417 }
    418 
    419 // Schemes --------------------------------------------------------------------
    420 
    421 // schemeMatcher matches the request against URL schemes.
    422 type schemeMatcher []string
    423 
    424 func (m schemeMatcher) Match(r *http.Request, match *RouteMatch) bool {
    425 	scheme := r.URL.Scheme
    426 	// https://golang.org/pkg/net/http/#Request
    427 	// "For [most] server requests, fields other than Path and RawQuery will be
    428 	// empty."
    429 	// Since we're an http muxer, the scheme is either going to be http or https
    430 	// though, so we can just set it based on the tls termination state.
    431 	if scheme == "" {
    432 		if r.TLS == nil {
    433 			scheme = "http"
    434 		} else {
    435 			scheme = "https"
    436 		}
    437 	}
    438 	return matchInArray(m, scheme)
    439 }
    440 
    441 // Schemes adds a matcher for URL schemes.
    442 // It accepts a sequence of schemes to be matched, e.g.: "http", "https".
    443 // If the request's URL has a scheme set, it will be matched against.
    444 // Generally, the URL scheme will only be set if a previous handler set it,
    445 // such as the ProxyHeaders handler from gorilla/handlers.
    446 // If unset, the scheme will be determined based on the request's TLS
    447 // termination state.
    448 // The first argument to Schemes will be used when constructing a route URL.
    449 func (r *Route) Schemes(schemes ...string) *Route {
    450 	for k, v := range schemes {
    451 		schemes[k] = strings.ToLower(v)
    452 	}
    453 	if len(schemes) > 0 {
    454 		r.buildScheme = schemes[0]
    455 	}
    456 	return r.addMatcher(schemeMatcher(schemes))
    457 }
    458 
    459 // BuildVarsFunc --------------------------------------------------------------
    460 
    461 // BuildVarsFunc is the function signature used by custom build variable
    462 // functions (which can modify route variables before a route's URL is built).
    463 type BuildVarsFunc func(map[string]string) map[string]string
    464 
    465 // BuildVarsFunc adds a custom function to be used to modify build variables
    466 // before a route's URL is built.
    467 func (r *Route) BuildVarsFunc(f BuildVarsFunc) *Route {
    468 	if r.buildVarsFunc != nil {
    469 		// compose the old and new functions
    470 		old := r.buildVarsFunc
    471 		r.buildVarsFunc = func(m map[string]string) map[string]string {
    472 			return f(old(m))
    473 		}
    474 	} else {
    475 		r.buildVarsFunc = f
    476 	}
    477 	return r
    478 }
    479 
    480 // Subrouter ------------------------------------------------------------------
    481 
    482 // Subrouter creates a subrouter for the route.
    483 //
    484 // It will test the inner routes only if the parent route matched. For example:
    485 //
    486 //	r := mux.NewRouter().NewRoute()
    487 //	s := r.Host("www.example.com").Subrouter()
    488 //	s.HandleFunc("/products/", ProductsHandler)
    489 //	s.HandleFunc("/products/{key}", ProductHandler)
    490 //	s.HandleFunc("/articles/{category}/{id:[0-9]+}"), ArticleHandler)
    491 //
    492 // Here, the routes registered in the subrouter won't be tested if the host
    493 // doesn't match.
    494 func (r *Route) Subrouter() *Router {
    495 	// initialize a subrouter with a copy of the parent route's configuration
    496 	router := &Router{routeConf: copyRouteConf(r.routeConf), namedRoutes: r.namedRoutes}
    497 	r.addMatcher(router)
    498 	return router
    499 }
    500 
    501 // ----------------------------------------------------------------------------
    502 // URL building
    503 // ----------------------------------------------------------------------------
    504 
    505 // URL builds a URL for the route.
    506 //
    507 // It accepts a sequence of key/value pairs for the route variables. For
    508 // example, given this route:
    509 //
    510 //	r := mux.NewRouter()
    511 //	r.HandleFunc("/articles/{category}/{id:[0-9]+}", ArticleHandler).
    512 //	  Name("article")
    513 //
    514 // ...a URL for it can be built using:
    515 //
    516 //	url, err := r.Get("article").URL("category", "technology", "id", "42")
    517 //
    518 // ...which will return an url.URL with the following path:
    519 //
    520 //	"/articles/technology/42"
    521 //
    522 // This also works for host variables:
    523 //
    524 //	r := mux.NewRouter()
    525 //	r.HandleFunc("/articles/{category}/{id:[0-9]+}", ArticleHandler).
    526 //	  Host("{subdomain}.domain.com").
    527 //	  Name("article")
    528 //
    529 //	// url.String() will be "http://news.domain.com/articles/technology/42"
    530 //	url, err := r.Get("article").URL("subdomain", "news",
    531 //	                                 "category", "technology",
    532 //	                                 "id", "42")
    533 //
    534 // The scheme of the resulting url will be the first argument that was passed to Schemes:
    535 //
    536 //	// url.String() will be "https://example.com"
    537 //	r := mux.NewRouter().NewRoute()
    538 //	url, err := r.Host("example.com")
    539 //	             .Schemes("https", "http").URL()
    540 //
    541 // All variables defined in the route are required, and their values must
    542 // conform to the corresponding patterns.
    543 func (r *Route) URL(pairs ...string) (*url.URL, error) {
    544 	if r.err != nil {
    545 		return nil, r.err
    546 	}
    547 	values, err := r.prepareVars(pairs...)
    548 	if err != nil {
    549 		return nil, err
    550 	}
    551 	var scheme, host, path string
    552 	queries := make([]string, 0, len(r.regexp.queries))
    553 	if r.regexp.host != nil {
    554 		if host, err = r.regexp.host.url(values); err != nil {
    555 			return nil, err
    556 		}
    557 		scheme = "http"
    558 		if r.buildScheme != "" {
    559 			scheme = r.buildScheme
    560 		}
    561 	}
    562 	if r.regexp.path != nil {
    563 		if path, err = r.regexp.path.url(values); err != nil {
    564 			return nil, err
    565 		}
    566 	}
    567 	for _, q := range r.regexp.queries {
    568 		var query string
    569 		if query, err = q.url(values); err != nil {
    570 			return nil, err
    571 		}
    572 		queries = append(queries, query)
    573 	}
    574 	return &url.URL{
    575 		Scheme:   scheme,
    576 		Host:     host,
    577 		Path:     path,
    578 		RawQuery: strings.Join(queries, "&"),
    579 	}, nil
    580 }
    581 
    582 // URLHost builds the host part of the URL for a route. See Route.URL().
    583 //
    584 // The route must have a host defined.
    585 func (r *Route) URLHost(pairs ...string) (*url.URL, error) {
    586 	if r.err != nil {
    587 		return nil, r.err
    588 	}
    589 	if r.regexp.host == nil {
    590 		return nil, errors.New("mux: route doesn't have a host")
    591 	}
    592 	values, err := r.prepareVars(pairs...)
    593 	if err != nil {
    594 		return nil, err
    595 	}
    596 	host, err := r.regexp.host.url(values)
    597 	if err != nil {
    598 		return nil, err
    599 	}
    600 	u := &url.URL{
    601 		Scheme: "http",
    602 		Host:   host,
    603 	}
    604 	if r.buildScheme != "" {
    605 		u.Scheme = r.buildScheme
    606 	}
    607 	return u, nil
    608 }
    609 
    610 // URLPath builds the path part of the URL for a route. See Route.URL().
    611 //
    612 // The route must have a path defined.
    613 func (r *Route) URLPath(pairs ...string) (*url.URL, error) {
    614 	if r.err != nil {
    615 		return nil, r.err
    616 	}
    617 	if r.regexp.path == nil {
    618 		return nil, errors.New("mux: route doesn't have a path")
    619 	}
    620 	values, err := r.prepareVars(pairs...)
    621 	if err != nil {
    622 		return nil, err
    623 	}
    624 	path, err := r.regexp.path.url(values)
    625 	if err != nil {
    626 		return nil, err
    627 	}
    628 	return &url.URL{
    629 		Path: path,
    630 	}, nil
    631 }
    632 
    633 // GetPathTemplate returns the template used to build the
    634 // route match.
    635 // This is useful for building simple REST API documentation and for instrumentation
    636 // against third-party services.
    637 // An error will be returned if the route does not define a path.
    638 func (r *Route) GetPathTemplate() (string, error) {
    639 	if r.err != nil {
    640 		return "", r.err
    641 	}
    642 	if r.regexp.path == nil {
    643 		return "", errors.New("mux: route doesn't have a path")
    644 	}
    645 	return r.regexp.path.template, nil
    646 }
    647 
    648 // GetPathRegexp returns the expanded regular expression used to match route path.
    649 // This is useful for building simple REST API documentation and for instrumentation
    650 // against third-party services.
    651 // An error will be returned if the route does not define a path.
    652 func (r *Route) GetPathRegexp() (string, error) {
    653 	if r.err != nil {
    654 		return "", r.err
    655 	}
    656 	if r.regexp.path == nil {
    657 		return "", errors.New("mux: route does not have a path")
    658 	}
    659 	return r.regexp.path.regexp.String(), nil
    660 }
    661 
    662 // GetQueriesRegexp returns the expanded regular expressions used to match the
    663 // route queries.
    664 // This is useful for building simple REST API documentation and for instrumentation
    665 // against third-party services.
    666 // An error will be returned if the route does not have queries.
    667 func (r *Route) GetQueriesRegexp() ([]string, error) {
    668 	if r.err != nil {
    669 		return nil, r.err
    670 	}
    671 	if r.regexp.queries == nil {
    672 		return nil, errors.New("mux: route doesn't have queries")
    673 	}
    674 	queries := make([]string, 0, len(r.regexp.queries))
    675 	for _, query := range r.regexp.queries {
    676 		queries = append(queries, query.regexp.String())
    677 	}
    678 	return queries, nil
    679 }
    680 
    681 // GetQueriesTemplates returns the templates used to build the
    682 // query matching.
    683 // This is useful for building simple REST API documentation and for instrumentation
    684 // against third-party services.
    685 // An error will be returned if the route does not define queries.
    686 func (r *Route) GetQueriesTemplates() ([]string, error) {
    687 	if r.err != nil {
    688 		return nil, r.err
    689 	}
    690 	if r.regexp.queries == nil {
    691 		return nil, errors.New("mux: route doesn't have queries")
    692 	}
    693 	queries := make([]string, 0, len(r.regexp.queries))
    694 	for _, query := range r.regexp.queries {
    695 		queries = append(queries, query.template)
    696 	}
    697 	return queries, nil
    698 }
    699 
    700 // GetMethods returns the methods the route matches against
    701 // This is useful for building simple REST API documentation and for instrumentation
    702 // against third-party services.
    703 // An error will be returned if route does not have methods.
    704 func (r *Route) GetMethods() ([]string, error) {
    705 	if r.err != nil {
    706 		return nil, r.err
    707 	}
    708 	for _, m := range r.matchers {
    709 		if methods, ok := m.(methodMatcher); ok {
    710 			return []string(methods), nil
    711 		}
    712 	}
    713 	return nil, errors.New("mux: route doesn't have methods")
    714 }
    715 
    716 // GetHostTemplate returns the template used to build the
    717 // route match.
    718 // This is useful for building simple REST API documentation and for instrumentation
    719 // against third-party services.
    720 // An error will be returned if the route does not define a host.
    721 func (r *Route) GetHostTemplate() (string, error) {
    722 	if r.err != nil {
    723 		return "", r.err
    724 	}
    725 	if r.regexp.host == nil {
    726 		return "", errors.New("mux: route doesn't have a host")
    727 	}
    728 	return r.regexp.host.template, nil
    729 }
    730 
    731 // GetVarNames returns the names of all variables added by regexp matchers
    732 // These can be used to know which route variables should be passed into r.URL()
    733 func (r *Route) GetVarNames() ([]string, error) {
    734 	if r.err != nil {
    735 		return nil, r.err
    736 	}
    737 	var varNames []string
    738 	if r.regexp.host != nil {
    739 		varNames = append(varNames, r.regexp.host.varsN...)
    740 	}
    741 	if r.regexp.path != nil {
    742 		varNames = append(varNames, r.regexp.path.varsN...)
    743 	}
    744 	for _, regx := range r.regexp.queries {
    745 		varNames = append(varNames, regx.varsN...)
    746 	}
    747 	return varNames, nil
    748 }
    749 
    750 // prepareVars converts the route variable pairs into a map. If the route has a
    751 // BuildVarsFunc, it is invoked.
    752 func (r *Route) prepareVars(pairs ...string) (map[string]string, error) {
    753 	m, err := mapFromPairsToString(pairs...)
    754 	if err != nil {
    755 		return nil, err
    756 	}
    757 	return r.buildVars(m), nil
    758 }
    759 
    760 func (r *Route) buildVars(m map[string]string) map[string]string {
    761 	if r.buildVarsFunc != nil {
    762 		m = r.buildVarsFunc(m)
    763 	}
    764 	return m
    765 }