mirror of
https://github.com/gin-gonic/gin.git
synced 2025-10-16 13:22:09 +08:00
prevent double enconding in path parameters
This commit is contained in:
parent
c4580944ae
commit
250a4efe03
1
.gitignore
vendored
1
.gitignore
vendored
@ -5,3 +5,4 @@ count.out
|
|||||||
test
|
test
|
||||||
profile.out
|
profile.out
|
||||||
tmp.out
|
tmp.out
|
||||||
|
*.iml
|
||||||
|
4
gin.go
4
gin.go
@ -603,7 +603,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
|
||||||
}
|
}
|
||||||
@ -631,7 +631,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
|
||||||
|
36
tree.go
36
tree.go
@ -415,7 +415,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
|
||||||
@ -504,8 +504,21 @@ 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
|
||||||
|
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{
|
||||||
@ -550,8 +563,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{
|
||||||
|
23
tree_test.go
23
tree_test.go
@ -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 {
|
||||||
@ -856,7 +857,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)
|
||||||
@ -881,7 +882,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", ¶ms, getSkippedNodes(), false)
|
tree.getValue("/test", ¶ms, getSkippedNodes(), false, false)
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestTreeWildcardConflictEx(t *testing.T) {
|
func TestTreeWildcardConflictEx(t *testing.T) {
|
||||||
|
Loading…
x
Reference in New Issue
Block a user