Merge 3f436fce7eaaf109defa67c8646e69ba971015a1 into 857db39f82fb82456af2906ccea972ae1d65ff57

This commit is contained in:
Matheus Meneses 2024-01-26 15:17:14 +01:00 committed by GitHub
commit c1e4457e58
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
4 changed files with 45 additions and 18 deletions

1
.gitignore vendored
View File

@ -5,3 +5,4 @@ count.out
test test
profile.out profile.out
tmp.out tmp.out
*.iml

4
gin.go
View File

@ -609,7 +609,7 @@ func (engine *Engine) handleHTTPRequest(c *Context) {
} }
root := t[i].root root := t[i].root
// Find route in tree // Find route in tree
value := root.getValue(rPath, c.params, c.skippedNodes, unescape) value := root.getValue(rPath, c.params, c.skippedNodes, unescape, engine.RedirectFixedPath)
if value.params != nil { if value.params != nil {
c.Params = *value.params c.Params = *value.params
} }
@ -637,7 +637,7 @@ func (engine *Engine) handleHTTPRequest(c *Context) {
if tree.method == httpMethod { if tree.method == httpMethod {
continue continue
} }
if value := tree.root.getValue(rPath, nil, c.skippedNodes, unescape); value.handlers != nil { if value := tree.root.getValue(rPath, nil, c.skippedNodes, unescape, engine.RedirectFixedPath); value.handlers != nil {
c.handlers = engine.allNoMethod c.handlers = engine.allNoMethod
serveError(c, http.StatusMethodNotAllowed, default405Body) serveError(c, http.StatusMethodNotAllowed, default405Body)
return return

35
tree.go
View File

@ -417,7 +417,7 @@ type skippedNode struct {
// 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, params *Params, skippedNodes *[]skippedNode, unescape bool) (value nodeValue) { func (n *node) getValue(path string, params *Params, skippedNodes *[]skippedNode, unescape, redirectFixedPath bool) (value nodeValue) {
var globalParamsCount int16 var globalParamsCount int16
walk: // Outer loop for walking the tree walk: // Outer loop for walking the tree
@ -513,8 +513,20 @@ walk: // Outer loop for walking the tree
*value.params = (*value.params)[:i+1] *value.params = (*value.params)[:i+1]
val := path[:end] val := path[:end]
if unescape { if unescape {
if v, err := url.QueryUnescape(val); err == nil { v := val
val = v for {
beforeDecoding := v
decoded, err := url.QueryUnescape(v)
if err == nil {
v = decoded
}
if beforeDecoding == v || err != nil {
val = v
break
}
}
if redirectFixedPath {
val = cleanPath(val)
} }
} }
(*value.params)[i] = Param{ (*value.params)[i] = Param{
@ -566,8 +578,21 @@ walk: // Outer loop for walking the tree
*value.params = (*value.params)[:i+1] *value.params = (*value.params)[:i+1]
val := path val := path
if unescape { if unescape {
if v, err := url.QueryUnescape(path); err == nil { v := val
val = v for {
beforeDecoding := v
if decoded, err := url.QueryUnescape(v); err == nil {
v = decoded
} else {
break
}
if beforeDecoding == v {
val = v
break
}
}
if redirectFixedPath {
val = cleanPath(val)
} }
} }
(*value.params)[i] = Param{ (*value.params)[i] = Param{

View File

@ -38,14 +38,15 @@ func getSkippedNodes() *[]skippedNode {
return &ps return &ps
} }
func checkRequests(t *testing.T, tree *node, requests testRequests, unescapes ...bool) { func checkRequests(t *testing.T, tree *node, requests testRequests, redirectFixedPath bool, unescapes ...bool) {
unescape := false unescape := false
if len(unescapes) >= 1 { if len(unescapes) >= 1 {
unescape = unescapes[0] unescape = unescapes[0]
} }
for _, request := range requests { for _, request := range requests {
value := tree.getValue(request.path, getParams(), getSkippedNodes(), unescape) value := tree.getValue(request.path, getParams(), getSkippedNodes(), unescape, redirectFixedPath)
if value.handlers == nil { if value.handlers == nil {
if !request.nilHandler { if !request.nilHandler {
@ -130,7 +131,7 @@ func TestTreeAddAndGet(t *testing.T) {
{"/ab", false, "/ab", nil}, {"/ab", false, "/ab", nil},
{"/α", false, "/α", nil}, {"/α", false, "/α", nil},
{"/β", false, "/β", nil}, {"/β", false, "/β", nil},
}) }, false)
checkPriorities(t, tree) checkPriorities(t, tree)
} }
@ -315,7 +316,7 @@ func TestTreeWildcard(t *testing.T) {
{"/get/abc/123abg/test", false, "/get/abc/123abg/:param", Params{Param{Key: "param", Value: "test"}}}, {"/get/abc/123abg/test", false, "/get/abc/123abg/:param", Params{Param{Key: "param", Value: "test"}}},
{"/get/abc/123abf/testss", false, "/get/abc/123abf/:param", Params{Param{Key: "param", Value: "testss"}}}, {"/get/abc/123abf/testss", false, "/get/abc/123abf/:param", Params{Param{Key: "param", Value: "testss"}}},
{"/get/abc/123abfff/te", false, "/get/abc/123abfff/:param", Params{Param{Key: "param", Value: "te"}}}, {"/get/abc/123abfff/te", false, "/get/abc/123abfff/:param", Params{Param{Key: "param", Value: "te"}}},
}) }, false)
checkPriorities(t, tree) checkPriorities(t, tree)
} }
@ -352,7 +353,7 @@ func TestUnescapeParameters(t *testing.T) {
{"/info/slash%2Fgordon/project/Project%20%231", false, "/info/:user/project/:project", Params{Param{Key: "user", Value: "slash/gordon"}, Param{Key: "project", Value: "Project #1"}}}, {"/info/slash%2Fgordon/project/Project%20%231", false, "/info/:user/project/:project", Params{Param{Key: "user", Value: "slash/gordon"}, Param{Key: "project", Value: "Project #1"}}},
{"/info/slash%%%%", false, "/info/:user", Params{Param{Key: "user", Value: "slash%%%%"}}}, {"/info/slash%%%%", false, "/info/:user", Params{Param{Key: "user", Value: "slash%%%%"}}},
{"/info/slash%%%%2Fgordon/project/Project%%%%20%231", false, "/info/:user/project/:project", Params{Param{Key: "user", Value: "slash%%%%2Fgordon"}, Param{Key: "project", Value: "Project%%%%20%231"}}}, {"/info/slash%%%%2Fgordon/project/Project%%%%20%231", false, "/info/:user/project/:project", Params{Param{Key: "user", Value: "slash%%%%2Fgordon"}, Param{Key: "project", Value: "Project%%%%20%231"}}},
}, unescape) }, false, unescape)
checkPriorities(t, tree) checkPriorities(t, tree)
} }
@ -482,7 +483,7 @@ func TestTreeDuplicatePath(t *testing.T) {
{"/src/some/file.png", false, "/src/*filepath", Params{Param{"filepath", "/some/file.png"}}}, {"/src/some/file.png", false, "/src/*filepath", Params{Param{"filepath", "/some/file.png"}}},
{"/search/someth!ng+in+ünìcodé", false, "/search/:query", Params{Param{"query", "someth!ng+in+ünìcodé"}}}, {"/search/someth!ng+in+ünìcodé", false, "/search/:query", Params{Param{"query", "someth!ng+in+ünìcodé"}}},
{"/user_gopher", false, "/user_:name", Params{Param{"name", "gopher"}}}, {"/user_gopher", false, "/user_:name", Params{Param{"name", "gopher"}}},
}) }, false)
} }
func TestEmptyWildcardName(t *testing.T) { func TestEmptyWildcardName(t *testing.T) {
@ -636,7 +637,7 @@ func TestTreeTrailingSlashRedirect(t *testing.T) {
} }
for _, route := range tsrRoutes { for _, route := range tsrRoutes {
value := tree.getValue(route, nil, getSkippedNodes(), false) value := tree.getValue(route, nil, getSkippedNodes(), false, false)
if value.handlers != 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 !value.tsr { } else if !value.tsr {
@ -657,7 +658,7 @@ func TestTreeTrailingSlashRedirect(t *testing.T) {
"/foo/p/p", "/foo/p/p",
} }
for _, route := range noTsrRoutes { for _, route := range noTsrRoutes {
value := tree.getValue(route, nil, getSkippedNodes(), false) value := tree.getValue(route, nil, getSkippedNodes(), false, false)
if value.handlers != 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 value.tsr { } else if value.tsr {
@ -676,7 +677,7 @@ func TestTreeRootTrailingSlashRedirect(t *testing.T) {
t.Fatalf("panic inserting test route: %v", recv) t.Fatalf("panic inserting test route: %v", recv)
} }
value := tree.getValue("/", nil, getSkippedNodes(), false) value := tree.getValue("/", nil, getSkippedNodes(), false, false)
if value.handlers != nil { if value.handlers != nil {
t.Fatalf("non-nil handler") t.Fatalf("non-nil handler")
} else if value.tsr { } else if value.tsr {
@ -876,7 +877,7 @@ func TestTreeInvalidNodeType(t *testing.T) {
// normal lookup // normal lookup
recv := catchPanic(func() { recv := catchPanic(func() {
tree.getValue("/test", nil, getSkippedNodes(), false) tree.getValue("/test", nil, getSkippedNodes(), false, false)
}) })
if rs, ok := recv.(string); !ok || rs != panicMsg { if rs, ok := recv.(string); !ok || rs != panicMsg {
t.Fatalf("Expected panic '"+panicMsg+"', got '%v'", recv) t.Fatalf("Expected panic '"+panicMsg+"', got '%v'", recv)
@ -901,7 +902,7 @@ func TestTreeInvalidParamsType(t *testing.T) {
params := make(Params, 0) params := make(Params, 0)
// try to trigger slice bounds out of range with capacity 0 // try to trigger slice bounds out of range with capacity 0
tree.getValue("/test", &params, getSkippedNodes(), false) tree.getValue("/test", &params, getSkippedNodes(), false, false)
} }
func TestTreeExpandParamsCapacity(t *testing.T) { func TestTreeExpandParamsCapacity(t *testing.T) {