mirror of https://github.com/gin-gonic/gin.git
parent
334160bab7
commit
4621b7ac98
25
gin.go
25
gin.go
|
@ -24,6 +24,9 @@ import (
|
||||||
)
|
)
|
||||||
|
|
||||||
const defaultMultipartMemory = 32 << 20 // 32 MB
|
const defaultMultipartMemory = 32 << 20 // 32 MB
|
||||||
|
const escapedColon = "\\:"
|
||||||
|
const colon = ":"
|
||||||
|
const backslash = "\\"
|
||||||
|
|
||||||
var (
|
var (
|
||||||
default404Body = []byte("404 page not found")
|
default404Body = []byte("404 page not found")
|
||||||
|
@ -474,6 +477,26 @@ func (engine *Engine) validateHeader(header string) (clientIP string, valid bool
|
||||||
return "", false
|
return "", false
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// updateRouteTree do update to the route tree recursively
|
||||||
|
func updateRouteTree(n *node) {
|
||||||
|
n.path = strings.ReplaceAll(n.path, escapedColon, colon)
|
||||||
|
n.fullPath = strings.ReplaceAll(n.fullPath, escapedColon, colon)
|
||||||
|
n.indices = strings.ReplaceAll(n.indices, backslash, colon)
|
||||||
|
if n.children == nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
for _, child := range n.children {
|
||||||
|
updateRouteTree(child)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// updateRouteTrees do update to the route trees
|
||||||
|
func (engine *Engine) updateRouteTrees() {
|
||||||
|
for _, tree := range engine.trees {
|
||||||
|
updateRouteTree(tree.root)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// parseIP parse a string representation of an IP and returns a net.IP with the
|
// parseIP parse a string representation of an IP and returns a net.IP with the
|
||||||
// minimum byte representation or nil if input is invalid.
|
// minimum byte representation or nil if input is invalid.
|
||||||
func parseIP(ip string) net.IP {
|
func parseIP(ip string) net.IP {
|
||||||
|
@ -498,7 +521,7 @@ func (engine *Engine) Run(addr ...string) (err error) {
|
||||||
debugPrint("[WARNING] You trusted all proxies, this is NOT safe. We recommend you to set a value.\n" +
|
debugPrint("[WARNING] You trusted all proxies, this is NOT safe. We recommend you to set a value.\n" +
|
||||||
"Please check https://github.com/gin-gonic/gin/blob/master/docs/doc.md#dont-trust-all-proxies for details.")
|
"Please check https://github.com/gin-gonic/gin/blob/master/docs/doc.md#dont-trust-all-proxies for details.")
|
||||||
}
|
}
|
||||||
|
engine.updateRouteTrees()
|
||||||
address := resolveAddress(addr)
|
address := resolveAddress(addr)
|
||||||
debugPrint("Listening and serving HTTP on %s\n", address)
|
debugPrint("Listening and serving HTTP on %s\n", address)
|
||||||
err = http.ListenAndServe(address, engine.Handler())
|
err = http.ListenAndServe(address, engine.Handler())
|
||||||
|
|
|
@ -577,3 +577,28 @@ func TestTreeRunDynamicRouting(t *testing.T) {
|
||||||
func isWindows() bool {
|
func isWindows() bool {
|
||||||
return runtime.GOOS == "windows"
|
return runtime.GOOS == "windows"
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestEscapedColon(t *testing.T) {
|
||||||
|
router := New()
|
||||||
|
f := func(u string) {
|
||||||
|
router.GET(u, func(c *Context) { c.String(http.StatusOK, u) })
|
||||||
|
}
|
||||||
|
f("/r/r\\:r")
|
||||||
|
f("/r/r:r")
|
||||||
|
f("/r/r/:r")
|
||||||
|
f("/r/r/\\:r")
|
||||||
|
f("/r/r/r\\:r")
|
||||||
|
assert.Panics(t, func() {
|
||||||
|
f("\\foo:")
|
||||||
|
})
|
||||||
|
|
||||||
|
router.updateRouteTrees()
|
||||||
|
ts := httptest.NewServer(router)
|
||||||
|
defer ts.Close()
|
||||||
|
|
||||||
|
testRequest(t, ts.URL+"/r/r123", "", "/r/r:r")
|
||||||
|
testRequest(t, ts.URL+"/r/r:r", "", "/r/r\\:r")
|
||||||
|
testRequest(t, ts.URL+"/r/r/r123", "", "/r/r/:r")
|
||||||
|
testRequest(t, ts.URL+"/r/r/:r", "", "/r/r/\\:r")
|
||||||
|
testRequest(t, ts.URL+"/r/r/r:r", "", "/r/r/r\\:r")
|
||||||
|
}
|
||||||
|
|
12
tree.go
12
tree.go
|
@ -262,7 +262,19 @@ walk:
|
||||||
// Returns -1 as index, if no wildcard was found.
|
// Returns -1 as index, if no wildcard was found.
|
||||||
func findWildcard(path string) (wildcard string, i int, valid bool) {
|
func findWildcard(path string) (wildcard string, i int, valid bool) {
|
||||||
// Find start
|
// Find start
|
||||||
|
escapeColon := false
|
||||||
for start, c := range []byte(path) {
|
for start, c := range []byte(path) {
|
||||||
|
if escapeColon {
|
||||||
|
escapeColon = false
|
||||||
|
if c == ':' {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
panic("invalid escape string in path '" + path + "'")
|
||||||
|
}
|
||||||
|
if c == '\\' {
|
||||||
|
escapeColon = true
|
||||||
|
continue
|
||||||
|
}
|
||||||
// A wildcard starts with ':' (param) or '*' (catch-all)
|
// A wildcard starts with ':' (param) or '*' (catch-all)
|
||||||
if c != ':' && c != '*' {
|
if c != ':' && c != '*' {
|
||||||
continue
|
continue
|
||||||
|
|
22
tree_test.go
22
tree_test.go
|
@ -192,6 +192,7 @@ func TestTreeWildcard(t *testing.T) {
|
||||||
"/get/abc/123abg/:param",
|
"/get/abc/123abg/:param",
|
||||||
"/get/abc/123abf/:param",
|
"/get/abc/123abf/:param",
|
||||||
"/get/abc/123abfff/:param",
|
"/get/abc/123abfff/:param",
|
||||||
|
"/get/abc/escaped_colon/test\\:param",
|
||||||
}
|
}
|
||||||
for _, route := range routes {
|
for _, route := range routes {
|
||||||
tree.addRoute(route, fakeHandler(route))
|
tree.addRoute(route, fakeHandler(route))
|
||||||
|
@ -315,6 +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"}}},
|
||||||
|
{"/get/abc/escaped_colon/test\\:param", false, "/get/abc/escaped_colon/test\\:param", nil},
|
||||||
})
|
})
|
||||||
|
|
||||||
checkPriorities(t, tree)
|
checkPriorities(t, tree)
|
||||||
|
@ -419,6 +421,9 @@ func TestTreeWildcardConflict(t *testing.T) {
|
||||||
{"/id/:id", false},
|
{"/id/:id", false},
|
||||||
{"/static/*file", false},
|
{"/static/*file", false},
|
||||||
{"/static/", true},
|
{"/static/", true},
|
||||||
|
{"/escape/test\\:d1", false},
|
||||||
|
{"/escape/test\\:d2", false},
|
||||||
|
{"/escape/test:param", false},
|
||||||
}
|
}
|
||||||
testRoutes(t, routes)
|
testRoutes(t, routes)
|
||||||
}
|
}
|
||||||
|
@ -971,3 +976,20 @@ func TestTreeWildcardConflictEx(t *testing.T) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestTreeInvalidEscape(t *testing.T) {
|
||||||
|
routes := map[string]bool{
|
||||||
|
"/r1/r": true,
|
||||||
|
"/r2/:r": true,
|
||||||
|
"/r3/\\:r": true,
|
||||||
|
}
|
||||||
|
tree := &node{}
|
||||||
|
for route, valid := range routes {
|
||||||
|
recv := catchPanic(func() {
|
||||||
|
tree.addRoute(route, fakeHandler(route))
|
||||||
|
})
|
||||||
|
if recv == nil != valid {
|
||||||
|
t.Fatalf("%s should be %t but got %v", route, valid, recv)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
Loading…
Reference in New Issue