mux.go 13 KB

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