gitee.com/ks-custle/core-gm@v0.0.0-20230922171213-b83bdd97b62c/mux/route.go (about)

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