jsr311.go 9.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298
  1. package restful
  2. // Copyright 2013 Ernest Micklei. All rights reserved.
  3. // Use of this source code is governed by a license
  4. // that can be found in the LICENSE file.
  5. import (
  6. "errors"
  7. "fmt"
  8. "net/http"
  9. "sort"
  10. )
  11. // RouterJSR311 implements the flow for matching Requests to Routes (and consequently Resource Functions)
  12. // as specified by the JSR311 http://jsr311.java.net/nonav/releases/1.1/spec/spec.html.
  13. // RouterJSR311 implements the Router interface.
  14. // Concept of locators is not implemented.
  15. type RouterJSR311 struct{}
  16. // SelectRoute is part of the Router interface and returns the best match
  17. // for the WebService and its Route for the given Request.
  18. func (r RouterJSR311) SelectRoute(
  19. webServices []*WebService,
  20. httpRequest *http.Request) (selectedService *WebService, selectedRoute *Route, err error) {
  21. // Identify the root resource class (WebService)
  22. dispatcher, finalMatch, err := r.detectDispatcher(httpRequest.URL.Path, webServices)
  23. if err != nil {
  24. return nil, nil, NewError(http.StatusNotFound, "")
  25. }
  26. // Obtain the set of candidate methods (Routes)
  27. routes := r.selectRoutes(dispatcher, finalMatch)
  28. if len(routes) == 0 {
  29. return dispatcher, nil, NewError(http.StatusNotFound, "404: Page Not Found")
  30. }
  31. // Identify the method (Route) that will handle the request
  32. route, ok := r.detectRoute(routes, httpRequest)
  33. return dispatcher, route, ok
  34. }
  35. // ExtractParameters is used to obtain the path parameters from the route using the same matching
  36. // engine as the JSR 311 router.
  37. func (r RouterJSR311) ExtractParameters(route *Route, webService *WebService, urlPath string) map[string]string {
  38. webServiceExpr := webService.pathExpr
  39. webServiceMatches := webServiceExpr.Matcher.FindStringSubmatch(urlPath)
  40. pathParameters := r.extractParams(webServiceExpr, webServiceMatches)
  41. routeExpr := route.pathExpr
  42. routeMatches := routeExpr.Matcher.FindStringSubmatch(webServiceMatches[len(webServiceMatches)-1])
  43. routeParams := r.extractParams(routeExpr, routeMatches)
  44. for key, value := range routeParams {
  45. pathParameters[key] = value
  46. }
  47. return pathParameters
  48. }
  49. func (RouterJSR311) extractParams(pathExpr *pathExpression, matches []string) map[string]string {
  50. params := map[string]string{}
  51. for i := 1; i < len(matches); i++ {
  52. if len(pathExpr.VarNames) >= i {
  53. params[pathExpr.VarNames[i-1]] = matches[i]
  54. }
  55. }
  56. return params
  57. }
  58. // http://jsr311.java.net/nonav/releases/1.1/spec/spec3.html#x3-360003.7.2
  59. func (r RouterJSR311) detectRoute(routes []Route, httpRequest *http.Request) (*Route, error) {
  60. candidates := make([]*Route, 0, 8)
  61. for i, each := range routes {
  62. ok := true
  63. for _, fn := range each.If {
  64. if !fn(httpRequest) {
  65. ok = false
  66. break
  67. }
  68. }
  69. if ok {
  70. candidates = append(candidates, &routes[i])
  71. }
  72. }
  73. if len(candidates) == 0 {
  74. if trace {
  75. traceLogger.Printf("no Route found (from %d) that passes conditional checks", len(routes))
  76. }
  77. return nil, NewError(http.StatusNotFound, "404: Not Found")
  78. }
  79. // http method
  80. previous := candidates
  81. candidates = candidates[:0]
  82. for _, each := range previous {
  83. if httpRequest.Method == each.Method {
  84. candidates = append(candidates, each)
  85. }
  86. }
  87. if len(candidates) == 0 {
  88. if trace {
  89. traceLogger.Printf("no Route found (in %d routes) that matches HTTP method %s\n", len(previous), httpRequest.Method)
  90. }
  91. return nil, NewError(http.StatusMethodNotAllowed, "405: Method Not Allowed")
  92. }
  93. // content-type
  94. contentType := httpRequest.Header.Get(HEADER_ContentType)
  95. previous = candidates
  96. candidates = candidates[:0]
  97. for _, each := range previous {
  98. if each.matchesContentType(contentType) {
  99. candidates = append(candidates, each)
  100. }
  101. }
  102. if len(candidates) == 0 {
  103. if trace {
  104. traceLogger.Printf("no Route found (from %d) that matches HTTP Content-Type: %s\n", len(previous), contentType)
  105. }
  106. if httpRequest.ContentLength > 0 {
  107. return nil, NewError(http.StatusUnsupportedMediaType, "415: Unsupported Media Type")
  108. }
  109. }
  110. // accept
  111. previous = candidates
  112. candidates = candidates[:0]
  113. accept := httpRequest.Header.Get(HEADER_Accept)
  114. if len(accept) == 0 {
  115. accept = "*/*"
  116. }
  117. for _, each := range previous {
  118. if each.matchesAccept(accept) {
  119. candidates = append(candidates, each)
  120. }
  121. }
  122. if len(candidates) == 0 {
  123. if trace {
  124. traceLogger.Printf("no Route found (from %d) that matches HTTP Accept: %s\n", len(previous), accept)
  125. }
  126. return nil, NewError(http.StatusNotAcceptable, "406: Not Acceptable")
  127. }
  128. // return r.bestMatchByMedia(outputMediaOk, contentType, accept), nil
  129. return candidates[0], nil
  130. }
  131. // http://jsr311.java.net/nonav/releases/1.1/spec/spec3.html#x3-360003.7.2
  132. // n/m > n/* > */*
  133. func (r RouterJSR311) bestMatchByMedia(routes []Route, contentType string, accept string) *Route {
  134. // TODO
  135. return &routes[0]
  136. }
  137. // http://jsr311.java.net/nonav/releases/1.1/spec/spec3.html#x3-360003.7.2 (step 2)
  138. func (r RouterJSR311) selectRoutes(dispatcher *WebService, pathRemainder string) []Route {
  139. filtered := &sortableRouteCandidates{}
  140. for _, each := range dispatcher.Routes() {
  141. pathExpr := each.pathExpr
  142. matches := pathExpr.Matcher.FindStringSubmatch(pathRemainder)
  143. if matches != nil {
  144. lastMatch := matches[len(matches)-1]
  145. if len(lastMatch) == 0 || lastMatch == "/" { // do not include if value is neither empty nor ‘/’.
  146. filtered.candidates = append(filtered.candidates,
  147. routeCandidate{each, len(matches) - 1, pathExpr.LiteralCount, pathExpr.VarCount})
  148. }
  149. }
  150. }
  151. if len(filtered.candidates) == 0 {
  152. if trace {
  153. traceLogger.Printf("WebService on path %s has no routes that match URL path remainder:%s\n", dispatcher.rootPath, pathRemainder)
  154. }
  155. return []Route{}
  156. }
  157. sort.Sort(sort.Reverse(filtered))
  158. // select other routes from candidates whoes expression matches rmatch
  159. matchingRoutes := []Route{filtered.candidates[0].route}
  160. for c := 1; c < len(filtered.candidates); c++ {
  161. each := filtered.candidates[c]
  162. if each.route.pathExpr.Matcher.MatchString(pathRemainder) {
  163. matchingRoutes = append(matchingRoutes, each.route)
  164. }
  165. }
  166. return matchingRoutes
  167. }
  168. // http://jsr311.java.net/nonav/releases/1.1/spec/spec3.html#x3-360003.7.2 (step 1)
  169. func (r RouterJSR311) detectDispatcher(requestPath string, dispatchers []*WebService) (*WebService, string, error) {
  170. filtered := &sortableDispatcherCandidates{}
  171. for _, each := range dispatchers {
  172. matches := each.pathExpr.Matcher.FindStringSubmatch(requestPath)
  173. if matches != nil {
  174. filtered.candidates = append(filtered.candidates,
  175. dispatcherCandidate{each, matches[len(matches)-1], len(matches), each.pathExpr.LiteralCount, each.pathExpr.VarCount})
  176. }
  177. }
  178. if len(filtered.candidates) == 0 {
  179. if trace {
  180. traceLogger.Printf("no WebService was found to match URL path:%s\n", requestPath)
  181. }
  182. return nil, "", errors.New("not found")
  183. }
  184. sort.Sort(sort.Reverse(filtered))
  185. return filtered.candidates[0].dispatcher, filtered.candidates[0].finalMatch, nil
  186. }
  187. // Types and functions to support the sorting of Routes
  188. type routeCandidate struct {
  189. route Route
  190. matchesCount int // the number of capturing groups
  191. literalCount int // the number of literal characters (means those not resulting from template variable substitution)
  192. nonDefaultCount int // the number of capturing groups with non-default regular expressions (i.e. not ‘([^ /]+?)’)
  193. }
  194. func (r routeCandidate) expressionToMatch() string {
  195. return r.route.pathExpr.Source
  196. }
  197. func (r routeCandidate) String() string {
  198. return fmt.Sprintf("(m=%d,l=%d,n=%d)", r.matchesCount, r.literalCount, r.nonDefaultCount)
  199. }
  200. type sortableRouteCandidates struct {
  201. candidates []routeCandidate
  202. }
  203. func (rcs *sortableRouteCandidates) Len() int {
  204. return len(rcs.candidates)
  205. }
  206. func (rcs *sortableRouteCandidates) Swap(i, j int) {
  207. rcs.candidates[i], rcs.candidates[j] = rcs.candidates[j], rcs.candidates[i]
  208. }
  209. func (rcs *sortableRouteCandidates) Less(i, j int) bool {
  210. ci := rcs.candidates[i]
  211. cj := rcs.candidates[j]
  212. // primary key
  213. if ci.literalCount < cj.literalCount {
  214. return true
  215. }
  216. if ci.literalCount > cj.literalCount {
  217. return false
  218. }
  219. // secundary key
  220. if ci.matchesCount < cj.matchesCount {
  221. return true
  222. }
  223. if ci.matchesCount > cj.matchesCount {
  224. return false
  225. }
  226. // tertiary key
  227. if ci.nonDefaultCount < cj.nonDefaultCount {
  228. return true
  229. }
  230. if ci.nonDefaultCount > cj.nonDefaultCount {
  231. return false
  232. }
  233. // quaternary key ("source" is interpreted as Path)
  234. return ci.route.Path < cj.route.Path
  235. }
  236. // Types and functions to support the sorting of Dispatchers
  237. type dispatcherCandidate struct {
  238. dispatcher *WebService
  239. finalMatch string
  240. matchesCount int // the number of capturing groups
  241. literalCount int // the number of literal characters (means those not resulting from template variable substitution)
  242. nonDefaultCount int // the number of capturing groups with non-default regular expressions (i.e. not ‘([^ /]+?)’)
  243. }
  244. type sortableDispatcherCandidates struct {
  245. candidates []dispatcherCandidate
  246. }
  247. func (dc *sortableDispatcherCandidates) Len() int {
  248. return len(dc.candidates)
  249. }
  250. func (dc *sortableDispatcherCandidates) Swap(i, j int) {
  251. dc.candidates[i], dc.candidates[j] = dc.candidates[j], dc.candidates[i]
  252. }
  253. func (dc *sortableDispatcherCandidates) Less(i, j int) bool {
  254. ci := dc.candidates[i]
  255. cj := dc.candidates[j]
  256. // primary key
  257. if ci.matchesCount < cj.matchesCount {
  258. return true
  259. }
  260. if ci.matchesCount > cj.matchesCount {
  261. return false
  262. }
  263. // secundary key
  264. if ci.literalCount < cj.literalCount {
  265. return true
  266. }
  267. if ci.literalCount > cj.literalCount {
  268. return false
  269. }
  270. // tertiary key
  271. return ci.nonDefaultCount < cj.nonDefaultCount
  272. }