router.go 10 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425
  1. package martini
  2. import (
  3. "fmt"
  4. "net/http"
  5. "reflect"
  6. "regexp"
  7. "strconv"
  8. "sync"
  9. )
  10. // Params is a map of name/value pairs for named routes. An instance of martini.Params is available to be injected into any route handler.
  11. type Params map[string]string
  12. // Router is Martini's de-facto routing interface. Supports HTTP verbs, stacked handlers, and dependency injection.
  13. type Router interface {
  14. Routes
  15. // Group adds a group where related routes can be added.
  16. Group(string, func(Router), ...Handler)
  17. // Get adds a route for a HTTP GET request to the specified matching pattern.
  18. Get(string, ...Handler) Route
  19. // Patch adds a route for a HTTP PATCH request to the specified matching pattern.
  20. Patch(string, ...Handler) Route
  21. // Post adds a route for a HTTP POST request to the specified matching pattern.
  22. Post(string, ...Handler) Route
  23. // Put adds a route for a HTTP PUT request to the specified matching pattern.
  24. Put(string, ...Handler) Route
  25. // Delete adds a route for a HTTP DELETE request to the specified matching pattern.
  26. Delete(string, ...Handler) Route
  27. // Options adds a route for a HTTP OPTIONS request to the specified matching pattern.
  28. Options(string, ...Handler) Route
  29. // Head adds a route for a HTTP HEAD request to the specified matching pattern.
  30. Head(string, ...Handler) Route
  31. // Any adds a route for any HTTP method request to the specified matching pattern.
  32. Any(string, ...Handler) Route
  33. // AddRoute adds a route for a given HTTP method request to the specified matching pattern.
  34. AddRoute(string, string, ...Handler) Route
  35. // NotFound sets the handlers that are called when a no route matches a request. Throws a basic 404 by default.
  36. NotFound(...Handler)
  37. // Handle is the entry point for routing. This is used as a martini.Handler
  38. Handle(http.ResponseWriter, *http.Request, Context)
  39. }
  40. type router struct {
  41. routes []*route
  42. notFounds []Handler
  43. groups []group
  44. routesLock sync.RWMutex
  45. }
  46. type group struct {
  47. pattern string
  48. handlers []Handler
  49. }
  50. // NewRouter creates a new Router instance.
  51. // If you aren't using ClassicMartini, then you can add Routes as a
  52. // service with:
  53. //
  54. // m := martini.New()
  55. // r := martini.NewRouter()
  56. // m.MapTo(r, (*martini.Routes)(nil))
  57. //
  58. // If you are using ClassicMartini, then this is done for you.
  59. func NewRouter() Router {
  60. return &router{notFounds: []Handler{http.NotFound}, groups: make([]group, 0)}
  61. }
  62. func (r *router) Group(pattern string, fn func(Router), h ...Handler) {
  63. r.groups = append(r.groups, group{pattern, h})
  64. fn(r)
  65. r.groups = r.groups[:len(r.groups)-1]
  66. }
  67. func (r *router) Get(pattern string, h ...Handler) Route {
  68. return r.addRoute("GET", pattern, h)
  69. }
  70. func (r *router) Patch(pattern string, h ...Handler) Route {
  71. return r.addRoute("PATCH", pattern, h)
  72. }
  73. func (r *router) Post(pattern string, h ...Handler) Route {
  74. return r.addRoute("POST", pattern, h)
  75. }
  76. func (r *router) Put(pattern string, h ...Handler) Route {
  77. return r.addRoute("PUT", pattern, h)
  78. }
  79. func (r *router) Delete(pattern string, h ...Handler) Route {
  80. return r.addRoute("DELETE", pattern, h)
  81. }
  82. func (r *router) Options(pattern string, h ...Handler) Route {
  83. return r.addRoute("OPTIONS", pattern, h)
  84. }
  85. func (r *router) Head(pattern string, h ...Handler) Route {
  86. return r.addRoute("HEAD", pattern, h)
  87. }
  88. func (r *router) Any(pattern string, h ...Handler) Route {
  89. return r.addRoute("*", pattern, h)
  90. }
  91. func (r *router) AddRoute(method, pattern string, h ...Handler) Route {
  92. return r.addRoute(method, pattern, h)
  93. }
  94. func (r *router) Handle(res http.ResponseWriter, req *http.Request, context Context) {
  95. bestMatch := NoMatch
  96. var bestVals map[string]string
  97. var bestRoute *route
  98. for _, route := range r.getRoutes() {
  99. match, vals := route.Match(req.Method, req.URL.Path)
  100. if match.BetterThan(bestMatch) {
  101. bestMatch = match
  102. bestVals = vals
  103. bestRoute = route
  104. if match == ExactMatch {
  105. break
  106. }
  107. }
  108. }
  109. if bestMatch != NoMatch {
  110. params := Params(bestVals)
  111. context.Map(params)
  112. bestRoute.Handle(context, res)
  113. return
  114. }
  115. // no routes exist, 404
  116. c := &routeContext{context, 0, r.notFounds}
  117. context.MapTo(c, (*Context)(nil))
  118. c.run()
  119. }
  120. func (r *router) NotFound(handler ...Handler) {
  121. r.notFounds = handler
  122. }
  123. func (r *router) addRoute(method string, pattern string, handlers []Handler) *route {
  124. if len(r.groups) > 0 {
  125. groupPattern := ""
  126. h := make([]Handler, 0)
  127. for _, g := range r.groups {
  128. groupPattern += g.pattern
  129. h = append(h, g.handlers...)
  130. }
  131. pattern = groupPattern + pattern
  132. h = append(h, handlers...)
  133. handlers = h
  134. }
  135. route := newRoute(method, pattern, handlers)
  136. route.Validate()
  137. r.appendRoute(route)
  138. return route
  139. }
  140. func (r *router) appendRoute(rt *route) {
  141. r.routesLock.Lock()
  142. defer r.routesLock.Unlock()
  143. r.routes = append(r.routes, rt)
  144. }
  145. func (r *router) getRoutes() []*route {
  146. r.routesLock.RLock()
  147. defer r.routesLock.RUnlock()
  148. return r.routes[:]
  149. }
  150. func (r *router) findRoute(name string) *route {
  151. for _, route := range r.getRoutes() {
  152. if route.name == name {
  153. return route
  154. }
  155. }
  156. return nil
  157. }
  158. // Route is an interface representing a Route in Martini's routing layer.
  159. type Route interface {
  160. // URLWith returns a rendering of the Route's url with the given string params.
  161. URLWith([]string) string
  162. // Name sets a name for the route.
  163. Name(string)
  164. // GetName returns the name of the route.
  165. GetName() string
  166. // Pattern returns the pattern of the route.
  167. Pattern() string
  168. // Method returns the method of the route.
  169. Method() string
  170. }
  171. type route struct {
  172. method string
  173. regex *regexp.Regexp
  174. handlers []Handler
  175. pattern string
  176. name string
  177. }
  178. var routeReg1 = regexp.MustCompile(`:[^/#?()\.\\]+`)
  179. var routeReg2 = regexp.MustCompile(`\*\*`)
  180. func newRoute(method string, pattern string, handlers []Handler) *route {
  181. route := route{method, nil, handlers, pattern, ""}
  182. pattern = routeReg1.ReplaceAllStringFunc(pattern, func(m string) string {
  183. return fmt.Sprintf(`(?P<%s>[^/#?]+)`, m[1:])
  184. })
  185. var index int
  186. pattern = routeReg2.ReplaceAllStringFunc(pattern, func(m string) string {
  187. index++
  188. return fmt.Sprintf(`(?P<_%d>[^#?]*)`, index)
  189. })
  190. pattern += `\/?`
  191. route.regex = regexp.MustCompile(pattern)
  192. return &route
  193. }
  194. type RouteMatch int
  195. const (
  196. NoMatch RouteMatch = iota
  197. StarMatch
  198. OverloadMatch
  199. ExactMatch
  200. )
  201. //Higher number = better match
  202. func (r RouteMatch) BetterThan(o RouteMatch) bool {
  203. return r > o
  204. }
  205. func (r route) MatchMethod(method string) RouteMatch {
  206. switch {
  207. case method == r.method:
  208. return ExactMatch
  209. case method == "HEAD" && r.method == "GET":
  210. return OverloadMatch
  211. case r.method == "*":
  212. return StarMatch
  213. default:
  214. return NoMatch
  215. }
  216. }
  217. func (r route) Match(method string, path string) (RouteMatch, map[string]string) {
  218. // add Any method matching support
  219. match := r.MatchMethod(method)
  220. if match == NoMatch {
  221. return match, nil
  222. }
  223. matches := r.regex.FindStringSubmatch(path)
  224. if len(matches) > 0 && matches[0] == path {
  225. params := make(map[string]string)
  226. for i, name := range r.regex.SubexpNames() {
  227. if len(name) > 0 {
  228. params[name] = matches[i]
  229. }
  230. }
  231. return match, params
  232. }
  233. return NoMatch, nil
  234. }
  235. func (r *route) Validate() {
  236. for _, handler := range r.handlers {
  237. validateHandler(handler)
  238. }
  239. }
  240. func (r *route) Handle(c Context, res http.ResponseWriter) {
  241. context := &routeContext{c, 0, r.handlers}
  242. c.MapTo(context, (*Context)(nil))
  243. c.MapTo(r, (*Route)(nil))
  244. context.run()
  245. }
  246. var urlReg = regexp.MustCompile(`:[^/#?()\.\\]+|\(\?P<[a-zA-Z0-9]+>.*\)`)
  247. // URLWith returns the url pattern replacing the parameters for its values
  248. func (r *route) URLWith(args []string) string {
  249. if len(args) > 0 {
  250. argCount := len(args)
  251. i := 0
  252. url := urlReg.ReplaceAllStringFunc(r.pattern, func(m string) string {
  253. var val interface{}
  254. if i < argCount {
  255. val = args[i]
  256. } else {
  257. val = m
  258. }
  259. i += 1
  260. return fmt.Sprintf(`%v`, val)
  261. })
  262. return url
  263. }
  264. return r.pattern
  265. }
  266. func (r *route) Name(name string) {
  267. r.name = name
  268. }
  269. func (r *route) GetName() string {
  270. return r.name
  271. }
  272. func (r *route) Pattern() string {
  273. return r.pattern
  274. }
  275. func (r *route) Method() string {
  276. return r.method
  277. }
  278. // Routes is a helper service for Martini's routing layer.
  279. type Routes interface {
  280. // URLFor returns a rendered URL for the given route. Optional params can be passed to fulfill named parameters in the route.
  281. URLFor(name string, params ...interface{}) string
  282. // MethodsFor returns an array of methods available for the path
  283. MethodsFor(path string) []string
  284. // All returns an array with all the routes in the router.
  285. All() []Route
  286. }
  287. // URLFor returns the url for the given route name.
  288. func (r *router) URLFor(name string, params ...interface{}) string {
  289. route := r.findRoute(name)
  290. if route == nil {
  291. panic("route not found")
  292. }
  293. var args []string
  294. for _, param := range params {
  295. switch v := param.(type) {
  296. case int:
  297. args = append(args, strconv.FormatInt(int64(v), 10))
  298. case string:
  299. args = append(args, v)
  300. default:
  301. if v != nil {
  302. panic("Arguments passed to URLFor must be integers or strings")
  303. }
  304. }
  305. }
  306. return route.URLWith(args)
  307. }
  308. func (r *router) All() []Route {
  309. routes := r.getRoutes()
  310. var ri = make([]Route, len(routes))
  311. for i, route := range routes {
  312. ri[i] = Route(route)
  313. }
  314. return ri
  315. }
  316. func hasMethod(methods []string, method string) bool {
  317. for _, v := range methods {
  318. if v == method {
  319. return true
  320. }
  321. }
  322. return false
  323. }
  324. // MethodsFor returns all methods available for path
  325. func (r *router) MethodsFor(path string) []string {
  326. methods := []string{}
  327. for _, route := range r.getRoutes() {
  328. matches := route.regex.FindStringSubmatch(path)
  329. if len(matches) > 0 && matches[0] == path && !hasMethod(methods, route.method) {
  330. methods = append(methods, route.method)
  331. }
  332. }
  333. return methods
  334. }
  335. type routeContext struct {
  336. Context
  337. index int
  338. handlers []Handler
  339. }
  340. func (r *routeContext) Next() {
  341. r.index += 1
  342. r.run()
  343. }
  344. func (r *routeContext) run() {
  345. for r.index < len(r.handlers) {
  346. handler := r.handlers[r.index]
  347. vals, err := r.Invoke(handler)
  348. if err != nil {
  349. panic(err)
  350. }
  351. r.index += 1
  352. // if the handler returned something, write it to the http response
  353. if len(vals) > 0 {
  354. ev := r.Get(reflect.TypeOf(ReturnHandler(nil)))
  355. handleReturn := ev.Interface().(ReturnHandler)
  356. handleReturn(r, vals)
  357. }
  358. if r.Written() {
  359. return
  360. }
  361. }
  362. }