tree.go 15 KB

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