1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116
|
package radix
import (
"errors"
"strings"
"github.com/valyala/bytebufferpool"
"github.com/valyala/fasthttp"
)
// New returns an empty routes storage
func New() *Tree {
return &Tree{
root: &node{
nType: root,
},
}
}
// Add adds a node with the given handle to the path.
//
// WARNING: Not concurrency-safe!
func (t *Tree) Add(path string, handler fasthttp.RequestHandler) {
if !strings.HasPrefix(path, "/") {
panicf("path must begin with '/' in path '%s'", path)
} else if handler == nil {
panic("nil handler")
}
fullPath := path
i := longestCommonPrefix(path, t.root.path)
if i > 0 {
if len(t.root.path) > i {
t.root.split(i)
}
path = path[i:]
}
n, err := t.root.add(path, fullPath, handler)
if err != nil {
var radixErr radixError
if errors.As(err, &radixErr) && t.Mutable && !n.tsr {
switch radixErr.msg {
case errSetHandler:
n.handler = handler
return
case errSetWildcardHandler:
n.wildcard.handler = handler
return
}
}
panic(err)
}
if len(t.root.path) == 0 {
t.root = t.root.children[0]
t.root.nType = root
}
// Reorder the nodes
t.root.sort()
}
// Get returns the handle registered with the given path (key). The values of
// param/wildcard are saved as ctx.UserValue.
// If no handle can be found, a TSR (trailing slash redirect) recommendation is
// made if a handle exists with an extra (without the) trailing slash for the
// given path.
func (t *Tree) Get(path string, ctx *fasthttp.RequestCtx) (fasthttp.RequestHandler, bool) {
if len(path) > len(t.root.path) {
if path[:len(t.root.path)] != t.root.path {
return nil, false
}
path = path[len(t.root.path):]
return t.root.getFromChild(path, ctx)
} else if path == t.root.path {
switch {
case t.root.tsr:
return nil, true
case t.root.handler != nil:
return t.root.handler, false
case t.root.wildcard != nil:
if ctx != nil {
ctx.SetUserValue(t.root.wildcard.paramKey, "")
}
return t.root.wildcard.handler, false
}
}
return nil, false
}
// FindCaseInsensitivePath makes a case-insensitive lookup of the given path
// and tries to find a handler.
// It can optionally also fix trailing slashes.
// It returns the case-corrected path and a bool indicating whether the lookup
// was successful.
func (t *Tree) FindCaseInsensitivePath(path string, fixTrailingSlash bool, buf *bytebufferpool.ByteBuffer) bool {
found, tsr := t.root.find(path, buf)
if !found || (tsr && !fixTrailingSlash) {
buf.Reset()
return false
}
return true
}
|