Skip to content

Commit 9fc4672

Browse files
authored
Allow escaping of colon in route path so Google Cloud API "custom methods" https://cloud.google.com/apis/design/custom_methods can be implemented (resolves #1987) (#1988)
Allow escaping of colon in route path so Google Cloud API "custom methods" https://cloud.google.com/apis/design/custom_methods could be implemented (resolves #1987)
1 parent f6b45f2 commit 9fc4672

File tree

2 files changed

+55
-0
lines changed

2 files changed

+55
-0
lines changed

router.go

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -98,6 +98,9 @@ func (r *Router) Add(method, path string, h HandlerFunc) {
9898

9999
for i, lcpIndex := 0, len(path); i < lcpIndex; i++ {
100100
if path[i] == ':' {
101+
if i > 0 && path[i-1] == '\\' {
102+
continue
103+
}
101104
j := i + 1
102105

103106
r.insert(method, path[:i], nil, staticKind, "", nil)

router_test.go

Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1118,6 +1118,58 @@ func TestRouterParamStaticConflict(t *testing.T) {
11181118
}
11191119
}
11201120

1121+
func TestRouterParam_escapeColon(t *testing.T) {
1122+
// to allow Google cloud API like route paths with colon in them
1123+
// i.e. https://service.name/v1/some/resource/name:customVerb <- that `:customVerb` is not path param. It is just a string
1124+
e := New()
1125+
1126+
e.POST("/files/a/long/file\\:undelete", handlerFunc)
1127+
e.POST("/v1/some/resource/name:customVerb", handlerFunc)
1128+
1129+
var testCases = []struct {
1130+
whenURL string
1131+
expectRoute interface{}
1132+
expectParam map[string]string
1133+
expectError string
1134+
}{
1135+
{
1136+
whenURL: "/files/a/long/file\\:undelete",
1137+
expectRoute: "/files/a/long/file\\:undelete",
1138+
expectParam: map[string]string{},
1139+
},
1140+
{
1141+
whenURL: "/files/a/long/file\\:notMatching",
1142+
expectRoute: nil,
1143+
expectError: "code=404, message=Not Found",
1144+
expectParam: nil,
1145+
},
1146+
{
1147+
whenURL: "/v1/some/resource/name:PATCH",
1148+
expectRoute: "/v1/some/resource/name:customVerb",
1149+
expectParam: map[string]string{"customVerb": ":PATCH"},
1150+
},
1151+
}
1152+
for _, tc := range testCases {
1153+
t.Run(tc.whenURL, func(t *testing.T) {
1154+
c := e.NewContext(nil, nil).(*context)
1155+
1156+
e.router.Find(http.MethodPost, tc.whenURL, c)
1157+
err := c.handler(c)
1158+
1159+
assert.Equal(t, tc.expectRoute, c.Get("path"))
1160+
if tc.expectError != "" {
1161+
assert.EqualError(t, err, tc.expectError)
1162+
} else {
1163+
assert.NoError(t, err)
1164+
}
1165+
for param, expectedValue := range tc.expectParam {
1166+
assert.Equal(t, expectedValue, c.Param(param))
1167+
}
1168+
checkUnusedParamValues(t, c, tc.expectParam)
1169+
})
1170+
}
1171+
}
1172+
11211173
func TestRouterMatchAny(t *testing.T) {
11221174
e := New()
11231175
r := e.router

0 commit comments

Comments
 (0)