Skip to content

Commit 2e6a3ff

Browse files
committed
Add literal colon support (#1432)
1 parent a550c56 commit 2e6a3ff

File tree

3 files changed

+44
-1
lines changed

3 files changed

+44
-1
lines changed

gin.go

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,9 @@ import (
1919
)
2020

2121
const defaultMultipartMemory = 32 << 20 // 32 MB
22+
const escapedColon = "\\:"
23+
const colon = ":"
24+
const backslash = "\\"
2225

2326
var (
2427
default404Body = []byte("404 page not found")
@@ -345,6 +348,7 @@ func (engine *Engine) Run(addr ...string) (err error) {
345348
if err != nil {
346349
return err
347350
}
351+
engine.updateRouteTrees()
348352

349353
address := resolveAddress(addr)
350354
debugPrint("Listening and serving HTTP on %s\n", address)
@@ -394,6 +398,25 @@ func (engine *Engine) parseTrustedProxies() error {
394398
return err
395399
}
396400

401+
// updateRouteTree do update to the route tree recursively
402+
func updateRouteTree(n *node) {
403+
n.path = strings.ReplaceAll(n.path, escapedColon, colon)
404+
n.fullPath = strings.ReplaceAll(n.fullPath, escapedColon, colon)
405+
n.indices = strings.ReplaceAll(n.indices, backslash, colon)
406+
if n.children != nil {
407+
for _, child := range n.children {
408+
updateRouteTree(child)
409+
}
410+
}
411+
}
412+
413+
// updateRouteTrees do update to the route trees
414+
func (engine *Engine) updateRouteTrees() {
415+
for _, tree := range engine.trees {
416+
updateRouteTree(tree.root)
417+
}
418+
}
419+
397420
// parseIP parse a string representation of an IP and returns a net.IP with the
398421
// minimum byte representation or nil if input is invalid.
399422
func parseIP(ip string) net.IP {

tree.go

Lines changed: 16 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -261,7 +261,20 @@ walk:
261261
// Returns -1 as index, if no wildcard was found.
262262
func findWildcard(path string) (wildcard string, i int, valid bool) {
263263
// Find start
264+
escapeColon := false
264265
for start, c := range []byte(path) {
266+
if escapeColon {
267+
if c == ':' {
268+
escapeColon = false
269+
continue
270+
} else {
271+
panic("invalid escaped char in " + path)
272+
}
273+
}
274+
if c == '\\' {
275+
escapeColon = true
276+
continue
277+
}
265278
// A wildcard starts with ':' (param) or '*' (catch-all)
266279
if c != ':' && c != '*' {
267280
continue
@@ -402,6 +415,7 @@ func (n *node) getValue(path string, params *Params, unescape bool) (value nodeV
402415
var (
403416
skippedPath string
404417
latestNode = n // Caching the latest node
418+
latestPath = path
405419
)
406420

407421
walk: // Outer loop for walking the tree
@@ -427,6 +441,7 @@ walk: // Outer loop for walking the tree
427441
handlers: n.handlers,
428442
fullPath: n.fullPath,
429443
}
444+
latestPath = path
430445
}
431446

432447
n = n.children[i]
@@ -457,7 +472,7 @@ walk: // Outer loop for walking the tree
457472
// fix truncate the parameter
458473
// tree_test.go line: 204
459474
if matched {
460-
path = prefix + path
475+
path = latestPath
461476
// The saved path is used after the prefix route is intercepted by matching
462477
if n.indices == "/" {
463478
path = skippedPath[1:]

tree_test.go

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -185,6 +185,7 @@ func TestTreeWildcard(t *testing.T) {
185185
"/get/abc/123abg/:param",
186186
"/get/abc/123abf/:param",
187187
"/get/abc/123abfff/:param",
188+
"/get/abc/escaped_colon/test\\:param",
188189
}
189190
for _, route := range routes {
190191
tree.addRoute(route, fakeHandler(route))
@@ -305,6 +306,7 @@ func TestTreeWildcard(t *testing.T) {
305306
{"/get/abc/123abg/test", false, "/get/abc/123abg/:param", Params{Param{Key: "param", Value: "test"}}},
306307
{"/get/abc/123abf/testss", false, "/get/abc/123abf/:param", Params{Param{Key: "param", Value: "testss"}}},
307308
{"/get/abc/123abfff/te", false, "/get/abc/123abfff/:param", Params{Param{Key: "param", Value: "te"}}},
309+
{"/get/abc/escaped_colon/test\\:param", false, "/get/abc/escaped_colon/test\\:param", nil},
308310
})
309311

310312
checkPriorities(t, tree)
@@ -407,6 +409,9 @@ func TestTreeWildcardConflict(t *testing.T) {
407409
{"/user_:name", false},
408410
{"/id:id", false},
409411
{"/id/:id", false},
412+
{"/escape/test\\:d1", false},
413+
{"/escape/test\\:d2", false},
414+
{"/escape/test:param", false},
410415
}
411416
testRoutes(t, routes)
412417
}

0 commit comments

Comments
 (0)