Description
Issue Description
I've had to implement a small service implementing parts of the docker registry API; the issue is that multiple endpoints look like /v2/<repo>/manifests/<reference>
, where <repo>
may contain unescaped slashes. /v2/library/ubuntu/manifests/latest
is thus a valid endpoint to get the manifests of the latest tag for the library/ubuntu
repository.
The problem is that naively, Echo.GET("/v2/:repo/manifests/:reference")
doesn't work (which I expected), and Echo.GET("/v2/*/manifests/:reference")
does not work either, because reference
does not get recognized. Worse, if you go with the second form, and register another endpoint like "/v2/*/blobs/:digest"
, the second one starts matching paths like "/v2/repo/manifests/foobar"
.
It'd be great if this worked seamlessly. It doesn't seem crazy to have a greedy matching syntax for parameters that may contain slashes, like /v2/:*repo/manifests/:reference
-- regular expressions are able to do just that, in fact.
I've worked around this issue with a .Pre handler that rewrites the URL with path-escaped components based on a set of route-specific regular expressions:
// HACK: This tidbit of code here has the purpose of URL-escaping components
// that are allowed to contain slashes, based on the allowed set of routes.
// This is done to support URLs like /v2/library/ubuntu/manifests/latest
// without needing to URL-escape repo names client-side.
var escapes []*regexp.Regexp
escapes = append(escapes, regexp.MustCompile("^/v2/(.*)/manifests/(.*)$"))
escapes = append(escapes, regexp.MustCompile("^/v2/(.*)/blobs/(.*)$"))
e.Pre(func(handler echo.HandlerFunc) echo.HandlerFunc {
return func(c echo.Context) error {
reqpath := c.Request().URL.Path
for _, re := range escapes {
match := re.FindStringSubmatchIndex(reqpath)
if match == nil {
continue
}
indices := match[2:]
var rewritten strings.Builder
var prev int
for i := 0; i < len(indices); i += 2 {
lo, hi := indices[i], indices[i+1]
rewritten.WriteString(reqpath[prev:lo])
rewritten.WriteString(url.PathEscape(reqpath[lo:hi]))
prev = hi
}
rewritten.WriteString(reqpath[prev:])
c.Request().URL.Path = rewritten.String()
break
}
return handler(c)
}
})
Still, this is fairly half-baked, since the parameter values then need to be path-unescaped in the handler. It'd be nice if this was just plainly supported.
Checklist
- Dependencies installed
- No typos
- Searched existing issues and docs
Expected behaviour
Have a way to register routes with parameters containing unescaped slashes
Actual behaviour
Feature is missing
Steps to reproduce
(none, this is a feature request)
Working code to debug
(none, this is a feature request)
Version/commit
v4.6.1 (via go get)