forked from mirror/gin
tree: sync httprouter update (#2173)
This commit is contained in:
parent
6e16da8683
commit
168fa94516
164
tree.go
164
tree.go
|
@ -264,71 +264,80 @@ walk:
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (n *node) insertChild(numParams uint8, path string, fullPath string, handlers HandlersChain) {
|
// Search for a wildcard segment and check the name for invalid characters.
|
||||||
var offset int // already handled bytes of the path
|
// Returns -1 as index, if no wildcard war found.
|
||||||
|
func findWildcard(path string) (wildcard string, i int, valid bool) {
|
||||||
// Find prefix until first wildcard (beginning with ':' or '*')
|
// Find start
|
||||||
for i, max := 0, len(path); numParams > 0; i++ {
|
for start, c := range []byte(path) {
|
||||||
c := path[i]
|
// A wildcard starts with ':' (param) or '*' (catch-all)
|
||||||
if c != ':' && c != '*' {
|
if c != ':' && c != '*' {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
// Find wildcard end (either '/' or path end) and check the name for invalid characters
|
// Find end and check for invalid characters
|
||||||
end := i + 1
|
valid = true
|
||||||
invalid := false
|
for end, c := range []byte(path[start+1:]) {
|
||||||
for end < max {
|
switch c {
|
||||||
c := path[end]
|
case '/':
|
||||||
if c == '/' {
|
return path[start : start+1+end], start, valid
|
||||||
break
|
case ':', '*':
|
||||||
|
valid = false
|
||||||
}
|
}
|
||||||
if c == ':' || c == '*' {
|
}
|
||||||
invalid = true
|
return path[start:], start, valid
|
||||||
}
|
}
|
||||||
end++
|
return "", -1, false
|
||||||
|
}
|
||||||
|
|
||||||
|
func (n *node) insertChild(numParams uint8, path string, fullPath string, handlers HandlersChain) {
|
||||||
|
for numParams > 0 {
|
||||||
|
// Find prefix until first wildcard
|
||||||
|
wildcard, i, valid := findWildcard(path)
|
||||||
|
if i < 0 { // No wildcard found
|
||||||
|
break
|
||||||
}
|
}
|
||||||
|
|
||||||
// The wildcard name must not contain ':' and '*'
|
// The wildcard name must not contain ':' and '*'
|
||||||
if invalid {
|
if !valid {
|
||||||
panic("only one wildcard per path segment is allowed, has: '" +
|
panic("only one wildcard per path segment is allowed, has: '" +
|
||||||
path[i:end] + "' in path '" + fullPath + "'")
|
wildcard + "' in path '" + fullPath + "'")
|
||||||
}
|
}
|
||||||
|
|
||||||
// check if the wildcard has a name
|
// check if the wildcard has a name
|
||||||
if end-i < 2 {
|
if len(wildcard) < 2 {
|
||||||
panic("wildcards must be named with a non-empty name in path '" + fullPath + "'")
|
panic("wildcards must be named with a non-empty name in path '" + fullPath + "'")
|
||||||
}
|
}
|
||||||
|
|
||||||
// Check if this node has existing children which would be
|
// Check if this node has existing children which would be
|
||||||
// unreachable if we insert the wildcard here
|
// unreachable if we insert the wildcard here
|
||||||
if len(n.children) > 0 {
|
if len(n.children) > 0 {
|
||||||
panic("wildcard route '" + path[i:end] +
|
panic("wildcard segment '" + wildcard +
|
||||||
"' conflicts with existing children in path '" + fullPath + "'")
|
"' conflicts with existing children in path '" + fullPath + "'")
|
||||||
}
|
}
|
||||||
|
|
||||||
if c == ':' { // param
|
if wildcard[0] == ':' { // param
|
||||||
// split path at the beginning of the wildcard
|
|
||||||
if i > 0 {
|
if i > 0 {
|
||||||
n.path = path[offset:i]
|
// Insert prefix before the current wildcard
|
||||||
offset = i
|
n.path = path[:i]
|
||||||
|
path = path[i:]
|
||||||
}
|
}
|
||||||
|
|
||||||
|
n.wildChild = true
|
||||||
child := &node{
|
child := &node{
|
||||||
nType: param,
|
nType: param,
|
||||||
|
path: wildcard,
|
||||||
maxParams: numParams,
|
maxParams: numParams,
|
||||||
fullPath: fullPath,
|
fullPath: fullPath,
|
||||||
}
|
}
|
||||||
n.children = []*node{child}
|
n.children = []*node{child}
|
||||||
n.wildChild = true
|
|
||||||
n = child
|
n = child
|
||||||
n.priority++
|
n.priority++
|
||||||
numParams--
|
numParams--
|
||||||
|
|
||||||
// if the path doesn't end with the wildcard, then there
|
// if the path doesn't end with the wildcard, then there
|
||||||
// will be another non-wildcard subpath starting with '/'
|
// will be another non-wildcard subpath starting with '/'
|
||||||
if end < max {
|
if len(wildcard) < len(path) {
|
||||||
n.path = path[offset:end]
|
path = path[len(wildcard):]
|
||||||
offset = end
|
|
||||||
|
|
||||||
child := &node{
|
child := &node{
|
||||||
maxParams: numParams,
|
maxParams: numParams,
|
||||||
|
@ -337,58 +346,63 @@ func (n *node) insertChild(numParams uint8, path string, fullPath string, handle
|
||||||
}
|
}
|
||||||
n.children = []*node{child}
|
n.children = []*node{child}
|
||||||
n = child
|
n = child
|
||||||
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
} else { // catchAll
|
// Otherwise we're done. Insert the handle in the new leaf
|
||||||
if end != max || numParams > 1 {
|
n.handlers = handlers
|
||||||
panic("catch-all routes are only allowed at the end of the path in path '" + fullPath + "'")
|
|
||||||
}
|
|
||||||
|
|
||||||
if len(n.path) > 0 && n.path[len(n.path)-1] == '/' {
|
|
||||||
panic("catch-all conflicts with existing handle for the path segment root in path '" + fullPath + "'")
|
|
||||||
}
|
|
||||||
|
|
||||||
// currently fixed width 1 for '/'
|
|
||||||
i--
|
|
||||||
if path[i] != '/' {
|
|
||||||
panic("no / before catch-all in path '" + fullPath + "'")
|
|
||||||
}
|
|
||||||
|
|
||||||
n.path = path[offset:i]
|
|
||||||
|
|
||||||
// first node: catchAll node with empty path
|
|
||||||
child := &node{
|
|
||||||
wildChild: true,
|
|
||||||
nType: catchAll,
|
|
||||||
maxParams: 1,
|
|
||||||
fullPath: fullPath,
|
|
||||||
}
|
|
||||||
// update maxParams of the parent node
|
|
||||||
if n.maxParams < 1 {
|
|
||||||
n.maxParams = 1
|
|
||||||
}
|
|
||||||
n.children = []*node{child}
|
|
||||||
n.indices = string(path[i])
|
|
||||||
n = child
|
|
||||||
n.priority++
|
|
||||||
|
|
||||||
// second node: node holding the variable
|
|
||||||
child = &node{
|
|
||||||
path: path[i:],
|
|
||||||
nType: catchAll,
|
|
||||||
maxParams: 1,
|
|
||||||
handlers: handlers,
|
|
||||||
priority: 1,
|
|
||||||
fullPath: fullPath,
|
|
||||||
}
|
|
||||||
n.children = []*node{child}
|
|
||||||
|
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// catchAll
|
||||||
|
if i+len(wildcard) != len(path) || numParams > 1 {
|
||||||
|
panic("catch-all routes are only allowed at the end of the path in path '" + fullPath + "'")
|
||||||
|
}
|
||||||
|
|
||||||
|
if len(n.path) > 0 && n.path[len(n.path)-1] == '/' {
|
||||||
|
panic("catch-all conflicts with existing handle for the path segment root in path '" + fullPath + "'")
|
||||||
|
}
|
||||||
|
|
||||||
|
// currently fixed width 1 for '/'
|
||||||
|
i--
|
||||||
|
if path[i] != '/' {
|
||||||
|
panic("no / before catch-all in path '" + fullPath + "'")
|
||||||
|
}
|
||||||
|
|
||||||
|
n.path = path[:i]
|
||||||
|
|
||||||
|
// First node: catchAll node with empty path
|
||||||
|
child := &node{
|
||||||
|
wildChild: true,
|
||||||
|
nType: catchAll,
|
||||||
|
maxParams: 1,
|
||||||
|
fullPath: fullPath,
|
||||||
|
}
|
||||||
|
// update maxParams of the parent node
|
||||||
|
if n.maxParams < 1 {
|
||||||
|
n.maxParams = 1
|
||||||
|
}
|
||||||
|
n.children = []*node{child}
|
||||||
|
n.indices = string('/')
|
||||||
|
n = child
|
||||||
|
n.priority++
|
||||||
|
|
||||||
|
// second node: node holding the variable
|
||||||
|
child = &node{
|
||||||
|
path: path[i:],
|
||||||
|
nType: catchAll,
|
||||||
|
maxParams: 1,
|
||||||
|
handlers: handlers,
|
||||||
|
priority: 1,
|
||||||
|
fullPath: fullPath,
|
||||||
|
}
|
||||||
|
n.children = []*node{child}
|
||||||
|
|
||||||
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
// insert remaining path part and handle to the leaf
|
// If no wildcard was found, simple insert the path and handle
|
||||||
n.path = path[offset:]
|
n.path = path
|
||||||
n.handlers = handlers
|
n.handlers = handlers
|
||||||
n.fullPath = fullPath
|
n.fullPath = fullPath
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue