選択できるのは25トピックまでです。 トピックは、先頭が英数字で、英数字とダッシュ('-')を使用した35文字以内のものにしてください。

route.go 20 KiB

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