tree.go 16 KB

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