mux.go 17 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585
  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. "path"
  10. "regexp"
  11. )
  12. var (
  13. ErrMethodMismatch = errors.New("method is not allowed")
  14. ErrNotFound = errors.New("no matching route was found")
  15. )
  16. // NewRouter returns a new router instance.
  17. func NewRouter() *Router {
  18. return &Router{namedRoutes: make(map[string]*Route), KeepContext: false}
  19. }
  20. // Router registers routes to be matched and dispatches a handler.
  21. //
  22. // It implements the http.Handler interface, so it can be registered to serve
  23. // requests:
  24. //
  25. // var router = mux.NewRouter()
  26. //
  27. // func main() {
  28. // http.Handle("/", router)
  29. // }
  30. //
  31. // Or, for Google App Engine, register it in a init() function:
  32. //
  33. // func init() {
  34. // http.Handle("/", router)
  35. // }
  36. //
  37. // This will send all incoming requests to the router.
  38. type Router struct {
  39. // Configurable Handler to be used when no route matches.
  40. NotFoundHandler http.Handler
  41. // Configurable Handler to be used when the request method does not match the route.
  42. MethodNotAllowedHandler http.Handler
  43. // Parent route, if this is a subrouter.
  44. parent parentRoute
  45. // Routes to be matched, in order.
  46. routes []*Route
  47. // Routes by name for URL building.
  48. namedRoutes map[string]*Route
  49. // See Router.StrictSlash(). This defines the flag for new routes.
  50. strictSlash bool
  51. // See Router.SkipClean(). This defines the flag for new routes.
  52. skipClean bool
  53. // If true, do not clear the request context after handling the request.
  54. // This has no effect when go1.7+ is used, since the context is stored
  55. // on the request itself.
  56. KeepContext bool
  57. // see Router.UseEncodedPath(). This defines a flag for all routes.
  58. useEncodedPath bool
  59. // Slice of middlewares to be called after a match is found
  60. middlewares []middleware
  61. }
  62. // Match attempts to match the given request against the router's registered routes.
  63. //
  64. // If the request matches a route of this router or one of its subrouters the Route,
  65. // Handler, and Vars fields of the the match argument are filled and this function
  66. // returns true.
  67. //
  68. // If the request does not match any of this router's or its subrouters' routes
  69. // then this function returns false. If available, a reason for the match failure
  70. // will be filled in the match argument's MatchErr field. If the match failure type
  71. // (eg: not found) has a registered handler, the handler is assigned to the Handler
  72. // field of the match argument.
  73. func (r *Router) Match(req *http.Request, match *RouteMatch) bool {
  74. for _, route := range r.routes {
  75. if route.Match(req, match) {
  76. // Build middleware chain if no error was found
  77. if match.MatchErr == nil {
  78. for i := len(r.middlewares) - 1; i >= 0; i-- {
  79. match.Handler = r.middlewares[i].Middleware(match.Handler)
  80. }
  81. }
  82. return true
  83. }
  84. }
  85. if match.MatchErr == ErrMethodMismatch {
  86. if r.MethodNotAllowedHandler != nil {
  87. match.Handler = r.MethodNotAllowedHandler
  88. return true
  89. } else {
  90. return false
  91. }
  92. }
  93. // Closest match for a router (includes sub-routers)
  94. if r.NotFoundHandler != nil {
  95. match.Handler = r.NotFoundHandler
  96. match.MatchErr = ErrNotFound
  97. return true
  98. }
  99. match.MatchErr = ErrNotFound
  100. return false
  101. }
  102. // ServeHTTP dispatches the handler registered in the matched route.
  103. //
  104. // When there is a match, the route variables can be retrieved calling
  105. // mux.Vars(request).
  106. func (r *Router) ServeHTTP(w http.ResponseWriter, req *http.Request) {
  107. if !r.skipClean {
  108. path := req.URL.Path
  109. if r.useEncodedPath {
  110. path = req.URL.EscapedPath()
  111. }
  112. // Clean path to canonical form and redirect.
  113. if p := cleanPath(path); p != path {
  114. // Added 3 lines (Philip Schlump) - It was dropping the query string and #whatever from query.
  115. // This matches with fix in go 1.2 r.c. 4 for same problem. Go Issue:
  116. // http://code.google.com/p/go/issues/detail?id=5252
  117. url := *req.URL
  118. url.Path = p
  119. p = url.String()
  120. w.Header().Set("Location", p)
  121. w.WriteHeader(http.StatusMovedPermanently)
  122. return
  123. }
  124. }
  125. var match RouteMatch
  126. var handler http.Handler
  127. if r.Match(req, &match) {
  128. handler = match.Handler
  129. req = setVars(req, match.Vars)
  130. req = setCurrentRoute(req, match.Route)
  131. }
  132. if handler == nil && match.MatchErr == ErrMethodMismatch {
  133. handler = methodNotAllowedHandler()
  134. }
  135. if handler == nil {
  136. handler = http.NotFoundHandler()
  137. }
  138. if !r.KeepContext {
  139. defer contextClear(req)
  140. }
  141. handler.ServeHTTP(w, req)
  142. }
  143. // Get returns a route registered with the given name.
  144. func (r *Router) Get(name string) *Route {
  145. return r.getNamedRoutes()[name]
  146. }
  147. // GetRoute returns a route registered with the given name. This method
  148. // was renamed to Get() and remains here for backwards compatibility.
  149. func (r *Router) GetRoute(name string) *Route {
  150. return r.getNamedRoutes()[name]
  151. }
  152. // StrictSlash defines the trailing slash behavior for new routes. The initial
  153. // value is false.
  154. //
  155. // When true, if the route path is "/path/", accessing "/path" will perform a redirect
  156. // to the former and vice versa. In other words, your application will always
  157. // see the path as specified in the route.
  158. //
  159. // When false, if the route path is "/path", accessing "/path/" will not match
  160. // this route and vice versa.
  161. //
  162. // The re-direct is a HTTP 301 (Moved Permanently). Note that when this is set for
  163. // routes with a non-idempotent method (e.g. POST, PUT), the subsequent re-directed
  164. // request will be made as a GET by most clients. Use middleware or client settings
  165. // to modify this behaviour as needed.
  166. //
  167. // Special case: when a route sets a path prefix using the PathPrefix() method,
  168. // strict slash is ignored for that route because the redirect behavior can't
  169. // be determined from a prefix alone. However, any subrouters created from that
  170. // route inherit the original StrictSlash setting.
  171. func (r *Router) StrictSlash(value bool) *Router {
  172. r.strictSlash = value
  173. return r
  174. }
  175. // SkipClean defines the path cleaning behaviour for new routes. The initial
  176. // value is false. Users should be careful about which routes are not cleaned
  177. //
  178. // When true, if the route path is "/path//to", it will remain with the double
  179. // slash. This is helpful if you have a route like: /fetch/http://xkcd.com/534/
  180. //
  181. // When false, the path will be cleaned, so /fetch/http://xkcd.com/534/ will
  182. // become /fetch/http/xkcd.com/534
  183. func (r *Router) SkipClean(value bool) *Router {
  184. r.skipClean = value
  185. return r
  186. }
  187. // UseEncodedPath tells the router to match the encoded original path
  188. // to the routes.
  189. // For eg. "/path/foo%2Fbar/to" will match the path "/path/{var}/to".
  190. //
  191. // If not called, the router will match the unencoded path to the routes.
  192. // For eg. "/path/foo%2Fbar/to" will match the path "/path/foo/bar/to"
  193. func (r *Router) UseEncodedPath() *Router {
  194. r.useEncodedPath = true
  195. return r
  196. }
  197. // ----------------------------------------------------------------------------
  198. // parentRoute
  199. // ----------------------------------------------------------------------------
  200. func (r *Router) getBuildScheme() string {
  201. if r.parent != nil {
  202. return r.parent.getBuildScheme()
  203. }
  204. return ""
  205. }
  206. // getNamedRoutes returns the map where named routes are registered.
  207. func (r *Router) getNamedRoutes() map[string]*Route {
  208. if r.namedRoutes == nil {
  209. if r.parent != nil {
  210. r.namedRoutes = r.parent.getNamedRoutes()
  211. } else {
  212. r.namedRoutes = make(map[string]*Route)
  213. }
  214. }
  215. return r.namedRoutes
  216. }
  217. // getRegexpGroup returns regexp definitions from the parent route, if any.
  218. func (r *Router) getRegexpGroup() *routeRegexpGroup {
  219. if r.parent != nil {
  220. return r.parent.getRegexpGroup()
  221. }
  222. return nil
  223. }
  224. func (r *Router) buildVars(m map[string]string) map[string]string {
  225. if r.parent != nil {
  226. m = r.parent.buildVars(m)
  227. }
  228. return m
  229. }
  230. // ----------------------------------------------------------------------------
  231. // Route factories
  232. // ----------------------------------------------------------------------------
  233. // NewRoute registers an empty route.
  234. func (r *Router) NewRoute() *Route {
  235. route := &Route{parent: r, strictSlash: r.strictSlash, skipClean: r.skipClean, useEncodedPath: r.useEncodedPath}
  236. r.routes = append(r.routes, route)
  237. return route
  238. }
  239. // Handle registers a new route with a matcher for the URL path.
  240. // See Route.Path() and Route.Handler().
  241. func (r *Router) Handle(path string, handler http.Handler) *Route {
  242. return r.NewRoute().Path(path).Handler(handler)
  243. }
  244. // HandleFunc registers a new route with a matcher for the URL path.
  245. // See Route.Path() and Route.HandlerFunc().
  246. func (r *Router) HandleFunc(path string, f func(http.ResponseWriter,
  247. *http.Request)) *Route {
  248. return r.NewRoute().Path(path).HandlerFunc(f)
  249. }
  250. // Headers registers a new route with a matcher for request header values.
  251. // See Route.Headers().
  252. func (r *Router) Headers(pairs ...string) *Route {
  253. return r.NewRoute().Headers(pairs...)
  254. }
  255. // Host registers a new route with a matcher for the URL host.
  256. // See Route.Host().
  257. func (r *Router) Host(tpl string) *Route {
  258. return r.NewRoute().Host(tpl)
  259. }
  260. // MatcherFunc registers a new route with a custom matcher function.
  261. // See Route.MatcherFunc().
  262. func (r *Router) MatcherFunc(f MatcherFunc) *Route {
  263. return r.NewRoute().MatcherFunc(f)
  264. }
  265. // Methods registers a new route with a matcher for HTTP methods.
  266. // See Route.Methods().
  267. func (r *Router) Methods(methods ...string) *Route {
  268. return r.NewRoute().Methods(methods...)
  269. }
  270. // Path registers a new route with a matcher for the URL path.
  271. // See Route.Path().
  272. func (r *Router) Path(tpl string) *Route {
  273. return r.NewRoute().Path(tpl)
  274. }
  275. // PathPrefix registers a new route with a matcher for the URL path prefix.
  276. // See Route.PathPrefix().
  277. func (r *Router) PathPrefix(tpl string) *Route {
  278. return r.NewRoute().PathPrefix(tpl)
  279. }
  280. // Queries registers a new route with a matcher for URL query values.
  281. // See Route.Queries().
  282. func (r *Router) Queries(pairs ...string) *Route {
  283. return r.NewRoute().Queries(pairs...)
  284. }
  285. // Schemes registers a new route with a matcher for URL schemes.
  286. // See Route.Schemes().
  287. func (r *Router) Schemes(schemes ...string) *Route {
  288. return r.NewRoute().Schemes(schemes...)
  289. }
  290. // BuildVarsFunc registers a new route with a custom function for modifying
  291. // route variables before building a URL.
  292. func (r *Router) BuildVarsFunc(f BuildVarsFunc) *Route {
  293. return r.NewRoute().BuildVarsFunc(f)
  294. }
  295. // Walk walks the router and all its sub-routers, calling walkFn for each route
  296. // in the tree. The routes are walked in the order they were added. Sub-routers
  297. // are explored depth-first.
  298. func (r *Router) Walk(walkFn WalkFunc) error {
  299. return r.walk(walkFn, []*Route{})
  300. }
  301. // SkipRouter is used as a return value from WalkFuncs to indicate that the
  302. // router that walk is about to descend down to should be skipped.
  303. var SkipRouter = errors.New("skip this router")
  304. // WalkFunc is the type of the function called for each route visited by Walk.
  305. // At every invocation, it is given the current route, and the current router,
  306. // and a list of ancestor routes that lead to the current route.
  307. type WalkFunc func(route *Route, router *Router, ancestors []*Route) error
  308. func (r *Router) walk(walkFn WalkFunc, ancestors []*Route) error {
  309. for _, t := range r.routes {
  310. err := walkFn(t, r, ancestors)
  311. if err == SkipRouter {
  312. continue
  313. }
  314. if err != nil {
  315. return err
  316. }
  317. for _, sr := range t.matchers {
  318. if h, ok := sr.(*Router); ok {
  319. ancestors = append(ancestors, t)
  320. err := h.walk(walkFn, ancestors)
  321. if err != nil {
  322. return err
  323. }
  324. ancestors = ancestors[:len(ancestors)-1]
  325. }
  326. }
  327. if h, ok := t.handler.(*Router); ok {
  328. ancestors = append(ancestors, t)
  329. err := h.walk(walkFn, ancestors)
  330. if err != nil {
  331. return err
  332. }
  333. ancestors = ancestors[:len(ancestors)-1]
  334. }
  335. }
  336. return nil
  337. }
  338. // ----------------------------------------------------------------------------
  339. // Context
  340. // ----------------------------------------------------------------------------
  341. // RouteMatch stores information about a matched route.
  342. type RouteMatch struct {
  343. Route *Route
  344. Handler http.Handler
  345. Vars map[string]string
  346. // MatchErr is set to appropriate matching error
  347. // It is set to ErrMethodMismatch if there is a mismatch in
  348. // the request method and route method
  349. MatchErr error
  350. }
  351. type contextKey int
  352. const (
  353. varsKey contextKey = iota
  354. routeKey
  355. )
  356. // Vars returns the route variables for the current request, if any.
  357. func Vars(r *http.Request) map[string]string {
  358. if rv := contextGet(r, varsKey); rv != nil {
  359. return rv.(map[string]string)
  360. }
  361. return nil
  362. }
  363. // CurrentRoute returns the matched route for the current request, if any.
  364. // This only works when called inside the handler of the matched route
  365. // because the matched route is stored in the request context which is cleared
  366. // after the handler returns, unless the KeepContext option is set on the
  367. // Router.
  368. func CurrentRoute(r *http.Request) *Route {
  369. if rv := contextGet(r, routeKey); rv != nil {
  370. return rv.(*Route)
  371. }
  372. return nil
  373. }
  374. func setVars(r *http.Request, val interface{}) *http.Request {
  375. return contextSet(r, varsKey, val)
  376. }
  377. func setCurrentRoute(r *http.Request, val interface{}) *http.Request {
  378. return contextSet(r, routeKey, val)
  379. }
  380. // ----------------------------------------------------------------------------
  381. // Helpers
  382. // ----------------------------------------------------------------------------
  383. // cleanPath returns the canonical path for p, eliminating . and .. elements.
  384. // Borrowed from the net/http package.
  385. func cleanPath(p string) string {
  386. if p == "" {
  387. return "/"
  388. }
  389. if p[0] != '/' {
  390. p = "/" + p
  391. }
  392. np := path.Clean(p)
  393. // path.Clean removes trailing slash except for root;
  394. // put the trailing slash back if necessary.
  395. if p[len(p)-1] == '/' && np != "/" {
  396. np += "/"
  397. }
  398. return np
  399. }
  400. // uniqueVars returns an error if two slices contain duplicated strings.
  401. func uniqueVars(s1, s2 []string) error {
  402. for _, v1 := range s1 {
  403. for _, v2 := range s2 {
  404. if v1 == v2 {
  405. return fmt.Errorf("mux: duplicated route variable %q", v2)
  406. }
  407. }
  408. }
  409. return nil
  410. }
  411. // checkPairs returns the count of strings passed in, and an error if
  412. // the count is not an even number.
  413. func checkPairs(pairs ...string) (int, error) {
  414. length := len(pairs)
  415. if length%2 != 0 {
  416. return length, fmt.Errorf(
  417. "mux: number of parameters must be multiple of 2, got %v", pairs)
  418. }
  419. return length, nil
  420. }
  421. // mapFromPairsToString converts variadic string parameters to a
  422. // string to string map.
  423. func mapFromPairsToString(pairs ...string) (map[string]string, error) {
  424. length, err := checkPairs(pairs...)
  425. if err != nil {
  426. return nil, err
  427. }
  428. m := make(map[string]string, length/2)
  429. for i := 0; i < length; i += 2 {
  430. m[pairs[i]] = pairs[i+1]
  431. }
  432. return m, nil
  433. }
  434. // mapFromPairsToRegex converts variadic string parameters to a
  435. // string to regex map.
  436. func mapFromPairsToRegex(pairs ...string) (map[string]*regexp.Regexp, error) {
  437. length, err := checkPairs(pairs...)
  438. if err != nil {
  439. return nil, err
  440. }
  441. m := make(map[string]*regexp.Regexp, length/2)
  442. for i := 0; i < length; i += 2 {
  443. regex, err := regexp.Compile(pairs[i+1])
  444. if err != nil {
  445. return nil, err
  446. }
  447. m[pairs[i]] = regex
  448. }
  449. return m, nil
  450. }
  451. // matchInArray returns true if the given string value is in the array.
  452. func matchInArray(arr []string, value string) bool {
  453. for _, v := range arr {
  454. if v == value {
  455. return true
  456. }
  457. }
  458. return false
  459. }
  460. // matchMapWithString returns true if the given key/value pairs exist in a given map.
  461. func matchMapWithString(toCheck map[string]string, toMatch map[string][]string, canonicalKey bool) bool {
  462. for k, v := range toCheck {
  463. // Check if key exists.
  464. if canonicalKey {
  465. k = http.CanonicalHeaderKey(k)
  466. }
  467. if values := toMatch[k]; values == nil {
  468. return false
  469. } else if v != "" {
  470. // If value was defined as an empty string we only check that the
  471. // key exists. Otherwise we also check for equality.
  472. valueExists := false
  473. for _, value := range values {
  474. if v == value {
  475. valueExists = true
  476. break
  477. }
  478. }
  479. if !valueExists {
  480. return false
  481. }
  482. }
  483. }
  484. return true
  485. }
  486. // matchMapWithRegex returns true if the given key/value pairs exist in a given map compiled against
  487. // the given regex
  488. func matchMapWithRegex(toCheck map[string]*regexp.Regexp, toMatch map[string][]string, canonicalKey bool) bool {
  489. for k, v := range toCheck {
  490. // Check if key exists.
  491. if canonicalKey {
  492. k = http.CanonicalHeaderKey(k)
  493. }
  494. if values := toMatch[k]; values == nil {
  495. return false
  496. } else if v != nil {
  497. // If value was defined as an empty string we only check that the
  498. // key exists. Otherwise we also check for equality.
  499. valueExists := false
  500. for _, value := range values {
  501. if v.MatchString(value) {
  502. valueExists = true
  503. break
  504. }
  505. }
  506. if !valueExists {
  507. return false
  508. }
  509. }
  510. }
  511. return true
  512. }
  513. // methodNotAllowed replies to the request with an HTTP status code 405.
  514. func methodNotAllowed(w http.ResponseWriter, r *http.Request) {
  515. w.WriteHeader(http.StatusMethodNotAllowed)
  516. }
  517. // methodNotAllowedHandler returns a simple request handler
  518. // that replies to each request with a status code 405.
  519. func methodNotAllowedHandler() http.Handler { return http.HandlerFunc(methodNotAllowed) }