Skip to content

RFE: add ability to register routes with parameters containing unescaped slashes #2034

Open
@Snaipe

Description

@Snaipe

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)

Metadata

Metadata

Assignees

Type

No type

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions