tree.go 22 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871
  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. // at https://github.com/julienschmidt/httprouter/blob/master/LICENSE
  4. package gin
  5. import (
  6. "bytes"
  7. "net/url"
  8. "strings"
  9. "unicode"
  10. "unicode/utf8"
  11. "github.com/gin-gonic/gin/internal/bytesconv"
  12. )
  13. var (
  14. strColon = []byte(":")
  15. strStar = []byte("*")
  16. strSlash = []byte("/")
  17. )
  18. // Param is a single URL parameter, consisting of a key and a value.
  19. type Param struct {
  20. Key string
  21. Value string
  22. }
  23. // Params is a Param-slice, as returned by the router.
  24. // The slice is ordered, the first URL parameter is also the first slice value.
  25. // It is therefore safe to read values by the index.
  26. type Params []Param
  27. // Get returns the value of the first Param which key matches the given name and a boolean true.
  28. // If no matching Param is found, an empty string is returned and a boolean false .
  29. func (ps Params) Get(name string) (string, bool) {
  30. for _, entry := range ps {
  31. if entry.Key == name {
  32. return entry.Value, true
  33. }
  34. }
  35. return "", false
  36. }
  37. // ByName returns the value of the first Param which key matches the given name.
  38. // If no matching Param is found, an empty string is returned.
  39. func (ps Params) ByName(name string) (va string) {
  40. va, _ = ps.Get(name)
  41. return
  42. }
  43. type methodTree struct {
  44. method string
  45. root *node
  46. }
  47. type methodTrees []methodTree
  48. func (trees methodTrees) get(method string) *node {
  49. for _, tree := range trees {
  50. if tree.method == method {
  51. return tree.root
  52. }
  53. }
  54. return nil
  55. }
  56. func min(a, b int) int {
  57. if a <= b {
  58. return a
  59. }
  60. return b
  61. }
  62. func longestCommonPrefix(a, b string) int {
  63. i := 0
  64. max := min(len(a), len(b))
  65. for i < max && a[i] == b[i] {
  66. i++
  67. }
  68. return i
  69. }
  70. // addChild will add a child node, keeping wildcardChild at the end
  71. func (n *node) addChild(child *node) {
  72. if n.wildChild && len(n.children) > 0 {
  73. wildcardChild := n.children[len(n.children)-1]
  74. n.children = append(n.children[:len(n.children)-1], child, wildcardChild)
  75. } else {
  76. n.children = append(n.children, child)
  77. }
  78. }
  79. func countParams(path string) uint16 {
  80. var n uint16
  81. s := bytesconv.StringToBytes(path)
  82. n += uint16(bytes.Count(s, strColon))
  83. n += uint16(bytes.Count(s, strStar))
  84. return n
  85. }
  86. func countSections(path string) uint16 {
  87. s := bytesconv.StringToBytes(path)
  88. return uint16(bytes.Count(s, strSlash))
  89. }
  90. type nodeType uint8
  91. const (
  92. root nodeType = iota + 1
  93. param
  94. catchAll
  95. )
  96. type node struct {
  97. path string
  98. indices string
  99. wildChild bool
  100. nType nodeType
  101. priority uint32
  102. children []*node // child nodes, at most 1 :param style node at the end of the array
  103. handlers HandlersChain
  104. fullPath string
  105. }
  106. // Increments priority of the given child and reorders if necessary
  107. func (n *node) incrementChildPrio(pos int) int {
  108. cs := n.children
  109. cs[pos].priority++
  110. prio := cs[pos].priority
  111. // Adjust position (move to front)
  112. newPos := pos
  113. for ; newPos > 0 && cs[newPos-1].priority < prio; newPos-- {
  114. // Swap node positions
  115. cs[newPos-1], cs[newPos] = cs[newPos], cs[newPos-1]
  116. }
  117. // Build new index char string
  118. if newPos != pos {
  119. n.indices = n.indices[:newPos] + // Unchanged prefix, might be empty
  120. n.indices[pos:pos+1] + // The index char we move
  121. n.indices[newPos:pos] + n.indices[pos+1:] // Rest without char at 'pos'
  122. }
  123. return newPos
  124. }
  125. // addRoute adds a node with the given handle to the path.
  126. // Not concurrency-safe!
  127. func (n *node) addRoute(path string, handlers HandlersChain) {
  128. fullPath := path
  129. n.priority++
  130. // Empty tree
  131. if len(n.path) == 0 && len(n.children) == 0 {
  132. n.insertChild(path, fullPath, handlers)
  133. n.nType = root
  134. return
  135. }
  136. parentFullPathIndex := 0
  137. walk:
  138. for {
  139. // Find the longest common prefix.
  140. // This also implies that the common prefix contains no ':' or '*'
  141. // since the existing key can't contain those chars.
  142. i := longestCommonPrefix(path, n.path)
  143. // Split edge
  144. if i < len(n.path) {
  145. child := node{
  146. path: n.path[i:],
  147. wildChild: n.wildChild,
  148. indices: n.indices,
  149. children: n.children,
  150. handlers: n.handlers,
  151. priority: n.priority - 1,
  152. fullPath: n.fullPath,
  153. }
  154. n.children = []*node{&child}
  155. // []byte for proper unicode char conversion, see #65
  156. n.indices = bytesconv.BytesToString([]byte{n.path[i]})
  157. n.path = path[:i]
  158. n.handlers = nil
  159. n.wildChild = false
  160. n.fullPath = fullPath[:parentFullPathIndex+i]
  161. }
  162. // Make new node a child of this node
  163. if i < len(path) {
  164. path = path[i:]
  165. c := path[0]
  166. // '/' after param
  167. if n.nType == param && c == '/' && len(n.children) == 1 {
  168. parentFullPathIndex += len(n.path)
  169. n = n.children[0]
  170. n.priority++
  171. continue walk
  172. }
  173. // Check if a child with the next path byte exists
  174. for i, max := 0, len(n.indices); i < max; i++ {
  175. if c == n.indices[i] {
  176. parentFullPathIndex += len(n.path)
  177. i = n.incrementChildPrio(i)
  178. n = n.children[i]
  179. continue walk
  180. }
  181. }
  182. // Otherwise insert it
  183. if c != ':' && c != '*' && n.nType != catchAll {
  184. // []byte for proper unicode char conversion, see #65
  185. n.indices += bytesconv.BytesToString([]byte{c})
  186. child := &node{
  187. fullPath: fullPath,
  188. }
  189. n.addChild(child)
  190. n.incrementChildPrio(len(n.indices) - 1)
  191. n = child
  192. } else if n.wildChild {
  193. // inserting a wildcard node, need to check if it conflicts with the existing wildcard
  194. n = n.children[len(n.children)-1]
  195. n.priority++
  196. // Check if the wildcard matches
  197. if len(path) >= len(n.path) && n.path == path[:len(n.path)] &&
  198. // Adding a child to a catchAll is not possible
  199. n.nType != catchAll &&
  200. // Check for longer wildcard, e.g. :name and :names
  201. (len(n.path) >= len(path) || path[len(n.path)] == '/') {
  202. continue walk
  203. }
  204. // Wildcard conflict
  205. pathSeg := path
  206. if n.nType != catchAll {
  207. pathSeg = strings.SplitN(pathSeg, "/", 2)[0]
  208. }
  209. prefix := fullPath[:strings.Index(fullPath, pathSeg)] + n.path
  210. panic("'" + pathSeg +
  211. "' in new path '" + fullPath +
  212. "' conflicts with existing wildcard '" + n.path +
  213. "' in existing prefix '" + prefix +
  214. "'")
  215. }
  216. n.insertChild(path, fullPath, handlers)
  217. return
  218. }
  219. // Otherwise add handle to current node
  220. if n.handlers != nil {
  221. panic("handlers are already registered for path '" + fullPath + "'")
  222. }
  223. n.handlers = handlers
  224. n.fullPath = fullPath
  225. return
  226. }
  227. }
  228. // Search for a wildcard segment and check the name for invalid characters.
  229. // Returns -1 as index, if no wildcard was found.
  230. func findWildcard(path string) (wildcard string, i int, valid bool) {
  231. // Find start
  232. for start, c := range []byte(path) {
  233. // A wildcard starts with ':' (param) or '*' (catch-all)
  234. if c != ':' && c != '*' {
  235. continue
  236. }
  237. // Find end and check for invalid characters
  238. valid = true
  239. for end, c := range []byte(path[start+1:]) {
  240. switch c {
  241. case '/':
  242. return path[start : start+1+end], start, valid
  243. case ':', '*':
  244. valid = false
  245. }
  246. }
  247. return path[start:], start, valid
  248. }
  249. return "", -1, false
  250. }
  251. func (n *node) insertChild(path string, fullPath string, handlers HandlersChain) {
  252. for {
  253. // Find prefix until first wildcard
  254. wildcard, i, valid := findWildcard(path)
  255. if i < 0 { // No wildcard found
  256. break
  257. }
  258. // The wildcard name must only contain one ':' or '*' character
  259. if !valid {
  260. panic("only one wildcard per path segment is allowed, has: '" +
  261. wildcard + "' in path '" + fullPath + "'")
  262. }
  263. // check if the wildcard has a name
  264. if len(wildcard) < 2 {
  265. panic("wildcards must be named with a non-empty name in path '" + fullPath + "'")
  266. }
  267. if wildcard[0] == ':' { // param
  268. if i > 0 {
  269. // Insert prefix before the current wildcard
  270. n.path = path[:i]
  271. path = path[i:]
  272. }
  273. child := &node{
  274. nType: param,
  275. path: wildcard,
  276. fullPath: fullPath,
  277. }
  278. n.addChild(child)
  279. n.wildChild = true
  280. n = child
  281. n.priority++
  282. // if the path doesn't end with the wildcard, then there
  283. // will be another subpath starting with '/'
  284. if len(wildcard) < len(path) {
  285. path = path[len(wildcard):]
  286. child := &node{
  287. priority: 1,
  288. fullPath: fullPath,
  289. }
  290. n.addChild(child)
  291. n = child
  292. continue
  293. }
  294. // Otherwise we're done. Insert the handle in the new leaf
  295. n.handlers = handlers
  296. return
  297. }
  298. // catchAll
  299. if i+len(wildcard) != len(path) {
  300. panic("catch-all routes are only allowed at the end of the path in path '" + fullPath + "'")
  301. }
  302. if len(n.path) > 0 && n.path[len(n.path)-1] == '/' {
  303. pathSeg := strings.SplitN(n.children[0].path, "/", 2)[0]
  304. panic("catch-all wildcard '" + path +
  305. "' in new path '" + fullPath +
  306. "' conflicts with existing path segment '" + pathSeg +
  307. "' in existing prefix '" + n.path + pathSeg +
  308. "'")
  309. }
  310. // currently fixed width 1 for '/'
  311. i--
  312. if path[i] != '/' {
  313. panic("no / before catch-all in path '" + fullPath + "'")
  314. }
  315. n.path = path[:i]
  316. // First node: catchAll node with empty path
  317. child := &node{
  318. wildChild: true,
  319. nType: catchAll,
  320. fullPath: fullPath,
  321. }
  322. n.addChild(child)
  323. n.indices = string('/')
  324. n = child
  325. n.priority++
  326. // second node: node holding the variable
  327. child = &node{
  328. path: path[i:],
  329. nType: catchAll,
  330. handlers: handlers,
  331. priority: 1,
  332. fullPath: fullPath,
  333. }
  334. n.children = []*node{child}
  335. return
  336. }
  337. // If no wildcard was found, simply insert the path and handle
  338. n.path = path
  339. n.handlers = handlers
  340. n.fullPath = fullPath
  341. }
  342. // nodeValue holds return values of (*Node).getValue method
  343. type nodeValue struct {
  344. handlers HandlersChain
  345. params *Params
  346. tsr bool
  347. fullPath string
  348. }
  349. type skippedNode struct {
  350. path string
  351. node *node
  352. paramsCount int16
  353. }
  354. // Returns the handle registered with the given path (key). The values of
  355. // wildcards are saved to a map.
  356. // If no handle can be found, a TSR (trailing slash redirect) recommendation is
  357. // made if a handle exists with an extra (without the) trailing slash for the
  358. // given path.
  359. func (n *node) getValue(path string, params *Params, skippedNodes *[]skippedNode, unescape bool) (value nodeValue) {
  360. var globalParamsCount int16
  361. walk: // Outer loop for walking the tree
  362. for {
  363. prefix := n.path
  364. if len(path) > len(prefix) {
  365. if path[:len(prefix)] == prefix {
  366. path = path[len(prefix):]
  367. // Try all the non-wildcard children first by matching the indices
  368. idxc := path[0]
  369. for i, c := range []byte(n.indices) {
  370. if c == idxc {
  371. // strings.HasPrefix(n.children[len(n.children)-1].path, ":") == n.wildChild
  372. if n.wildChild {
  373. index := len(*skippedNodes)
  374. *skippedNodes = (*skippedNodes)[:index+1]
  375. (*skippedNodes)[index] = skippedNode{
  376. path: prefix + path,
  377. node: &node{
  378. path: n.path,
  379. wildChild: n.wildChild,
  380. nType: n.nType,
  381. priority: n.priority,
  382. children: n.children,
  383. handlers: n.handlers,
  384. fullPath: n.fullPath,
  385. },
  386. paramsCount: globalParamsCount,
  387. }
  388. }
  389. n = n.children[i]
  390. continue walk
  391. }
  392. }
  393. if !n.wildChild {
  394. // If the path at the end of the loop is not equal to '/' and the current node has no child nodes
  395. // the current node needs to roll back to last vaild skippedNode
  396. if path != "/" {
  397. for l := len(*skippedNodes); l > 0; {
  398. skippedNode := (*skippedNodes)[l-1]
  399. *skippedNodes = (*skippedNodes)[:l-1]
  400. if strings.HasSuffix(skippedNode.path, path) {
  401. path = skippedNode.path
  402. n = skippedNode.node
  403. if value.params != nil {
  404. *value.params = (*value.params)[:skippedNode.paramsCount]
  405. }
  406. globalParamsCount = skippedNode.paramsCount
  407. continue walk
  408. }
  409. }
  410. }
  411. // Nothing found.
  412. // We can recommend to redirect to the same URL without a
  413. // trailing slash if a leaf exists for that path.
  414. value.tsr = path == "/" && n.handlers != nil
  415. return
  416. }
  417. // Handle wildcard child, which is always at the end of the array
  418. n = n.children[len(n.children)-1]
  419. globalParamsCount++
  420. switch n.nType {
  421. case param:
  422. // fix truncate the parameter
  423. // tree_test.go line: 204
  424. // Find param end (either '/' or path end)
  425. end := 0
  426. for end < len(path) && path[end] != '/' {
  427. end++
  428. }
  429. // Save param value
  430. if params != nil && cap(*params) > 0 {
  431. if value.params == nil {
  432. value.params = params
  433. }
  434. // Expand slice within preallocated capacity
  435. i := len(*value.params)
  436. *value.params = (*value.params)[:i+1]
  437. val := path[:end]
  438. if unescape {
  439. if v, err := url.QueryUnescape(val); err == nil {
  440. val = v
  441. }
  442. }
  443. (*value.params)[i] = Param{
  444. Key: n.path[1:],
  445. Value: val,
  446. }
  447. }
  448. // we need to go deeper!
  449. if end < len(path) {
  450. if len(n.children) > 0 {
  451. path = path[end:]
  452. n = n.children[0]
  453. continue walk
  454. }
  455. // ... but we can't
  456. value.tsr = len(path) == end+1
  457. return
  458. }
  459. if value.handlers = n.handlers; value.handlers != nil {
  460. value.fullPath = n.fullPath
  461. return
  462. }
  463. if len(n.children) == 1 {
  464. // No handle found. Check if a handle for this path + a
  465. // trailing slash exists for TSR recommendation
  466. n = n.children[0]
  467. value.tsr = (n.path == "/" && n.handlers != nil) || (n.path == "" && n.indices == "/")
  468. }
  469. return
  470. case catchAll:
  471. // Save param value
  472. if params != nil {
  473. if value.params == nil {
  474. value.params = params
  475. }
  476. // Expand slice within preallocated capacity
  477. i := len(*value.params)
  478. *value.params = (*value.params)[:i+1]
  479. val := path
  480. if unescape {
  481. if v, err := url.QueryUnescape(path); err == nil {
  482. val = v
  483. }
  484. }
  485. (*value.params)[i] = Param{
  486. Key: n.path[2:],
  487. Value: val,
  488. }
  489. }
  490. value.handlers = n.handlers
  491. value.fullPath = n.fullPath
  492. return
  493. default:
  494. panic("invalid node type")
  495. }
  496. }
  497. }
  498. if path == prefix {
  499. // If the current path does not equal '/' and the node does not have a registered handle and the most recently matched node has a child node
  500. // the current node needs to roll back to last vaild skippedNode
  501. if n.handlers == nil && path != "/" {
  502. for l := len(*skippedNodes); l > 0; {
  503. skippedNode := (*skippedNodes)[l-1]
  504. *skippedNodes = (*skippedNodes)[:l-1]
  505. if strings.HasSuffix(skippedNode.path, path) {
  506. path = skippedNode.path
  507. n = skippedNode.node
  508. if value.params != nil {
  509. *value.params = (*value.params)[:skippedNode.paramsCount]
  510. }
  511. globalParamsCount = skippedNode.paramsCount
  512. continue walk
  513. }
  514. }
  515. // n = latestNode.children[len(latestNode.children)-1]
  516. }
  517. // We should have reached the node containing the handle.
  518. // Check if this node has a handle registered.
  519. if value.handlers = n.handlers; value.handlers != nil {
  520. value.fullPath = n.fullPath
  521. return
  522. }
  523. // If there is no handle for this route, but this route has a
  524. // wildcard child, there must be a handle for this path with an
  525. // additional trailing slash
  526. if path == "/" && n.wildChild && n.nType != root {
  527. value.tsr = true
  528. return
  529. }
  530. // No handle found. Check if a handle for this path + a
  531. // trailing slash exists for trailing slash recommendation
  532. for i, c := range []byte(n.indices) {
  533. if c == '/' {
  534. n = n.children[i]
  535. value.tsr = (len(n.path) == 1 && n.handlers != nil) ||
  536. (n.nType == catchAll && n.children[0].handlers != nil)
  537. return
  538. }
  539. }
  540. return
  541. }
  542. // Nothing found. We can recommend to redirect to the same URL with an
  543. // extra trailing slash if a leaf exists for that path
  544. value.tsr = path == "/" ||
  545. (len(prefix) == len(path)+1 && prefix[len(path)] == '/' &&
  546. path == prefix[:len(prefix)-1] && n.handlers != nil)
  547. // roll back to last valid skippedNode
  548. if !value.tsr && path != "/" {
  549. for l := len(*skippedNodes); l > 0; {
  550. skippedNode := (*skippedNodes)[l-1]
  551. *skippedNodes = (*skippedNodes)[:l-1]
  552. if strings.HasSuffix(skippedNode.path, path) {
  553. path = skippedNode.path
  554. n = skippedNode.node
  555. if value.params != nil {
  556. *value.params = (*value.params)[:skippedNode.paramsCount]
  557. }
  558. globalParamsCount = skippedNode.paramsCount
  559. continue walk
  560. }
  561. }
  562. }
  563. return
  564. }
  565. }
  566. // Makes a case-insensitive lookup of the given path and tries to find a handler.
  567. // It can optionally also fix trailing slashes.
  568. // It returns the case-corrected path and a bool indicating whether the lookup
  569. // was successful.
  570. func (n *node) findCaseInsensitivePath(path string, fixTrailingSlash bool) ([]byte, bool) {
  571. const stackBufSize = 128
  572. // Use a static sized buffer on the stack in the common case.
  573. // If the path is too long, allocate a buffer on the heap instead.
  574. buf := make([]byte, 0, stackBufSize)
  575. if length := len(path) + 1; length > stackBufSize {
  576. buf = make([]byte, 0, length)
  577. }
  578. ciPath := n.findCaseInsensitivePathRec(
  579. path,
  580. buf, // Preallocate enough memory for new path
  581. [4]byte{}, // Empty rune buffer
  582. fixTrailingSlash,
  583. )
  584. return ciPath, ciPath != nil
  585. }
  586. // Shift bytes in array by n bytes left
  587. func shiftNRuneBytes(rb [4]byte, n int) [4]byte {
  588. switch n {
  589. case 0:
  590. return rb
  591. case 1:
  592. return [4]byte{rb[1], rb[2], rb[3], 0}
  593. case 2:
  594. return [4]byte{rb[2], rb[3]}
  595. case 3:
  596. return [4]byte{rb[3]}
  597. default:
  598. return [4]byte{}
  599. }
  600. }
  601. // Recursive case-insensitive lookup function used by n.findCaseInsensitivePath
  602. func (n *node) findCaseInsensitivePathRec(path string, ciPath []byte, rb [4]byte, fixTrailingSlash bool) []byte {
  603. npLen := len(n.path)
  604. walk: // Outer loop for walking the tree
  605. for len(path) >= npLen && (npLen == 0 || strings.EqualFold(path[1:npLen], n.path[1:])) {
  606. // Add common prefix to result
  607. oldPath := path
  608. path = path[npLen:]
  609. ciPath = append(ciPath, n.path...)
  610. if len(path) == 0 {
  611. // We should have reached the node containing the handle.
  612. // Check if this node has a handle registered.
  613. if n.handlers != nil {
  614. return ciPath
  615. }
  616. // No handle found.
  617. // Try to fix the path by adding a trailing slash
  618. if fixTrailingSlash {
  619. for i, c := range []byte(n.indices) {
  620. if c == '/' {
  621. n = n.children[i]
  622. if (len(n.path) == 1 && n.handlers != nil) ||
  623. (n.nType == catchAll && n.children[0].handlers != nil) {
  624. return append(ciPath, '/')
  625. }
  626. return nil
  627. }
  628. }
  629. }
  630. return nil
  631. }
  632. // If this node does not have a wildcard (param or catchAll) child,
  633. // we can just look up the next child node and continue to walk down
  634. // the tree
  635. if !n.wildChild {
  636. // Skip rune bytes already processed
  637. rb = shiftNRuneBytes(rb, npLen)
  638. if rb[0] != 0 {
  639. // Old rune not finished
  640. idxc := rb[0]
  641. for i, c := range []byte(n.indices) {
  642. if c == idxc {
  643. // continue with child node
  644. n = n.children[i]
  645. npLen = len(n.path)
  646. continue walk
  647. }
  648. }
  649. } else {
  650. // Process a new rune
  651. var rv rune
  652. // Find rune start.
  653. // Runes are up to 4 byte long,
  654. // -4 would definitely be another rune.
  655. var off int
  656. for max := min(npLen, 3); off < max; off++ {
  657. if i := npLen - off; utf8.RuneStart(oldPath[i]) {
  658. // read rune from cached path
  659. rv, _ = utf8.DecodeRuneInString(oldPath[i:])
  660. break
  661. }
  662. }
  663. // Calculate lowercase bytes of current rune
  664. lo := unicode.ToLower(rv)
  665. utf8.EncodeRune(rb[:], lo)
  666. // Skip already processed bytes
  667. rb = shiftNRuneBytes(rb, off)
  668. idxc := rb[0]
  669. for i, c := range []byte(n.indices) {
  670. // Lowercase matches
  671. if c == idxc {
  672. // must use a recursive approach since both the
  673. // uppercase byte and the lowercase byte might exist
  674. // as an index
  675. if out := n.children[i].findCaseInsensitivePathRec(
  676. path, ciPath, rb, fixTrailingSlash,
  677. ); out != nil {
  678. return out
  679. }
  680. break
  681. }
  682. }
  683. // If we found no match, the same for the uppercase rune,
  684. // if it differs
  685. if up := unicode.ToUpper(rv); up != lo {
  686. utf8.EncodeRune(rb[:], up)
  687. rb = shiftNRuneBytes(rb, off)
  688. idxc := rb[0]
  689. for i, c := range []byte(n.indices) {
  690. // Uppercase matches
  691. if c == idxc {
  692. // Continue with child node
  693. n = n.children[i]
  694. npLen = len(n.path)
  695. continue walk
  696. }
  697. }
  698. }
  699. }
  700. // Nothing found. We can recommend to redirect to the same URL
  701. // without a trailing slash if a leaf exists for that path
  702. if fixTrailingSlash && path == "/" && n.handlers != nil {
  703. return ciPath
  704. }
  705. return nil
  706. }
  707. n = n.children[0]
  708. switch n.nType {
  709. case param:
  710. // Find param end (either '/' or path end)
  711. end := 0
  712. for end < len(path) && path[end] != '/' {
  713. end++
  714. }
  715. // Add param value to case insensitive path
  716. ciPath = append(ciPath, path[:end]...)
  717. // We need to go deeper!
  718. if end < len(path) {
  719. if len(n.children) > 0 {
  720. // Continue with child node
  721. n = n.children[0]
  722. npLen = len(n.path)
  723. path = path[end:]
  724. continue
  725. }
  726. // ... but we can't
  727. if fixTrailingSlash && len(path) == end+1 {
  728. return ciPath
  729. }
  730. return nil
  731. }
  732. if n.handlers != nil {
  733. return ciPath
  734. }
  735. if fixTrailingSlash && len(n.children) == 1 {
  736. // No handle found. Check if a handle for this path + a
  737. // trailing slash exists
  738. n = n.children[0]
  739. if n.path == "/" && n.handlers != nil {
  740. return append(ciPath, '/')
  741. }
  742. }
  743. return nil
  744. case catchAll:
  745. return append(ciPath, path...)
  746. default:
  747. panic("invalid node type")
  748. }
  749. }
  750. // Nothing found.
  751. // Try to fix the path by adding / removing a trailing slash
  752. if fixTrailingSlash {
  753. if path == "/" {
  754. return ciPath
  755. }
  756. if len(path)+1 == npLen && n.path[len(path)] == '/' &&
  757. strings.EqualFold(path[1:], n.path[1:len(path)]) && n.handlers != nil {
  758. return append(ciPath, n.path...)
  759. }
  760. }
  761. return nil
  762. }