diff --git a/tree.go b/tree.go index 88f25fcb..96b63d1b 100644 --- a/tree.go +++ b/tree.go @@ -272,7 +272,19 @@ func findWildcard(path string) (wildcard string, i int, valid bool) { // Find end and check for invalid characters valid = true + escapeNextColon := false for end, c := range []byte(path[start+1:]) { + if escapeNextColon { + escapeNextColon = false + if c == ':' { + continue + } + panic("invalid escape string in path '" + path + "'") + } + if c == '\\' { + escapeNextColon = true + continue + } switch c { case '/': return path[start : start+1+end], start, valid diff --git a/tree_test.go b/tree_test.go index b580007d..28cdf248 100644 --- a/tree_test.go +++ b/tree_test.go @@ -1018,3 +1018,29 @@ func TestWildcardInvalidSlash(t *testing.T) { } } } + +func TestTreeEscapedColon(t *testing.T) { + routes := map[string]bool{ + "/files/:id\\:undelete": true, + "/api/:resource\\:method": true, + "/escape/\\:static": true, + "/invalid/\\x": false, + } + + for route, valid := range routes { + tree := &node{} + recv := catchPanic(func() { + tree.addRoute(route, fakeHandler(route)) + }) + + if recv == nil != valid { + t.Fatalf("%s should be %t but got %v", route, valid, recv) + } + + if recv != nil { + if rs, ok := recv.(string); !ok || !strings.Contains(rs, "invalid escape") { + t.Fatalf(`Expected panic with "invalid escape" for route '%s', got "%v"`, route, recv) + } + } + } +}