Return nodeValue from getValue method

This commit is contained in:
Roman Zaynetdinov 2019-03-26 09:36:19 +02:00
parent 1d462bbe37
commit 7d4cee14b5
3 changed files with 52 additions and 46 deletions

12
gin.go
View File

@ -381,16 +381,16 @@ func (engine *Engine) handleHTTPRequest(c *Context) {
} }
root := t[i].root root := t[i].root
// Find route in tree // Find route in tree
handlers, params, tsr := root.getValue(rPath, c.Params, unescape) value := root.getValue(rPath, c.Params, unescape)
if handlers != nil { if value.handlers != nil {
c.handlers = handlers c.handlers = value.handlers
c.Params = params c.Params = value.params
c.Next() c.Next()
c.writermem.WriteHeaderNow() c.writermem.WriteHeaderNow()
return return
} }
if httpMethod != "CONNECT" && rPath != "/" { if httpMethod != "CONNECT" && rPath != "/" {
if tsr && engine.RedirectTrailingSlash { if value.tsr && engine.RedirectTrailingSlash {
redirectTrailingSlash(c) redirectTrailingSlash(c)
return return
} }
@ -406,7 +406,7 @@ func (engine *Engine) handleHTTPRequest(c *Context) {
if tree.method == httpMethod { if tree.method == httpMethod {
continue continue
} }
if handlers, _, _ := tree.root.getValue(rPath, nil, unescape); handlers != nil { if value := tree.root.getValue(rPath, nil, unescape); value.handlers != nil {
c.handlers = engine.allNoMethod c.handlers = engine.allNoMethod
serveError(c, http.StatusMethodNotAllowed, default405Body) serveError(c, http.StatusMethodNotAllowed, default405Body)
return return

60
tree.go
View File

@ -364,13 +364,19 @@ func (n *node) insertChild(numParams uint8, path string, fullPath string, handle
n.handlers = handlers n.handlers = handlers
} }
type nodeValue struct {
handlers HandlersChain
params Params
tsr bool
}
// getValue returns the handle registered with the given path (key). The values of // getValue returns the handle registered with the given path (key). The values of
// wildcards are saved to a map. // wildcards are saved to a map.
// If no handle can be found, a TSR (trailing slash redirect) recommendation is // 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 // made if a handle exists with an extra (without the) trailing slash for the
// given path. // given path.
func (n *node) getValue(path string, po Params, unescape bool) (handlers HandlersChain, p Params, tsr bool) { func (n *node) getValue(path string, po Params, unescape bool) (value nodeValue) {
p = po value.params = po
walk: // Outer loop for walking the tree walk: // Outer loop for walking the tree
for { for {
if len(path) > len(n.path) { if len(path) > len(n.path) {
@ -391,7 +397,7 @@ walk: // Outer loop for walking the tree
// Nothing found. // Nothing found.
// We can recommend to redirect to the same URL without a // We can recommend to redirect to the same URL without a
// trailing slash if a leaf exists for that path. // trailing slash if a leaf exists for that path.
tsr = path == "/" && n.handlers != nil value.tsr = path == "/" && n.handlers != nil
return return
} }
@ -406,20 +412,20 @@ walk: // Outer loop for walking the tree
} }
// save param value // save param value
if cap(p) < int(n.maxParams) { if cap(value.params) < int(n.maxParams) {
p = make(Params, 0, n.maxParams) value.params = make(Params, 0, n.maxParams)
} }
i := len(p) i := len(value.params)
p = p[:i+1] // expand slice within preallocated capacity value.params = value.params[:i+1] // expand slice within preallocated capacity
p[i].Key = n.path[1:] value.params[i].Key = n.path[1:]
val := path[:end] val := path[:end]
if unescape { if unescape {
var err error var err error
if p[i].Value, err = url.QueryUnescape(val); err != nil { if value.params[i].Value, err = url.QueryUnescape(val); err != nil {
p[i].Value = val // fallback, in case of error value.params[i].Value = val // fallback, in case of error
} }
} else { } else {
p[i].Value = val value.params[i].Value = val
} }
// we need to go deeper! // we need to go deeper!
@ -431,40 +437,40 @@ walk: // Outer loop for walking the tree
} }
// ... but we can't // ... but we can't
tsr = len(path) == end+1 value.tsr = len(path) == end+1
return return
} }
if handlers = n.handlers; handlers != nil { if value.handlers = n.handlers; value.handlers != nil {
return return
} }
if len(n.children) == 1 { if len(n.children) == 1 {
// No handle found. Check if a handle for this path + a // No handle found. Check if a handle for this path + a
// trailing slash exists for TSR recommendation // trailing slash exists for TSR recommendation
n = n.children[0] n = n.children[0]
tsr = n.path == "/" && n.handlers != nil value.tsr = n.path == "/" && n.handlers != nil
} }
return return
case catchAll: case catchAll:
// save param value // save param value
if cap(p) < int(n.maxParams) { if cap(value.params) < int(n.maxParams) {
p = make(Params, 0, n.maxParams) value.params = make(Params, 0, n.maxParams)
} }
i := len(p) i := len(value.params)
p = p[:i+1] // expand slice within preallocated capacity value.params = value.params[:i+1] // expand slice within preallocated capacity
p[i].Key = n.path[2:] value.params[i].Key = n.path[2:]
if unescape { if unescape {
var err error var err error
if p[i].Value, err = url.QueryUnescape(path); err != nil { if value.params[i].Value, err = url.QueryUnescape(path); err != nil {
p[i].Value = path // fallback, in case of error value.params[i].Value = path // fallback, in case of error
} }
} else { } else {
p[i].Value = path value.params[i].Value = path
} }
handlers = n.handlers value.handlers = n.handlers
return return
default: default:
@ -474,12 +480,12 @@ walk: // Outer loop for walking the tree
} else if path == n.path { } else if path == n.path {
// We should have reached the node containing the handle. // We should have reached the node containing the handle.
// Check if this node has a handle registered. // Check if this node has a handle registered.
if handlers = n.handlers; handlers != nil { if value.handlers = n.handlers; value.handlers != nil {
return return
} }
if path == "/" && n.wildChild && n.nType != root { if path == "/" && n.wildChild && n.nType != root {
tsr = true value.tsr = true
return return
} }
@ -488,7 +494,7 @@ walk: // Outer loop for walking the tree
for i := 0; i < len(n.indices); i++ { for i := 0; i < len(n.indices); i++ {
if n.indices[i] == '/' { if n.indices[i] == '/' {
n = n.children[i] n = n.children[i]
tsr = (len(n.path) == 1 && n.handlers != nil) || value.tsr = (len(n.path) == 1 && n.handlers != nil) ||
(n.nType == catchAll && n.children[0].handlers != nil) (n.nType == catchAll && n.children[0].handlers != nil)
return return
} }
@ -499,7 +505,7 @@ walk: // Outer loop for walking the tree
// Nothing found. We can recommend to redirect to the same URL with an // Nothing found. We can recommend to redirect to the same URL with an
// extra trailing slash if a leaf exists for that path // extra trailing slash if a leaf exists for that path
tsr = (path == "/") || value.tsr = (path == "/") ||
(len(n.path) == len(path)+1 && n.path[len(path)] == '/' && (len(n.path) == len(path)+1 && n.path[len(path)] == '/' &&
path == n.path[:len(n.path)-1] && n.handlers != nil) path == n.path[:len(n.path)-1] && n.handlers != nil)
return return

View File

@ -35,22 +35,22 @@ func checkRequests(t *testing.T, tree *node, requests testRequests, unescapes ..
} }
for _, request := range requests { for _, request := range requests {
handler, ps, _ := tree.getValue(request.path, nil, unescape) value := tree.getValue(request.path, nil, unescape)
if handler == nil { if value.handlers == nil {
if !request.nilHandler { if !request.nilHandler {
t.Errorf("handle mismatch for route '%s': Expected non-nil handle", request.path) t.Errorf("handle mismatch for route '%s': Expected non-nil handle", request.path)
} }
} else if request.nilHandler { } else if request.nilHandler {
t.Errorf("handle mismatch for route '%s': Expected nil handle", request.path) t.Errorf("handle mismatch for route '%s': Expected nil handle", request.path)
} else { } else {
handler[0](nil) value.handlers[0](nil)
if fakeHandlerValue != request.route { if fakeHandlerValue != request.route {
t.Errorf("handle mismatch for route '%s': Wrong handle (%s != %s)", request.path, fakeHandlerValue, request.route) t.Errorf("handle mismatch for route '%s': Wrong handle (%s != %s)", request.path, fakeHandlerValue, request.route)
} }
} }
if !reflect.DeepEqual(ps, request.ps) { if !reflect.DeepEqual(value.params, request.ps) {
t.Errorf("Params mismatch for route '%s'", request.path) t.Errorf("Params mismatch for route '%s'", request.path)
} }
} }
@ -454,10 +454,10 @@ func TestTreeTrailingSlashRedirect(t *testing.T) {
"/doc/", "/doc/",
} }
for _, route := range tsrRoutes { for _, route := range tsrRoutes {
handler, _, tsr := tree.getValue(route, nil, false) value := tree.getValue(route, nil, false)
if handler != nil { if value.handlers != nil {
t.Fatalf("non-nil handler for TSR route '%s", route) t.Fatalf("non-nil handler for TSR route '%s", route)
} else if !tsr { } else if !value.tsr {
t.Errorf("expected TSR recommendation for route '%s'", route) t.Errorf("expected TSR recommendation for route '%s'", route)
} }
} }
@ -471,10 +471,10 @@ func TestTreeTrailingSlashRedirect(t *testing.T) {
"/api/world/abc", "/api/world/abc",
} }
for _, route := range noTsrRoutes { for _, route := range noTsrRoutes {
handler, _, tsr := tree.getValue(route, nil, false) value := tree.getValue(route, nil, false)
if handler != nil { if value.handlers != nil {
t.Fatalf("non-nil handler for No-TSR route '%s", route) t.Fatalf("non-nil handler for No-TSR route '%s", route)
} else if tsr { } else if value.tsr {
t.Errorf("expected no TSR recommendation for route '%s'", route) t.Errorf("expected no TSR recommendation for route '%s'", route)
} }
} }
@ -490,10 +490,10 @@ func TestTreeRootTrailingSlashRedirect(t *testing.T) {
t.Fatalf("panic inserting test route: %v", recv) t.Fatalf("panic inserting test route: %v", recv)
} }
handler, _, tsr := tree.getValue("/", nil, false) value := tree.getValue("/", nil, false)
if handler != nil { if value.handlers != nil {
t.Fatalf("non-nil handler") t.Fatalf("non-nil handler")
} else if tsr { } else if value.tsr {
t.Errorf("expected no TSR recommendation") t.Errorf("expected no TSR recommendation")
} }
} }