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