tree.go 14 KB

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