mux.go 17 KB

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