Вы не можете выбрать более 25 тем Темы должны начинаться с буквы или цифры, могут содержать дефисы(-) и должны содержать не более 35 символов.

607 строки
17 KiB

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