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

mux.go 17 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年前
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607
  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 is returned when the method in the request does not match
  14. // the method defined against the route.
  15. ErrMethodMismatch = errors.New("method is not allowed")
  16. // ErrNotFound is returned when no route match is found.
  17. ErrNotFound = errors.New("no matching route was found")
  18. )
  19. // NewRouter returns a new router instance.
  20. func NewRouter() *Router {
  21. return &Router{namedRoutes: make(map[string]*Route)}
  22. }
  23. // Router registers routes to be matched and dispatches a handler.
  24. //
  25. // It implements the http.Handler interface, so it can be registered to serve
  26. // requests:
  27. //
  28. // var router = mux.NewRouter()
  29. //
  30. // func main() {
  31. // http.Handle("/", router)
  32. // }
  33. //
  34. // Or, for Google App Engine, register it in a init() function:
  35. //
  36. // func init() {
  37. // http.Handle("/", router)
  38. // }
  39. //
  40. // This will send all incoming requests to the router.
  41. type Router struct {
  42. // Configurable Handler to be used when no route matches.
  43. NotFoundHandler http.Handler
  44. // Configurable Handler to be used when the request method does not match the route.
  45. MethodNotAllowedHandler http.Handler
  46. // Routes to be matched, in order.
  47. routes []*Route
  48. // Routes by name for URL building.
  49. namedRoutes map[string]*Route
  50. // If true, do not clear the request context after handling the request.
  51. //
  52. // Deprecated: No effect when go1.7+ is used, since the context is stored
  53. // on the request itself.
  54. KeepContext bool
  55. // Slice of middlewares to be called after a match is found
  56. middlewares []middleware
  57. // configuration shared with `Route`
  58. routeConf
  59. }
  60. // common route configuration shared between `Router` and `Route`
  61. type routeConf struct {
  62. // If true, "/path/foo%2Fbar/to" will match the path "/path/{var}/to"
  63. useEncodedPath bool
  64. // If true, when the path pattern is "/path/", accessing "/path" will
  65. // redirect to the former and vice versa.
  66. strictSlash bool
  67. // If true, when the path pattern is "/path//to", accessing "/path//to"
  68. // will not redirect
  69. skipClean bool
  70. // Manager for the variables from host and path.
  71. regexp routeRegexpGroup
  72. // List of matchers.
  73. matchers []matcher
  74. // The scheme used when building URLs.
  75. buildScheme string
  76. buildVarsFunc BuildVarsFunc
  77. }
  78. // returns an effective deep copy of `routeConf`
  79. func copyRouteConf(r routeConf) routeConf {
  80. c := r
  81. if r.regexp.path != nil {
  82. c.regexp.path = copyRouteRegexp(r.regexp.path)
  83. }
  84. if r.regexp.host != nil {
  85. c.regexp.host = copyRouteRegexp(r.regexp.host)
  86. }
  87. c.regexp.queries = make([]*routeRegexp, 0, len(r.regexp.queries))
  88. for _, q := range r.regexp.queries {
  89. c.regexp.queries = append(c.regexp.queries, copyRouteRegexp(q))
  90. }
  91. c.matchers = make([]matcher, 0, len(r.matchers))
  92. for _, m := range r.matchers {
  93. c.matchers = append(c.matchers, m)
  94. }
  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 = setVars(req, match.Vars)
  168. req = setCurrentRoute(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 := contextGet(r, 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, unless the KeepContext option is set on the
  375. // Router.
  376. func CurrentRoute(r *http.Request) *Route {
  377. if rv := contextGet(r, routeKey); rv != nil {
  378. return rv.(*Route)
  379. }
  380. return nil
  381. }
  382. func setVars(r *http.Request, val interface{}) *http.Request {
  383. return contextSet(r, varsKey, val)
  384. }
  385. func setCurrentRoute(r *http.Request, val interface{}) *http.Request {
  386. return contextSet(r, routeKey, val)
  387. }
  388. // ----------------------------------------------------------------------------
  389. // Helpers
  390. // ----------------------------------------------------------------------------
  391. // cleanPath returns the canonical path for p, eliminating . and .. elements.
  392. // Borrowed from the net/http package.
  393. func cleanPath(p string) string {
  394. if p == "" {
  395. return "/"
  396. }
  397. if p[0] != '/' {
  398. p = "/" + p
  399. }
  400. np := path.Clean(p)
  401. // path.Clean removes trailing slash except for root;
  402. // put the trailing slash back if necessary.
  403. if p[len(p)-1] == '/' && np != "/" {
  404. np += "/"
  405. }
  406. return np
  407. }
  408. // uniqueVars returns an error if two slices contain duplicated strings.
  409. func uniqueVars(s1, s2 []string) error {
  410. for _, v1 := range s1 {
  411. for _, v2 := range s2 {
  412. if v1 == v2 {
  413. return fmt.Errorf("mux: duplicated route variable %q", v2)
  414. }
  415. }
  416. }
  417. return nil
  418. }
  419. // checkPairs returns the count of strings passed in, and an error if
  420. // the count is not an even number.
  421. func checkPairs(pairs ...string) (int, error) {
  422. length := len(pairs)
  423. if length%2 != 0 {
  424. return length, fmt.Errorf(
  425. "mux: number of parameters must be multiple of 2, got %v", pairs)
  426. }
  427. return length, nil
  428. }
  429. // mapFromPairsToString converts variadic string parameters to a
  430. // string to string map.
  431. func mapFromPairsToString(pairs ...string) (map[string]string, error) {
  432. length, err := checkPairs(pairs...)
  433. if err != nil {
  434. return nil, err
  435. }
  436. m := make(map[string]string, length/2)
  437. for i := 0; i < length; i += 2 {
  438. m[pairs[i]] = pairs[i+1]
  439. }
  440. return m, nil
  441. }
  442. // mapFromPairsToRegex converts variadic string parameters to a
  443. // string to regex map.
  444. func mapFromPairsToRegex(pairs ...string) (map[string]*regexp.Regexp, error) {
  445. length, err := checkPairs(pairs...)
  446. if err != nil {
  447. return nil, err
  448. }
  449. m := make(map[string]*regexp.Regexp, length/2)
  450. for i := 0; i < length; i += 2 {
  451. regex, err := regexp.Compile(pairs[i+1])
  452. if err != nil {
  453. return nil, err
  454. }
  455. m[pairs[i]] = regex
  456. }
  457. return m, nil
  458. }
  459. // matchInArray returns true if the given string value is in the array.
  460. func matchInArray(arr []string, value string) bool {
  461. for _, v := range arr {
  462. if v == value {
  463. return true
  464. }
  465. }
  466. return false
  467. }
  468. // matchMapWithString returns true if the given key/value pairs exist in a given map.
  469. func matchMapWithString(toCheck map[string]string, toMatch map[string][]string, canonicalKey bool) bool {
  470. for k, v := range toCheck {
  471. // Check if key exists.
  472. if canonicalKey {
  473. k = http.CanonicalHeaderKey(k)
  474. }
  475. if values := toMatch[k]; values == nil {
  476. return false
  477. } else if v != "" {
  478. // If value was defined as an empty string we only check that the
  479. // key exists. Otherwise we also check for equality.
  480. valueExists := false
  481. for _, value := range values {
  482. if v == value {
  483. valueExists = true
  484. break
  485. }
  486. }
  487. if !valueExists {
  488. return false
  489. }
  490. }
  491. }
  492. return true
  493. }
  494. // matchMapWithRegex returns true if the given key/value pairs exist in a given map compiled against
  495. // the given regex
  496. func matchMapWithRegex(toCheck map[string]*regexp.Regexp, toMatch map[string][]string, canonicalKey bool) bool {
  497. for k, v := range toCheck {
  498. // Check if key exists.
  499. if canonicalKey {
  500. k = http.CanonicalHeaderKey(k)
  501. }
  502. if values := toMatch[k]; values == nil {
  503. return false
  504. } else if v != nil {
  505. // If value was defined as an empty string we only check that the
  506. // key exists. Otherwise we also check for equality.
  507. valueExists := false
  508. for _, value := range values {
  509. if v.MatchString(value) {
  510. valueExists = true
  511. break
  512. }
  513. }
  514. if !valueExists {
  515. return false
  516. }
  517. }
  518. }
  519. return true
  520. }
  521. // methodNotAllowed replies to the request with an HTTP status code 405.
  522. func methodNotAllowed(w http.ResponseWriter, r *http.Request) {
  523. w.WriteHeader(http.StatusMethodNotAllowed)
  524. }
  525. // methodNotAllowedHandler returns a simple request handler
  526. // that replies to each request with a status code 405.
  527. func methodNotAllowedHandler() http.Handler { return http.HandlerFunc(methodNotAllowed) }