Micro & pluggable web framework for Go
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

555 lines
13KB

  1. package tango
  2. import (
  3. "bytes"
  4. "fmt"
  5. "net/http"
  6. "reflect"
  7. "regexp"
  8. "sort"
  9. "strings"
  10. )
  11. // RouteType defines route types
  12. type RouteType byte
  13. // enumerates route types
  14. const (
  15. FuncRoute RouteType = iota + 1 // 1 func ()
  16. FuncHTTPRoute // 2 func (http.ResponseWriter, *http.Request)
  17. FuncReqRoute // 3 func (*http.Request)
  18. FuncResponseRoute // 4 func (http.ResponseWriter)
  19. FuncCtxRoute // 5 func (*tango.Context)
  20. StructRoute // 6 func (st) <Get>()
  21. StructPtrRoute // 7 func (*struct) <Get>()
  22. )
  23. // enumerates all supported HTTP methods
  24. var (
  25. SupportMethods = []string{
  26. "GET",
  27. "POST",
  28. "HEAD",
  29. "DELETE",
  30. "PUT",
  31. "OPTIONS",
  32. "TRACE",
  33. "PATCH",
  34. }
  35. PoolSize = 10
  36. )
  37. // Route defines HTTP route
  38. type Route struct {
  39. raw interface{}
  40. method reflect.Value
  41. handlers []Handler
  42. routeType RouteType
  43. pool *pool
  44. }
  45. // NewRoute returns a route
  46. func NewRoute(v interface{}, t reflect.Type,
  47. method reflect.Value, tp RouteType, handlers []Handler) *Route {
  48. var pool *pool
  49. if tp == StructRoute || tp == StructPtrRoute {
  50. pool = newPool(PoolSize, t)
  51. }
  52. return &Route{
  53. raw: v,
  54. routeType: tp,
  55. method: method,
  56. pool: pool,
  57. handlers: handlers,
  58. }
  59. }
  60. // Raw returns raw data to define route.
  61. func (r *Route) Raw() interface{} {
  62. return r.raw
  63. }
  64. // Method returns finalize execute method.
  65. func (r *Route) Method() reflect.Value {
  66. return r.method
  67. }
  68. // RouteType returns route type.
  69. func (r *Route) RouteType() RouteType {
  70. return r.routeType
  71. }
  72. // IsStruct returns if the execute is a struct
  73. func (r *Route) IsStruct() bool {
  74. return r.routeType == StructRoute || r.routeType == StructPtrRoute
  75. }
  76. func (r *Route) newAction() reflect.Value {
  77. if !r.IsStruct() {
  78. return r.method
  79. }
  80. return r.pool.New()
  81. }
  82. // Router describes the interface of route
  83. type Router interface {
  84. Route(methods interface{}, path string, handler interface{}, middlewares ...Handler)
  85. Match(requestPath, method string) (*Route, Params)
  86. }
  87. var specialBytes = []byte(`.\+*?|[]{}^$`)
  88. func isSpecial(ch byte) bool {
  89. return bytes.IndexByte(specialBytes, ch) > -1
  90. }
  91. func isAlpha(ch byte) bool {
  92. return 'a' <= ch && ch <= 'z' || 'A' <= ch && ch <= 'Z' || ch == '_'
  93. }
  94. func isDigit(ch byte) bool {
  95. return '0' <= ch && ch <= '9'
  96. }
  97. func isAlnum(ch byte) bool {
  98. return isAlpha(ch) || isDigit(ch)
  99. }
  100. type (
  101. router struct {
  102. trees map[string]*node
  103. }
  104. ntype byte
  105. node struct {
  106. tp ntype // Type of node it contains
  107. handle *Route // executor
  108. regexp *regexp.Regexp // regexp if tp is rnode
  109. content string // static content or named
  110. edges edges // children
  111. path string // executor path
  112. }
  113. edges []*node
  114. )
  115. func (e edges) Len() int { return len(e) }
  116. func (e edges) Swap(i, j int) { e[i], e[j] = e[j], e[i] }
  117. // static route will be put the first, so it will be match first.
  118. // two static route, content longer is first.
  119. func (e edges) Less(i, j int) bool {
  120. if e[i].tp == snode {
  121. if e[j].tp == snode {
  122. return len(e[i].content) > len(e[j].content)
  123. }
  124. return true
  125. }
  126. if e[j].tp == snode {
  127. return false
  128. }
  129. return i < j
  130. }
  131. const (
  132. snode ntype = iota // static, should equal
  133. nnode // named node, match a non-/ is ok
  134. anode // catch-all node, match any
  135. rnode // regex node, should match
  136. )
  137. func (n *node) equal(o *node) bool {
  138. if n.tp != o.tp || n.content != o.content {
  139. return false
  140. }
  141. return true
  142. }
  143. // newRouter return a new router
  144. func newRouter() (r *router) {
  145. r = &router{
  146. trees: make(map[string]*node),
  147. }
  148. for _, m := range SupportMethods {
  149. r.trees[m] = &node{
  150. edges: edges{},
  151. }
  152. }
  153. return
  154. }
  155. // /:name1/:name2 /:name1-:name2 /(:name1)sss(:name2)
  156. // /(*name) /(:name[0-9]+) /(:name[a-z]+)
  157. func parseNodes(path string) []*node {
  158. var i, j int
  159. l := len(path)
  160. var nodes = make([]*node, 0)
  161. var bracket int
  162. for ; i < l; i++ {
  163. if path[i] == ':' {
  164. nodes = append(nodes, &node{tp: snode, content: path[j : i-bracket]})
  165. j = i
  166. var regex string
  167. if bracket == 1 {
  168. var start = -1
  169. for ; i < l && ')' != path[i]; i++ {
  170. if start == -1 && isSpecial(path[i]) {
  171. start = i
  172. }
  173. }
  174. if path[i] != ')' {
  175. panic("lack of )")
  176. }
  177. if start > -1 {
  178. regex = path[start:i]
  179. }
  180. } else {
  181. i = i + 1
  182. for ; i < l && isAlnum(path[i]); i++ {
  183. }
  184. }
  185. if len(regex) > 0 {
  186. nodes = append(nodes, &node{tp: rnode,
  187. regexp: regexp.MustCompile("(" + regex + ")"),
  188. content: path[j : i-len(regex)]})
  189. } else {
  190. nodes = append(nodes, &node{tp: nnode, content: path[j:i]})
  191. }
  192. i = i + bracket
  193. j = i
  194. bracket = 0
  195. if i == l {
  196. return nodes
  197. }
  198. } else if path[i] == '*' {
  199. nodes = append(nodes, &node{tp: snode, content: path[j : i-bracket]})
  200. j = i
  201. if bracket == 1 {
  202. for ; i < l && ')' != path[i]; i++ {
  203. }
  204. } else {
  205. i = i + 1
  206. for ; i < l && isAlnum(path[i]); i++ {
  207. }
  208. }
  209. nodes = append(nodes, &node{tp: anode, content: path[j:i]})
  210. i = i + bracket
  211. bracket = 0
  212. j = i
  213. if i == l {
  214. return nodes
  215. }
  216. } else if path[i] == '(' {
  217. bracket = 1
  218. } else if path[i] == '/' {
  219. if bracket == 0 && i > j {
  220. nodes = append(nodes, &node{tp: snode, content: path[j:i]})
  221. j = i
  222. }
  223. } else {
  224. bracket = 0
  225. }
  226. }
  227. nodes = append(nodes, &node{
  228. tp: snode,
  229. content: path[j:i],
  230. })
  231. return nodes
  232. }
  233. func printNode(i int, node *node) {
  234. for _, c := range node.edges {
  235. for j := 0; j < i; j++ {
  236. fmt.Print(" ")
  237. }
  238. if i > 1 {
  239. fmt.Print("┗", " ")
  240. }
  241. fmt.Print(c.content)
  242. if c.handle != nil {
  243. fmt.Print(" ", c.handle.method.Type())
  244. fmt.Printf(" %p", c.handle.method.Interface())
  245. }
  246. fmt.Println()
  247. printNode(i+1, c)
  248. }
  249. }
  250. func (r *router) printTrees() {
  251. for _, method := range SupportMethods {
  252. if len(r.trees[method].edges) > 0 {
  253. fmt.Println(method)
  254. printNode(1, r.trees[method])
  255. fmt.Println()
  256. }
  257. }
  258. }
  259. func (r *router) addRoute(method, path string, h *Route) {
  260. nodes := parseNodes(path)
  261. nodes[len(nodes)-1].handle = h
  262. nodes[len(nodes)-1].path = path
  263. if !validNodes(nodes) {
  264. panic(fmt.Sprintln("express", path, "is not supported"))
  265. }
  266. r.addnodes(method, nodes)
  267. //r.printTrees()
  268. }
  269. func (r *router) matchNode(n *node, url string, params Params) (*node, Params) {
  270. if n.tp == snode {
  271. if strings.HasPrefix(url, n.content) {
  272. if len(url) == len(n.content) {
  273. return n, params
  274. }
  275. for _, c := range n.edges {
  276. e, newParams := r.matchNode(c, url[len(n.content):], params)
  277. if e != nil {
  278. return e, newParams
  279. }
  280. }
  281. }
  282. } else if n.tp == anode {
  283. for _, c := range n.edges {
  284. idx := strings.LastIndex(url, c.content)
  285. if idx > -1 {
  286. params = append(params, param{n.content, url[:idx]})
  287. return r.matchNode(c, url[idx:], params)
  288. }
  289. }
  290. return n, append(params, param{n.content, url})
  291. } else if n.tp == nnode {
  292. for _, c := range n.edges {
  293. idx := strings.Index(url, c.content)
  294. if idx > -1 {
  295. params = append(params, param{n.content, url[:idx]})
  296. return r.matchNode(c, url[idx:], params)
  297. }
  298. }
  299. idx := strings.IndexByte(url, '/')
  300. if idx < 0 {
  301. params = append(params, param{n.content, url})
  302. return n, params
  303. }
  304. } else if n.tp == rnode {
  305. idx := strings.IndexByte(url, '/')
  306. if idx > -1 {
  307. if n.regexp.MatchString(url[:idx]) {
  308. for _, c := range n.edges {
  309. h, newParams := r.matchNode(c, url[idx:], params)
  310. if h != nil {
  311. return h, append([]param{param{n.content, url[:idx]}}, newParams...)
  312. }
  313. }
  314. }
  315. return nil, params
  316. }
  317. for _, c := range n.edges {
  318. idx := strings.Index(url, c.content)
  319. if idx > -1 && n.regexp.MatchString(url[:idx]) {
  320. params = append(params, param{n.content, url[:idx]})
  321. return r.matchNode(c, url[idx:], params)
  322. }
  323. }
  324. if n.regexp.MatchString(url) {
  325. params = append(params, param{n.content, url})
  326. return n, params
  327. }
  328. }
  329. return nil, params
  330. }
  331. // Match for request url, match router
  332. func (r *router) Match(url, method string) (*Route, Params) {
  333. cn, ok := r.trees[method]
  334. if !ok {
  335. return nil, nil
  336. }
  337. var params = make(Params, 0, strings.Count(url, "/"))
  338. for _, n := range cn.edges {
  339. e, newParams := r.matchNode(n, url, params)
  340. if e != nil {
  341. return e.handle, newParams
  342. }
  343. }
  344. return nil, nil
  345. }
  346. // addnode adds node nodes[i] to parent node p
  347. func (r *router) addnode(p *node, nodes []*node, i int) *node {
  348. if len(p.edges) == 0 {
  349. p.edges = make([]*node, 0)
  350. }
  351. for _, pc := range p.edges {
  352. if pc.equal(nodes[i]) {
  353. if i == len(nodes)-1 {
  354. pc.handle = nodes[i].handle
  355. }
  356. return pc
  357. }
  358. }
  359. p.edges = append(p.edges, nodes[i])
  360. sort.Sort(p.edges)
  361. return nodes[i]
  362. }
  363. // validNodes validates parsed nodes, all non-static route should have static route children.
  364. func validNodes(nodes []*node) bool {
  365. if len(nodes) == 0 {
  366. return false
  367. }
  368. var lastTp = nodes[0]
  369. for _, node := range nodes[1:] {
  370. if lastTp.tp != snode && node.tp != snode {
  371. return false
  372. }
  373. lastTp = node
  374. }
  375. return true
  376. }
  377. // addnodes adds nodes to trees
  378. func (r *router) addnodes(method string, nodes []*node) {
  379. cn := r.trees[method]
  380. var p = cn
  381. for i := 0; i < len(nodes); i++ {
  382. p = r.addnode(p, nodes, i)
  383. }
  384. }
  385. func removeStick(uri string) string {
  386. uri = strings.TrimRight(uri, "/")
  387. if uri == "" {
  388. uri = "/"
  389. }
  390. return uri
  391. }
  392. // Route adds route
  393. func (r *router) Route(ms interface{}, url string, c interface{}, handlers ...Handler) {
  394. vc := reflect.ValueOf(c)
  395. if vc.Kind() == reflect.Func {
  396. switch ms.(type) {
  397. case string:
  398. s := strings.Split(ms.(string), ":")
  399. r.addFunc([]string{s[0]}, url, c, handlers)
  400. case []string:
  401. var newSlice []string
  402. for _, m := range ms.([]string) {
  403. s := strings.Split(m, ":")
  404. newSlice = append(newSlice, s[0])
  405. }
  406. r.addFunc(newSlice, url, c, handlers)
  407. default:
  408. panic("unknow methods format")
  409. }
  410. } else if vc.Kind() == reflect.Ptr && vc.Elem().Kind() == reflect.Struct {
  411. if handler, ok := vc.Interface().(http.Handler); ok {
  412. r.Route(ms, url, handler.ServeHTTP, handlers...)
  413. return
  414. }
  415. var methods = make(map[string]string)
  416. switch ms.(type) {
  417. case string:
  418. s := strings.Split(ms.(string), ":")
  419. if len(s) == 1 {
  420. methods[s[0]] = strings.Title(strings.ToLower(s[0]))
  421. } else if len(s) == 2 {
  422. methods[s[0]] = strings.TrimSpace(s[1])
  423. } else {
  424. panic("unknow methods format")
  425. }
  426. case []string:
  427. for _, m := range ms.([]string) {
  428. s := strings.Split(m, ":")
  429. if len(s) == 1 {
  430. methods[s[0]] = strings.Title(strings.ToLower(s[0]))
  431. } else if len(s) == 2 {
  432. methods[s[0]] = strings.TrimSpace(s[1])
  433. } else {
  434. panic("unknow format")
  435. }
  436. }
  437. case map[string]string:
  438. methods = ms.(map[string]string)
  439. default:
  440. panic("unsupported methods")
  441. }
  442. r.addStruct(methods, url, c, handlers)
  443. } else {
  444. panic("not support route type")
  445. }
  446. }
  447. /*
  448. Tango supports 5 form funcs
  449. func()
  450. func(*Context)
  451. func(http.ResponseWriter, *http.Request)
  452. func(http.ResponseWriter)
  453. func(*http.Request)
  454. it can has or has not return value
  455. */
  456. func (r *router) addFunc(methods []string, url string, c interface{}, handlers []Handler) {
  457. vc := reflect.ValueOf(c)
  458. t := vc.Type()
  459. var rt RouteType
  460. if t.NumIn() == 0 {
  461. rt = FuncRoute
  462. } else if t.NumIn() == 1 {
  463. if t.In(0) == reflect.TypeOf(new(Context)) {
  464. rt = FuncCtxRoute
  465. } else if t.In(0) == reflect.TypeOf(new(http.Request)) {
  466. rt = FuncReqRoute
  467. } else if t.In(0).Kind() == reflect.Interface && t.In(0).Name() == "ResponseWriter" &&
  468. t.In(0).PkgPath() == "net/http" {
  469. rt = FuncResponseRoute
  470. } else {
  471. panic(fmt.Sprintln("no support function type", methods, url, c))
  472. }
  473. } else if t.NumIn() == 2 &&
  474. (t.In(0).Kind() == reflect.Interface && t.In(0).Name() == "ResponseWriter" &&
  475. t.In(0).PkgPath() == "net/http") &&
  476. t.In(1) == reflect.TypeOf(new(http.Request)) {
  477. rt = FuncHTTPRoute
  478. } else {
  479. panic(fmt.Sprintln("no support function type", methods, url, c))
  480. }
  481. url = removeStick(url)
  482. for _, m := range methods {
  483. r.addRoute(m, url, NewRoute(c, t, vc, rt, handlers))
  484. }
  485. }
  486. func (r *router) addStruct(methods map[string]string, url string, c interface{}, handlers []Handler) {
  487. vc := reflect.ValueOf(c)
  488. t := vc.Type().Elem()
  489. // added a default method Get, Post
  490. for name, method := range methods {
  491. if m, ok := t.MethodByName(method); ok {
  492. r.addRoute(name, removeStick(url), NewRoute(c, t, m.Func, StructPtrRoute, handlers))
  493. } else if m, ok := vc.Type().MethodByName(method); ok {
  494. r.addRoute(name, removeStick(url), NewRoute(c, t, m.Func, StructRoute, handlers))
  495. } else if m, ok := t.MethodByName("Any"); ok {
  496. r.addRoute(name, removeStick(url), NewRoute(c, t, m.Func, StructPtrRoute, handlers))
  497. } else if m, ok := vc.Type().MethodByName("Any"); ok {
  498. r.addRoute(name, removeStick(url), NewRoute(c, t, m.Func, StructRoute, handlers))
  499. }
  500. }
  501. }