tree.go 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548
  1. // Copyright 2013 Julien Schmidt. All rights reserved.
  2. // Use of this source code is governed by a BSD-style license that can be found
  3. // in the LICENSE file.
  4. package gin
  5. import (
  6. "strings"
  7. "unicode"
  8. )
  9. func min(a, b int) int {
  10. if a <= b {
  11. return a
  12. }
  13. return b
  14. }
  15. func countParams(path string) uint8 {
  16. var n uint
  17. for i := 0; i < len(path); i++ {
  18. if path[i] != ':' && path[i] != '*' {
  19. continue
  20. }
  21. n++
  22. }
  23. if n >= 255 {
  24. return 255
  25. }
  26. return uint8(n)
  27. }
  28. type nodeType uint8
  29. const (
  30. static nodeType = 0
  31. param nodeType = 1
  32. catchAll nodeType = 2
  33. )
  34. type node struct {
  35. path string
  36. wildChild bool
  37. nType nodeType
  38. maxParams uint8
  39. indices string
  40. children []*node
  41. handlers []HandlerFunc
  42. priority uint32
  43. }
  44. // increments priority of the given child and reorders if necessary
  45. func (n *node) incrementChildPrio(pos int) int {
  46. n.children[pos].priority++
  47. prio := n.children[pos].priority
  48. // adjust position (move to front)
  49. newPos := pos
  50. for newPos > 0 && n.children[newPos-1].priority < prio {
  51. // swap node positions
  52. tmpN := n.children[newPos-1]
  53. n.children[newPos-1] = n.children[newPos]
  54. n.children[newPos] = tmpN
  55. newPos--
  56. }
  57. // build new index char string
  58. if newPos != pos {
  59. n.indices = n.indices[:newPos] + // unchanged prefix, might be empty
  60. n.indices[pos:pos+1] + // the index char we move
  61. n.indices[newPos:pos] + n.indices[pos+1:] // rest without char at 'pos'
  62. }
  63. return newPos
  64. }
  65. // addRoute adds a node with the given handle to the path.
  66. // Not concurrency-safe!
  67. func (n *node) addRoute(path string, handlers []HandlerFunc) {
  68. n.priority++
  69. numParams := countParams(path)
  70. // non-empty tree
  71. if len(n.path) > 0 || len(n.children) > 0 {
  72. walk:
  73. for {
  74. // Update maxParams of the current node
  75. if numParams > n.maxParams {
  76. n.maxParams = numParams
  77. }
  78. // Find the longest common prefix.
  79. // This also implies that the common prefix contains no ':' or '*'
  80. // since the existing key can't contain those chars.
  81. i := 0
  82. max := min(len(path), len(n.path))
  83. for i < max && path[i] == n.path[i] {
  84. i++
  85. }
  86. // Split edge
  87. if i < len(n.path) {
  88. child := node{
  89. path: n.path[i:],
  90. wildChild: n.wildChild,
  91. indices: n.indices,
  92. children: n.children,
  93. handlers: n.handlers,
  94. priority: n.priority - 1,
  95. }
  96. // Update maxParams (max of all children)
  97. for i := range child.children {
  98. if child.children[i].maxParams > child.maxParams {
  99. child.maxParams = child.children[i].maxParams
  100. }
  101. }
  102. n.children = []*node{&child}
  103. // []byte for proper unicode char conversion, see #65
  104. n.indices = string([]byte{n.path[i]})
  105. n.path = path[:i]
  106. n.handlers = nil
  107. n.wildChild = false
  108. }
  109. // Make new node a child of this node
  110. if i < len(path) {
  111. path = path[i:]
  112. if n.wildChild {
  113. n = n.children[0]
  114. n.priority++
  115. // Update maxParams of the child node
  116. if numParams > n.maxParams {
  117. n.maxParams = numParams
  118. }
  119. numParams--
  120. // Check if the wildcard matches
  121. if len(path) >= len(n.path) && n.path == path[:len(n.path)] {
  122. // check for longer wildcard, e.g. :name and :names
  123. if len(n.path) >= len(path) || path[len(n.path)] == '/' {
  124. continue walk
  125. }
  126. }
  127. panic("conflict with wildcard route")
  128. }
  129. c := path[0]
  130. // slash after param
  131. if n.nType == param && c == '/' && len(n.children) == 1 {
  132. n = n.children[0]
  133. n.priority++
  134. continue walk
  135. }
  136. // Check if a child with the next path byte exists
  137. for i := 0; i < len(n.indices); i++ {
  138. if c == n.indices[i] {
  139. i = n.incrementChildPrio(i)
  140. n = n.children[i]
  141. continue walk
  142. }
  143. }
  144. // Otherwise insert it
  145. if c != ':' && c != '*' {
  146. // []byte for proper unicode char conversion, see #65
  147. n.indices += string([]byte{c})
  148. child := &node{
  149. maxParams: numParams,
  150. }
  151. n.children = append(n.children, child)
  152. n.incrementChildPrio(len(n.indices) - 1)
  153. n = child
  154. }
  155. n.insertChild(numParams, path, handlers)
  156. return
  157. } else if i == len(path) { // Make node a (in-path) leaf
  158. if n.handlers != nil {
  159. panic("a Handle is already registered for this path")
  160. }
  161. n.handlers = handlers
  162. }
  163. return
  164. }
  165. } else { // Empty tree
  166. n.insertChild(numParams, path, handlers)
  167. }
  168. }
  169. func (n *node) insertChild(numParams uint8, path string, handlers []HandlerFunc) {
  170. var offset int // already handled bytes of the path
  171. // find prefix until first wildcard (beginning with ':'' or '*'')
  172. for i, max := 0, len(path); numParams > 0; i++ {
  173. c := path[i]
  174. if c != ':' && c != '*' {
  175. continue
  176. }
  177. // check if this Node existing children which would be
  178. // unreachable if we insert the wildcard here
  179. if len(n.children) > 0 {
  180. panic("wildcard route conflicts with existing children")
  181. }
  182. // find wildcard end (either '/' or path end)
  183. end := i + 1
  184. for end < max && path[end] != '/' {
  185. switch path[end] {
  186. // the wildcard name must not contain ':' and '*'
  187. case ':', '*':
  188. panic("only one wildcard per path segment is allowed")
  189. default:
  190. end++
  191. }
  192. }
  193. // check if the wildcard has a name
  194. if end-i < 2 {
  195. panic("wildcards must be named with a non-empty name")
  196. }
  197. if c == ':' { // param
  198. // split path at the beginning of the wildcard
  199. if i > 0 {
  200. n.path = path[offset:i]
  201. offset = i
  202. }
  203. child := &node{
  204. nType: param,
  205. maxParams: numParams,
  206. }
  207. n.children = []*node{child}
  208. n.wildChild = true
  209. n = child
  210. n.priority++
  211. numParams--
  212. // if the path doesn't end with the wildcard, then there
  213. // will be another non-wildcard subpath starting with '/'
  214. if end < max {
  215. n.path = path[offset:end]
  216. offset = end
  217. child := &node{
  218. maxParams: numParams,
  219. priority: 1,
  220. }
  221. n.children = []*node{child}
  222. n = child
  223. }
  224. } else { // catchAll
  225. if end != max || numParams > 1 {
  226. panic("catch-all routes are only allowed at the end of the path")
  227. }
  228. if len(n.path) > 0 && n.path[len(n.path)-1] == '/' {
  229. panic("catch-all conflicts with existing handle for the path segment root")
  230. }
  231. // currently fixed width 1 for '/'
  232. i--
  233. if path[i] != '/' {
  234. panic("no / before catch-all")
  235. }
  236. n.path = path[offset:i]
  237. // first node: catchAll node with empty path
  238. child := &node{
  239. wildChild: true,
  240. nType: catchAll,
  241. maxParams: 1,
  242. }
  243. n.children = []*node{child}
  244. n.indices = string(path[i])
  245. n = child
  246. n.priority++
  247. // second node: node holding the variable
  248. child = &node{
  249. path: path[i:],
  250. nType: catchAll,
  251. maxParams: 1,
  252. handlers: handlers,
  253. priority: 1,
  254. }
  255. n.children = []*node{child}
  256. return
  257. }
  258. }
  259. // insert remaining path part and handle to the leaf
  260. n.path = path[offset:]
  261. n.handlers = handlers
  262. }
  263. // Returns the handle registered with the given path (key). The values of
  264. // wildcards are saved to a map.
  265. // If no handle can be found, a TSR (trailing slash redirect) recommendation is
  266. // made if a handle exists with an extra (without the) trailing slash for the
  267. // given path.
  268. func (n *node) getValue(path string, po Params) (handlers []HandlerFunc, p Params, tsr bool) {
  269. p = po
  270. walk: // Outer loop for walking the tree
  271. for {
  272. if len(path) > len(n.path) {
  273. if path[:len(n.path)] == n.path {
  274. path = path[len(n.path):]
  275. // If this node does not have a wildcard (param or catchAll)
  276. // child, we can just look up the next child node and continue
  277. // to walk down the tree
  278. if !n.wildChild {
  279. c := path[0]
  280. for i := 0; i < len(n.indices); i++ {
  281. if c == n.indices[i] {
  282. n = n.children[i]
  283. continue walk
  284. }
  285. }
  286. // Nothing found.
  287. // We can recommend to redirect to the same URL without a
  288. // trailing slash if a leaf exists for that path.
  289. tsr = (path == "/" && n.handlers != nil)
  290. return
  291. }
  292. // handle wildcard child
  293. n = n.children[0]
  294. switch n.nType {
  295. case param:
  296. // find param end (either '/' or path end)
  297. end := 0
  298. for end < len(path) && path[end] != '/' {
  299. end++
  300. }
  301. // save param value
  302. if cap(p) < int(n.maxParams) {
  303. p = make(Params, 0, n.maxParams)
  304. }
  305. i := len(p)
  306. p = p[:i+1] // expand slice within preallocated capacity
  307. p[i].Key = n.path[1:]
  308. p[i].Value = path[:end]
  309. // we need to go deeper!
  310. if end < len(path) {
  311. if len(n.children) > 0 {
  312. path = path[end:]
  313. n = n.children[0]
  314. continue walk
  315. }
  316. // ... but we can't
  317. tsr = (len(path) == end+1)
  318. return
  319. }
  320. if handlers = n.handlers; handlers != nil {
  321. return
  322. } else if len(n.children) == 1 {
  323. // No handle found. Check if a handle for this path + a
  324. // trailing slash exists for TSR recommendation
  325. n = n.children[0]
  326. tsr = (n.path == "/" && n.handlers != nil)
  327. }
  328. return
  329. case catchAll:
  330. // save param value
  331. if cap(p) < int(n.maxParams) {
  332. p = make(Params, 0, n.maxParams)
  333. }
  334. i := len(p)
  335. p = p[:i+1] // expand slice within preallocated capacity
  336. p[i].Key = n.path[2:]
  337. p[i].Value = path
  338. handlers = n.handlers
  339. return
  340. default:
  341. panic("Invalid node type")
  342. }
  343. }
  344. } else if path == n.path {
  345. // We should have reached the node containing the handle.
  346. // Check if this node has a handle registered.
  347. if handlers = n.handlers; handlers != nil {
  348. return
  349. }
  350. // No handle found. Check if a handle for this path + a
  351. // trailing slash exists for trailing slash recommendation
  352. for i := 0; i < len(n.indices); i++ {
  353. if n.indices[i] == '/' {
  354. n = n.children[i]
  355. tsr = (len(n.path) == 1 && n.handlers != nil) ||
  356. (n.nType == catchAll && n.children[0].handlers != nil)
  357. return
  358. }
  359. }
  360. return
  361. }
  362. // Nothing found. We can recommend to redirect to the same URL with an
  363. // extra trailing slash if a leaf exists for that path
  364. tsr = (path == "/") ||
  365. (len(n.path) == len(path)+1 && n.path[len(path)] == '/' &&
  366. path == n.path[:len(n.path)-1] && n.handlers != nil)
  367. return
  368. }
  369. }
  370. // Makes a case-insensitive lookup of the given path and tries to find a handler.
  371. // It can optionally also fix trailing slashes.
  372. // It returns the case-corrected path and a bool indicating whether the lookup
  373. // was successful.
  374. func (n *node) findCaseInsensitivePath(path string, fixTrailingSlash bool) (ciPath []byte, found bool) {
  375. ciPath = make([]byte, 0, len(path)+1) // preallocate enough memory
  376. // Outer loop for walking the tree
  377. for len(path) >= len(n.path) && strings.ToLower(path[:len(n.path)]) == strings.ToLower(n.path) {
  378. path = path[len(n.path):]
  379. ciPath = append(ciPath, n.path...)
  380. if len(path) > 0 {
  381. // If this node does not have a wildcard (param or catchAll) child,
  382. // we can just look up the next child node and continue to walk down
  383. // the tree
  384. if !n.wildChild {
  385. r := unicode.ToLower(rune(path[0]))
  386. for i, index := range n.indices {
  387. // must use recursive approach since both index and
  388. // ToLower(index) could exist. We must check both.
  389. if r == unicode.ToLower(index) {
  390. out, found := n.children[i].findCaseInsensitivePath(path, fixTrailingSlash)
  391. if found {
  392. return append(ciPath, out...), true
  393. }
  394. }
  395. }
  396. // Nothing found. We can recommend to redirect to the same URL
  397. // without a trailing slash if a leaf exists for that path
  398. found = (fixTrailingSlash && path == "/" && n.handlers != nil)
  399. return
  400. }
  401. n = n.children[0]
  402. switch n.nType {
  403. case param:
  404. // find param end (either '/' or path end)
  405. k := 0
  406. for k < len(path) && path[k] != '/' {
  407. k++
  408. }
  409. // add param value to case insensitive path
  410. ciPath = append(ciPath, path[:k]...)
  411. // we need to go deeper!
  412. if k < len(path) {
  413. if len(n.children) > 0 {
  414. path = path[k:]
  415. n = n.children[0]
  416. continue
  417. }
  418. // ... but we can't
  419. if fixTrailingSlash && len(path) == k+1 {
  420. return ciPath, true
  421. }
  422. return
  423. }
  424. if n.handlers != nil {
  425. return ciPath, true
  426. } else if fixTrailingSlash && len(n.children) == 1 {
  427. // No handle found. Check if a handle for this path + a
  428. // trailing slash exists
  429. n = n.children[0]
  430. if n.path == "/" && n.handlers != nil {
  431. return append(ciPath, '/'), true
  432. }
  433. }
  434. return
  435. case catchAll:
  436. return append(ciPath, path...), true
  437. default:
  438. panic("Invalid node type")
  439. }
  440. } else {
  441. // We should have reached the node containing the handle.
  442. // Check if this node has a handle registered.
  443. if n.handlers != nil {
  444. return ciPath, true
  445. }
  446. // No handle found.
  447. // Try to fix the path by adding a trailing slash
  448. if fixTrailingSlash {
  449. for i := 0; i < len(n.indices); i++ {
  450. if n.indices[i] == '/' {
  451. n = n.children[i]
  452. if (len(n.path) == 1 && n.handlers != nil) ||
  453. (n.nType == catchAll && n.children[0].handlers != nil) {
  454. return append(ciPath, '/'), true
  455. }
  456. return
  457. }
  458. }
  459. }
  460. return
  461. }
  462. }
  463. // Nothing found.
  464. // Try to fix the path by adding / removing a trailing slash
  465. if fixTrailingSlash {
  466. if path == "/" {
  467. return ciPath, true
  468. }
  469. if len(path)+1 == len(n.path) && n.path[len(path)] == '/' &&
  470. strings.ToLower(path) == strings.ToLower(n.path[:len(path)]) &&
  471. n.handlers != nil {
  472. return append(ciPath, n.path...), true
  473. }
  474. }
  475. return
  476. }