Repository: ogen-go/ogen
Pull request #727 (2022-12-19 07:35:23)

feat(gen): add `FindPath` method


Patch:
diff --git a/examples/ex_2ch/oas_router_gen.go b/examples/ex_2ch/oas_router_gen.go
index cf8d5984..fb1eedbc 100644
--- a/examples/ex_2ch/oas_router_gen.go
+++ b/examples/ex_2ch/oas_router_gen.go
@@ -585,22 +585,30 @@ func (r Route) Args() []string {
 }
 
 // FindRoute finds Route for given method and path.
-func (s *Server) FindRoute(method, path string) (r Route, _ bool) {
+//
+// Note: this method does not unescape path or handle reserved characters in path properly. Use FindPath instead.
+func (s *Server) FindRoute(method, path string) (Route, bool) {
+	return s.FindPath(method, &url.URL{Path: path})
+}
+
+// FindPath finds Route for given method and URL.
+func (s *Server) FindPath(method string, u *url.URL) (r Route, _ bool) {
 	var (
-		args = [3]string{}
-		elem = path
+		elem = u.Path
+		args = r.args
 	)
-	r.args = args
-	if elem == "" {
-		return r, false
-	}
-	defer func() {
-		for i, arg := range r.args[:r.count] {
-			if unescaped, err := url.PathUnescape(arg); err == nil {
-				r.args[i] = unescaped
-			}
+	if rawPath := u.RawPath; rawPath != "" {
+		if normalized, ok := uri.NormalizeEscapedPath(rawPath); ok {
+			elem = normalized
 		}
-	}()
+		defer func() {
+			for i, arg := range r.args[:r.count] {
+				if unescaped, err := url.PathUnescape(arg); err == nil {
+					r.args[i] = unescaped
+				}
+			}
+		}()
+	}
 
 	// Static code generated router with unwrapped path search.
 	switch {
diff --git a/examples/ex_ent/oas_router_gen.go b/examples/ex_ent/oas_router_gen.go
index 199d54c8..2418ef2a 100644
--- a/examples/ex_ent/oas_router_gen.go
+++ b/examples/ex_ent/oas_router_gen.go
@@ -220,22 +220,30 @@ func (r Route) Args() []string {
 }
 
 // FindRoute finds Route for given method and path.
-func (s *Server) FindRoute(method, path string) (r Route, _ bool) {
+//
+// Note: this method does not unescape path or handle reserved characters in path properly. Use FindPath instead.
+func (s *Server) FindRoute(method, path string) (Route, bool) {
+	return s.FindPath(method, &url.URL{Path: path})
+}
+
+// FindPath finds Route for given method and URL.
+func (s *Server) FindPath(method string, u *url.URL) (r Route, _ bool) {
 	var (
-		args = [1]string{}
-		elem = path
+		elem = u.Path
+		args = r.args
 	)
-	r.args = args
-	if elem == "" {
-		return r, false
-	}
-	defer func() {
-		for i, arg := range r.args[:r.count] {
-			if unescaped, err := url.PathUnescape(arg); err == nil {
-				r.args[i] = unescaped
-			}
+	if rawPath := u.RawPath; rawPath != "" {
+		if normalized, ok := uri.NormalizeEscapedPath(rawPath); ok {
+			elem = normalized
 		}
-	}()
+		defer func() {
+			for i, arg := range r.args[:r.count] {
+				if unescaped, err := url.PathUnescape(arg); err == nil {
+					r.args[i] = unescaped
+				}
+			}
+		}()
+	}
 
 	// Static code generated router with unwrapped path search.
 	switch {
diff --git a/examples/ex_firecracker/oas_router_gen.go b/examples/ex_firecracker/oas_router_gen.go
index 90c9caa8..460013b5 100644
--- a/examples/ex_firecracker/oas_router_gen.go
+++ b/examples/ex_firecracker/oas_router_gen.go
@@ -467,22 +467,30 @@ func (r Route) Args() []string {
 }
 
 // FindRoute finds Route for given method and path.
-func (s *Server) FindRoute(method, path string) (r Route, _ bool) {
+//
+// Note: this method does not unescape path or handle reserved characters in path properly. Use FindPath instead.
+func (s *Server) FindRoute(method, path string) (Route, bool) {
+	return s.FindPath(method, &url.URL{Path: path})
+}
+
+// FindPath finds Route for given method and URL.
+func (s *Server) FindPath(method string, u *url.URL) (r Route, _ bool) {
 	var (
-		args = [1]string{}
-		elem = path
+		elem = u.Path
+		args = r.args
 	)
-	r.args = args
-	if elem == "" {
-		return r, false
-	}
-	defer func() {
-		for i, arg := range r.args[:r.count] {
-			if unescaped, err := url.PathUnescape(arg); err == nil {
-				r.args[i] = unescaped
-			}
+	if rawPath := u.RawPath; rawPath != "" {
+		if normalized, ok := uri.NormalizeEscapedPath(rawPath); ok {
+			elem = normalized
 		}
-	}()
+		defer func() {
+			for i, arg := range r.args[:r.count] {
+				if unescaped, err := url.PathUnescape(arg); err == nil {
+					r.args[i] = unescaped
+				}
+			}
+		}()
+	}
 
 	// Static code generated router with unwrapped path search.
 	switch {
diff --git a/examples/ex_github/oas_router_gen.go b/examples/ex_github/oas_router_gen.go
index e6bc0b35..e9e4d902 100644
--- a/examples/ex_github/oas_router_gen.go
+++ b/examples/ex_github/oas_router_gen.go
@@ -14593,22 +14593,30 @@ func (r Route) Args() []string {
 }
 
 // FindRoute finds Route for given method and path.
-func (s *Server) FindRoute(method, path string) (r Route, _ bool) {
+//
+// Note: this method does not unescape path or handle reserved characters in path properly. Use FindPath instead.
+func (s *Server) FindRoute(method, path string) (Route, bool) {
+	return s.FindPath(method, &url.URL{Path: path})
+}
+
+// FindPath finds Route for given method and URL.
+func (s *Server) FindPath(method string, u *url.URL) (r Route, _ bool) {
 	var (
-		args = [5]string{}
-		elem = path
+		elem = u.Path
+		args = r.args
 	)
-	r.args = args
-	if elem == "" {
-		return r, false
-	}
-	defer func() {
-		for i, arg := range r.args[:r.count] {
-			if unescaped, err := url.PathUnescape(arg); err == nil {
-				r.args[i] = unescaped
-			}
+	if rawPath := u.RawPath; rawPath != "" {
+		if normalized, ok := uri.NormalizeEscapedPath(rawPath); ok {
+			elem = normalized
 		}
-	}()
+		defer func() {
+			for i, arg := range r.args[:r.count] {
+				if unescaped, err := url.PathUnescape(arg); err == nil {
+					r.args[i] = unescaped
+				}
+			}
+		}()
+	}
 
 	// Static code generated router with unwrapped path search.
 	switch {
diff --git a/examples/ex_gotd/oas_router_gen.go b/examples/ex_gotd/oas_router_gen.go
index b4123bb6..70716b54 100644
--- a/examples/ex_gotd/oas_router_gen.go
+++ b/examples/ex_gotd/oas_router_gen.go
@@ -2121,22 +2121,30 @@ func (r Route) Args() []string {
 }
 
 // FindRoute finds Route for given method and path.
-func (s *Server) FindRoute(method, path string) (r Route, _ bool) {
+//
+// Note: this method does not unescape path or handle reserved characters in path properly. Use FindPath instead.
+func (s *Server) FindRoute(method, path string) (Route, bool) {
+	return s.FindPath(method, &url.URL{Path: path})
+}
+
+// FindPath finds Route for given method and URL.
+func (s *Server) FindPath(method string, u *url.URL) (r Route, _ bool) {
 	var (
-		args = [0]string{}
-		elem = path
+		elem = u.Path
+		args = r.args
 	)
-	r.args = args
-	if elem == "" {
-		return r, false
-	}
-	defer func() {
-		for i, arg := range r.args[:r.count] {
-			if unescaped, err := url.PathUnescape(arg); err == nil {
-				r.args[i] = unescaped
-			}
+	if rawPath := u.RawPath; rawPath != "" {
+		if normalized, ok := uri.NormalizeEscapedPath(rawPath); ok {
+			elem = normalized
 		}
-	}()
+		defer func() {
+			for i, arg := range r.args[:r.count] {
+				if unescaped, err := url.PathUnescape(arg); err == nil {
+					r.args[i] = unescaped
+				}
+			}
+		}()
+	}
 
 	// Static code generated router with unwrapped path search.
 	switch {
diff --git a/examples/ex_k8s/oas_router_gen.go b/examples/ex_k8s/oas_router_gen.go
index a42eea2f..6ba81b87 100644
--- a/examples/ex_k8s/oas_router_gen.go
+++ b/examples/ex_k8s/oas_router_gen.go
@@ -11426,22 +11426,30 @@ func (r Route) Args() []string {
 }
 
 // FindRoute finds Route for given method and path.
-func (s *Server) FindRoute(method, path string) (r Route, _ bool) {
+//
+// Note: this method does not unescape path or handle reserved characters in path properly. Use FindPath instead.
+func (s *Server) FindRoute(method, path string) (Route, bool) {
+	return s.FindPath(method, &url.URL{Path: path})
+}
+
+// FindPath finds Route for given method and URL.
+func (s *Server) FindPath(method string, u *url.URL) (r Route, _ bool) {
 	var (
-		args = [3]string{}
-		elem = path
+		elem = u.Path
+		args = r.args
 	)
-	r.args = args
-	if elem == "" {
-		return r, false
-	}
-	defer func() {
-		for i, arg := range r.args[:r.count] {
-			if unescaped, err := url.PathUnescape(arg); err == nil {
-				r.args[i] = unescaped
-			}
+	if rawPath := u.RawPath; rawPath != "" {
+		if normalized, ok := uri.NormalizeEscapedPath(rawPath); ok {
+			elem = normalized
 		}
-	}()
+		defer func() {
+			for i, arg := range r.args[:r.count] {
+				if unescaped, err := url.PathUnescape(arg); err == nil {
+					r.args[i] = unescaped
+				}
+			}
+		}()
+	}
 
 	// Static code generated router with unwrapped path search.
 	switch {
diff --git a/examples/ex_manga/oas_router_gen.go b/examples/ex_manga/oas_router_gen.go
index 9698ec69..903ebdff 100644
--- a/examples/ex_manga/oas_router_gen.go
+++ b/examples/ex_manga/oas_router_gen.go
@@ -297,22 +297,30 @@ func (r Route) Args() []string {
 }
 
 // FindRoute finds Route for given method and path.
-func (s *Server) FindRoute(method, path string) (r Route, _ bool) {
+//
+// Note: this method does not unescape path or handle reserved characters in path properly. Use FindPath instead.
+func (s *Server) FindRoute(method, path string) (Route, bool) {
+	return s.FindPath(method, &url.URL{Path: path})
+}
+
+// FindPath finds Route for given method and URL.
+func (s *Server) FindPath(method string, u *url.URL) (r Route, _ bool) {
 	var (
-		args = [3]string{}
-		elem = path
+		elem = u.Path
+		args = r.args
 	)
-	r.args = args
-	if elem == "" {
-		return r, false
-	}
-	defer func() {
-		for i, arg := range r.args[:r.count] {
-			if unescaped, err := url.PathUnescape(arg); err == nil {
-				r.args[i] = unescaped
-			}
+	if rawPath := u.RawPath; rawPath != "" {
+		if normalized, ok := uri.NormalizeEscapedPath(rawPath); ok {
+			elem = normalized
 		}
-	}()
+		defer func() {
+			for i, arg := range r.args[:r.count] {
+				if unescaped, err := url.PathUnescape(arg); err == nil {
+					r.args[i] = unescaped
+				}
+			}
+		}()
+	}
 
 	// Static code generated router with unwrapped path search.
 	switch {
diff --git a/examples/ex_petstore/oas_router_gen.go b/examples/ex_petstore/oas_router_gen.go
index 26419e4d..e0de4662 100644
--- a/examples/ex_petstore/oas_router_gen.go
+++ b/examples/ex_petstore/oas_router_gen.go
@@ -119,22 +119,30 @@ func (r Route) Args() []string {
 }
 
 // FindRoute finds Route for given method and path.
-func (s *Server) FindRoute(method, path string) (r Route, _ bool) {
+//
+// Note: this method does not unescape path or handle reserved characters in path properly. Use FindPath instead.
+func (s *Server) FindRoute(method, path string) (Route, bool) {
+	return s.FindPath(method, &url.URL{Path: path})
+}
+
+// FindPath finds Route for given method and URL.
+func (s *Server) FindPath(method string, u *url.URL) (r Route, _ bool) {
 	var (
-		args = [1]string{}
-		elem = path
+		elem = u.Path
+		args = r.args
 	)
-	r.args = args
-	if elem == "" {
-		return r, false
-	}
-	defer func() {
-		for i, arg := range r.args[:r.count] {
-			if unescaped, err := url.PathUnescape(arg); err == nil {
-				r.args[i] = unescaped
-			}
+	if rawPath := u.RawPath; rawPath != "" {
+		if normalized, ok := uri.NormalizeEscapedPath(rawPath); ok {
+			elem = normalized
 		}
-	}()
+		defer func() {
+			for i, arg := range r.args[:r.count] {
+				if unescaped, err := url.PathUnescape(arg); err == nil {
+					r.args[i] = unescaped
+				}
+			}
+		}()
+	}
 
 	// Static code generated router with unwrapped path search.
 	switch {
diff --git a/examples/ex_petstore_expanded/oas_router_gen.go b/examples/ex_petstore_expanded/oas_router_gen.go
index f4a86951..4d718341 100644
--- a/examples/ex_petstore_expanded/oas_router_gen.go
+++ b/examples/ex_petstore_expanded/oas_router_gen.go
@@ -123,22 +123,30 @@ func (r Route) Args() []string {
 }
 
 // FindRoute finds Route for given method and path.
-func (s *Server) FindRoute(method, path string) (r Route, _ bool) {
+//
+// Note: this method does not unescape path or handle reserved characters in path properly. Use FindPath instead.
+func (s *Server) FindRoute(method, path string) (Route, bool) {
+	return s.FindPath(method, &url.URL{Path: path})
+}
+
+// FindPath finds Route for given method and URL.
+func (s *Server) FindPath(method string, u *url.URL) (r Route, _ bool) {
 	var (
-		args = [1]string{}
-		elem = path
+		elem = u.Path
+		args = r.args
 	)
-	r.args = args
-	if elem == "" {
-		return r, false
-	}
-	defer func() {
-		for i, arg := range r.args[:r.count] {
-			if unescaped, err := url.PathUnescape(arg); err == nil {
-				r.args[i] = unescaped
-			}
+	if rawPath := u.RawPath; rawPath != "" {
+		if normalized, ok := uri.NormalizeEscapedPath(rawPath); ok {
+			elem = normalized
 		}
-	}()
+		defer func() {
+			for i, arg := range r.args[:r.count] {
+				if unescaped, err := url.PathUnescape(arg); err == nil {
+					r.args[i] = unescaped
+				}
+			}
+		}()
+	}
 
 	// Static code generated router with unwrapped path search.
 	switch {
diff --git a/examples/ex_route_params/oas_router_gen.go b/examples/ex_route_params/oas_router_gen.go
index 55d16ab6..354d1d73 100644
--- a/examples/ex_route_params/oas_router_gen.go
+++ b/examples/ex_route_params/oas_router_gen.go
@@ -148,22 +148,30 @@ func (r Route) Args() []string {
 }
 
 // FindRoute finds Route for given method and path.
-func (s *Server) FindRoute(method, path string) (r Route, _ bool) {
+//
+// Note: this method does not unescape path or handle reserved characters in path properly. Use FindPath instead.
+func (s *Server) FindRoute(method, path string) (Route, bool) {
+	return s.FindPath(method, &url.URL{Path: path})
+}
+
+// FindPath finds Route for given method and URL.
+func (s *Server) FindPath(method string, u *url.URL) (r Route, _ bool) {
 	var (
-		args = [2]string{}
-		elem = path
+		elem = u.Path
+		args = r.args
 	)
-	r.args = args
-	if elem == "" {
-		return r, false
-	}
-	defer func() {
-		for i, arg := range r.args[:r.count] {
-			if unescaped, err := url.PathUnescape(arg); err == nil {
-				r.args[i] = unescaped
-			}
+	if rawPath := u.RawPath; rawPath != "" {
+		if normalized, ok := uri.NormalizeEscapedPath(rawPath); ok {
+			elem = normalized
 		}
-	}()
+		defer func() {
+			for i, arg := range r.args[:r.count] {
+				if unescaped, err := url.PathUnescape(arg); err == nil {
+					r.args[i] = unescaped
+				}
+			}
+		}()
+	}
 
 	// Static code generated router with unwrapped path search.
 	switch {
diff --git a/examples/ex_telegram/oas_router_gen.go b/examples/ex_telegram/oas_router_gen.go
index 307ec8cc..378f105a 100644
--- a/examples/ex_telegram/oas_router_gen.go
+++ b/examples/ex_telegram/oas_router_gen.go
@@ -1995,22 +1995,30 @@ func (r Route) Args() []string {
 }
 
 // FindRoute finds Route for given method and path.
-func (s *Server) FindRoute(method, path string) (r Route, _ bool) {
+//
+// Note: this method does not unescape path or handle reserved characters in path properly. Use FindPath instead.
+func (s *Server) FindRoute(method, path string) (Route, bool) {
+	return s.FindPath(method, &url.URL{Path: path})
+}
+
+// FindPath finds Route for given method and URL.
+func (s *Server) FindPath(method string, u *url.URL) (r Route, _ bool) {
 	var (
-		args = [0]string{}
-		elem = path
+		elem = u.Path
+		args = r.args
 	)
-	r.args = args
-	if elem == "" {
-		return r, false
-	}
-	defer func() {
-		for i, arg := range r.args[:r.count] {
-			if unescaped, err := url.PathUnescape(arg); err == nil {
-				r.args[i] = unescaped
-			}
+	if rawPath := u.RawPath; rawPath != "" {
+		if normalized, ok := uri.NormalizeEscapedPath(rawPath); ok {
+			elem = normalized
 		}
-	}()
+		defer func() {
+			for i, arg := range r.args[:r.count] {
+				if unescaped, err := url.PathUnescape(arg); err == nil {
+					r.args[i] = unescaped
+				}
+			}
+		}()
+	}
 
 	// Static code generated router with unwrapped path search.
 	switch {
diff --git a/examples/ex_tinkoff/oas_router_gen.go b/examples/ex_tinkoff/oas_router_gen.go
index d2d5c9ef..e9fecacc 100644
--- a/examples/ex_tinkoff/oas_router_gen.go
+++ b/examples/ex_tinkoff/oas_router_gen.go
@@ -572,22 +572,30 @@ func (r Route) Args() []string {
 }
 
 // FindRoute finds Route for given method and path.
-func (s *Server) FindRoute(method, path string) (r Route, _ bool) {
+//
+// Note: this method does not unescape path or handle reserved characters in path properly. Use FindPath instead.
+func (s *Server) FindRoute(method, path string) (Route, bool) {
+	return s.FindPath(method, &url.URL{Path: path})
+}
+
+// FindPath finds Route for given method and URL.
+func (s *Server) FindPath(method string, u *url.URL) (r Route, _ bool) {
 	var (
-		args = [0]string{}
-		elem = path
+		elem = u.Path
+		args = r.args
 	)
-	r.args = args
-	if elem == "" {
-		return r, false
-	}
-	defer func() {
-		for i, arg := range r.args[:r.count] {
-			if unescaped, err := url.PathUnescape(arg); err == nil {
-				r.args[i] = unescaped
-			}
+	if rawPath := u.RawPath; rawPath != "" {
+		if normalized, ok := uri.NormalizeEscapedPath(rawPath); ok {
+			elem = normalized
 		}
-	}()
+		defer func() {
+			for i, arg := range r.args[:r.count] {
+				if unescaped, err := url.PathUnescape(arg); err == nil {
+					r.args[i] = unescaped
+				}
+			}
+		}()
+	}
 
 	// Static code generated router with unwrapped path search.
 	switch {
diff --git a/gen/_template/router.tmpl b/gen/_template/router.tmpl
index 1aa47c53..4b4880ab 100644
--- a/gen/_template/router.tmpl
+++ b/gen/_template/router.tmpl
@@ -67,22 +67,30 @@ func (r Route) Args() []string {
 }
 
 // FindRoute finds Route for given method and path.
-func (s *Server) FindRoute(method, path string) (r Route, _ bool) {
+//
+// Note: this method does not unescape path or handle reserved characters in path properly. Use FindPath instead.
+func (s *Server) FindRoute(method, path string) (Route, bool) {
+	return s.FindPath(method, &url.URL{Path: path})
+}
+
+// FindPath finds Route for given method and URL.
+func (s *Server) FindPath(method string, u *url.URL) (r Route, _ bool) {
 	var (
-		args = [{{ $router.MaxParametersCount }}]string{}
-		elem = path
+		elem = u.Path
+		args = r.args
 	)
-	r.args = args
-	if elem == "" {
-		return r, false
-	}
-	defer func() {
-		for i, arg := range r.args[:r.count] {
-			if unescaped, err := url.PathUnescape(arg); err == nil {
-				r.args[i] = unescaped
-			}
+	if rawPath := u.RawPath; rawPath != "" {
+		if normalized, ok := uri.NormalizeEscapedPath(rawPath); ok {
+			elem = normalized
 		}
-	}()
+		defer func() {
+			for i, arg := range r.args[:r.count] {
+				if unescaped, err := url.PathUnescape(arg); err == nil {
+					r.args[i] = unescaped
+				}
+			}
+		}()
+	}
 
 	// Static code generated router with unwrapped path search.
 	{{- with $n := $router.Tree.Root }}
@@ -94,7 +102,6 @@ func (s *Server) FindRoute(method, path string) (r Route, _ bool) {
 	return r, false
 }
 
-
 {{- if $.Webhooks }}
 // Handle handles webhook request.
 //
diff --git a/internal/integration/referenced_path_item/oas_router_gen.go b/internal/integration/referenced_path_item/oas_router_gen.go
index aa166443..0df71a33 100644
--- a/internal/integration/referenced_path_item/oas_router_gen.go
+++ b/internal/integration/referenced_path_item/oas_router_gen.go
@@ -90,22 +90,30 @@ func (r Route) Args() []string {
 }
 
 // FindRoute finds Route for given method and path.
-func (s *Server) FindRoute(method, path string) (r Route, _ bool) {
+//
+// Note: this method does not unescape path or handle reserved characters in path properly. Use FindPath instead.
+func (s *Server) FindRoute(method, path string) (Route, bool) {
+	return s.FindPath(method, &url.URL{Path: path})
+}
+
+// FindPath finds Route for given method and URL.
+func (s *Server) FindPath(method string, u *url.URL) (r Route, _ bool) {
 	var (
-		args = [0]string{}
-		elem = path
+		elem = u.Path
+		args = r.args
 	)
-	r.args = args
-	if elem == "" {
-		return r, false
-	}
-	defer func() {
-		for i, arg := range r.args[:r.count] {
-			if unescaped, err := url.PathUnescape(arg); err == nil {
-				r.args[i] = unescaped
-			}
+	if rawPath := u.RawPath; rawPath != "" {
+		if normalized, ok := uri.NormalizeEscapedPath(rawPath); ok {
+			elem = normalized
 		}
-	}()
+		defer func() {
+			for i, arg := range r.args[:r.count] {
+				if unescaped, err := url.PathUnescape(arg); err == nil {
+					r.args[i] = unescaped
+				}
+			}
+		}()
+	}
 
 	// Static code generated router with unwrapped path search.
 	switch {
diff --git a/internal/integration/sample_api/oas_router_gen.go b/internal/integration/sample_api/oas_router_gen.go
index a87be518..c96a176e 100644
--- a/internal/integration/sample_api/oas_router_gen.go
+++ b/internal/integration/sample_api/oas_router_gen.go
@@ -679,22 +679,30 @@ func (r Route) Args() []string {
 }
 
 // FindRoute finds Route for given method and path.
-func (s *Server) FindRoute(method, path string) (r Route, _ bool) {
+//
+// Note: this method does not unescape path or handle reserved characters in path properly. Use FindPath instead.
+func (s *Server) FindRoute(method, path string) (Route, bool) {
+	return s.FindPath(method, &url.URL{Path: path})
+}
+
+// FindPath finds Route for given method and URL.
+func (s *Server) FindPath(method string, u *url.URL) (r Route, _ bool) {
 	var (
-		args = [5]string{}
-		elem = path
+		elem = u.Path
+		args = r.args
 	)
-	r.args = args
-	if elem == "" {
-		return r, false
-	}
-	defer func() {
-		for i, arg := range r.args[:r.count] {
-			if unescaped, err := url.PathUnescape(arg); err == nil {
-				r.args[i] = unescaped
-			}
+	if rawPath := u.RawPath; rawPath != "" {
+		if normalized, ok := uri.NormalizeEscapedPath(rawPath); ok {
+			elem = normalized
 		}
-	}()
+		defer func() {
+			for i, arg := range r.args[:r.count] {
+				if unescaped, err := url.PathUnescape(arg); err == nil {
+					r.args[i] = unescaped
+				}
+			}
+		}()
+	}
 
 	// Static code generated router with unwrapped path search.
 	switch {
diff --git a/internal/integration/sample_api_nc/oas_router_gen.go b/internal/integration/sample_api_nc/oas_router_gen.go
index a87be518..c96a176e 100644
--- a/internal/integration/sample_api_nc/oas_router_gen.go
+++ b/internal/integration/sample_api_nc/oas_router_gen.go
@@ -679,22 +679,30 @@ func (r Route) Args() []string {
 }
 
 // FindRoute finds Route for given method and path.
-func (s *Server) FindRoute(method, path string) (r Route, _ bool) {
+//
+// Note: this method does not unescape path or handle reserved characters in path properly. Use FindPath instead.
+func (s *Server) FindRoute(method, path string) (Route, bool) {
+	return s.FindPath(method, &url.URL{Path: path})
+}
+
+// FindPath finds Route for given method and URL.
+func (s *Server) FindPath(method string, u *url.URL) (r Route, _ bool) {
 	var (
-		args = [5]string{}
-		elem = path
+		elem = u.Path
+		args = r.args
 	)
-	r.args = args
-	if elem == "" {
-		return r, false
-	}
-	defer func() {
-		for i, arg := range r.args[:r.count] {
-			if unescaped, err := url.PathUnescape(arg); err == nil {
-				r.args[i] = unescaped
-			}
+	if rawPath := u.RawPath; rawPath != "" {
+		if normalized, ok := uri.NormalizeEscapedPath(rawPath); ok {
+			elem = normalized
 		}
-	}()
+		defer func() {
+			for i, arg := range r.args[:r.count] {
+				if unescaped, err := url.PathUnescape(arg); err == nil {
+					r.args[i] = unescaped
+				}
+			}
+		}()
+	}
 
 	// Static code generated router with unwrapped path search.
 	switch {
diff --git a/internal/integration/sample_err/oas_router_gen.go b/internal/integration/sample_err/oas_router_gen.go
index 5fe4d1f2..319d15bc 100644
--- a/internal/integration/sample_err/oas_router_gen.go
+++ b/internal/integration/sample_err/oas_router_gen.go
@@ -92,22 +92,30 @@ func (r Route) Args() []string {
 }
 
 // FindRoute finds Route for given method and path.
-func (s *Server) FindRoute(method, path string) (r Route, _ bool) {
+//
+// Note: this method does not unescape path or handle reserved characters in path properly. Use FindPath instead.
+func (s *Server) FindRoute(method, path string) (Route, bool) {
+	return s.FindPath(method, &url.URL{Path: path})
+}
+
+// FindPath finds Route for given method and URL.
+func (s *Server) FindPath(method string, u *url.URL) (r Route, _ bool) {
 	var (
-		args = [0]string{}
-		elem = path
+		elem = u.Path
+		args = r.args
 	)
-	r.args = args
-	if elem == "" {
-		return r, false
-	}
-	defer func() {
-		for i, arg := range r.args[:r.count] {
-			if unescaped, err := url.PathUnescape(arg); err == nil {
-				r.args[i] = unescaped
-			}
+	if rawPath := u.RawPath; rawPath != "" {
+		if normalized, ok := uri.NormalizeEscapedPath(rawPath); ok {
+			elem = normalized
 		}
-	}()
+		defer func() {
+			for i, arg := range r.args[:r.count] {
+				if unescaped, err := url.PathUnescape(arg); err == nil {
+					r.args[i] = unescaped
+				}
+			}
+		}()
+	}
 
 	// Static code generated router with unwrapped path search.
 	switch {
diff --git a/internal/integration/techempower/oas_router_gen.go b/internal/integration/techempower/oas_router_gen.go
index dabd2c91..a9475e3f 100644
--- a/internal/integration/techempower/oas_router_gen.go
+++ b/internal/integration/techempower/oas_router_gen.go
@@ -174,22 +174,30 @@ func (r Route) Args() []string {
 }
 
 // FindRoute finds Route for given method and path.
-func (s *Server) FindRoute(method, path string) (r Route, _ bool) {
+//
+// Note: this method does not unescape path or handle reserved characters in path properly. Use FindPath instead.
+func (s *Server) FindRoute(method, path string) (Route, bool) {
+	return s.FindPath(method, &url.URL{Path: path})
+}
+
+// FindPath finds Route for given method and URL.
+func (s *Server) FindPath(method string, u *url.URL) (r Route, _ bool) {
 	var (
-		args = [0]string{}
-		elem = path
+		elem = u.Path
+		args = r.args
 	)
-	r.args = args
-	if elem == "" {
-		return r, false
-	}
-	defer func() {
-		for i, arg := range r.args[:r.count] {
-			if unescaped, err := url.PathUnescape(arg); err == nil {
-				r.args[i] = unescaped
-			}
+	if rawPath := u.RawPath; rawPath != "" {
+		if normalized, ok := uri.NormalizeEscapedPath(rawPath); ok {
+			elem = normalized
 		}
-	}()
+		defer func() {
+			for i, arg := range r.args[:r.count] {
+				if unescaped, err := url.PathUnescape(arg); err == nil {
+					r.args[i] = unescaped
+				}
+			}
+		}()
+	}
 
 	// Static code generated router with unwrapped path search.
 	switch {


Test patch:
diff --git a/examples/ex_test_format/oas_router_gen.go b/examples/ex_test_format/oas_router_gen.go
index 362b43f8..b4319723 100644
--- a/examples/ex_test_format/oas_router_gen.go
+++ b/examples/ex_test_format/oas_router_gen.go
@@ -16068,22 +16068,30 @@ func (r Route) Args() []string {
 }
 
 // FindRoute finds Route for given method and path.
-func (s *Server) FindRoute(method, path string) (r Route, _ bool) {
+//
+// Note: this method does not unescape path or handle reserved characters in path properly. Use FindPath instead.
+func (s *Server) FindRoute(method, path string) (Route, bool) {
+	return s.FindPath(method, &url.URL{Path: path})
+}
+
+// FindPath finds Route for given method and URL.
+func (s *Server) FindPath(method string, u *url.URL) (r Route, _ bool) {
 	var (
-		args = [0]string{}
-		elem = path
+		elem = u.Path
+		args = r.args
 	)
-	r.args = args
-	if elem == "" {
-		return r, false
-	}
-	defer func() {
-		for i, arg := range r.args[:r.count] {
-			if unescaped, err := url.PathUnescape(arg); err == nil {
-				r.args[i] = unescaped
-			}
+	if rawPath := u.RawPath; rawPath != "" {
+		if normalized, ok := uri.NormalizeEscapedPath(rawPath); ok {
+			elem = normalized
 		}
-	}()
+		defer func() {
+			for i, arg := range r.args[:r.count] {
+				if unescaped, err := url.PathUnescape(arg); err == nil {
+					r.args[i] = unescaped
+				}
+			}
+		}()
+	}
 
 	// Static code generated router with unwrapped path search.
 	switch {
diff --git a/internal/integration/router_test.go b/internal/integration/router_test.go
index eca01453..a9a67ff2 100644
--- a/internal/integration/router_test.go
+++ b/internal/integration/router_test.go
@@ -6,6 +6,7 @@ import (
 	"io"
 	"net/http"
 	"net/http/httptest"
+	"net/url"
 	"strconv"
 	"testing"
 
@@ -44,7 +45,11 @@ func FuzzRouter(f *testing.F) {
 	require.NoError(f, err)
 
 	f.Fuzz(func(t *testing.T, method, path string) {
-		s.FindRoute(method, path)
+		u, err := url.Parse(path)
+		if err != nil {
+			t.Skipf("Parse %q: %#v", path, err)
+		}
+		s.FindPath(method, u)
 	})
 }
 
@@ -130,7 +135,11 @@ func TestRouter(t *testing.T) {
 		t.Run(fmt.Sprintf("Test%d", i+1), func(t *testing.T) {
 			t.Run("FindRoute", func(t *testing.T) {
 				a := require.New(t)
-				r, ok := s.FindRoute(tc.Method, tc.Path)
+
+				u, err := url.Parse(tc.Path)
+				a.NoError(err)
+
+				r, ok := s.FindPath(tc.Method, u)
 				if tc.Name == "" {
 					a.False(ok, r.Name())
 					return
diff --git a/internal/integration/test_allof/oas_router_gen.go b/internal/integration/test_allof/oas_router_gen.go
index 420d5434..f7ecf4db 100644
--- a/internal/integration/test_allof/oas_router_gen.go
+++ b/internal/integration/test_allof/oas_router_gen.go
@@ -235,22 +235,30 @@ func (r Route) Args() []string {
 }
 
 // FindRoute finds Route for given method and path.
-func (s *Server) FindRoute(method, path string) (r Route, _ bool) {
+//
+// Note: this method does not unescape path or handle reserved characters in path properly. Use FindPath instead.
+func (s *Server) FindRoute(method, path string) (Route, bool) {
+	return s.FindPath(method, &url.URL{Path: path})
+}
+
+// FindPath finds Route for given method and URL.
+func (s *Server) FindPath(method string, u *url.URL) (r Route, _ bool) {
 	var (
-		args = [0]string{}
-		elem = path
+		elem = u.Path
+		args = r.args
 	)
-	r.args = args
-	if elem == "" {
-		return r, false
-	}
-	defer func() {
-		for i, arg := range r.args[:r.count] {
-			if unescaped, err := url.PathUnescape(arg); err == nil {
-				r.args[i] = unescaped
-			}
+	if rawPath := u.RawPath; rawPath != "" {
+		if normalized, ok := uri.NormalizeEscapedPath(rawPath); ok {
+			elem = normalized
 		}
-	}()
+		defer func() {
+			for i, arg := range r.args[:r.count] {
+				if unescaped, err := url.PathUnescape(arg); err == nil {
+					r.args[i] = unescaped
+				}
+			}
+		}()
+	}
 
 	// Static code generated router with unwrapped path search.
 	switch {
diff --git a/internal/integration/test_anyof/oas_router_gen.go b/internal/integration/test_anyof/oas_router_gen.go
index 707af2bd..f168319a 100644
--- a/internal/integration/test_anyof/oas_router_gen.go
+++ b/internal/integration/test_anyof/oas_router_gen.go
@@ -138,22 +138,30 @@ func (r Route) Args() []string {
 }
 
 // FindRoute finds Route for given method and path.
-func (s *Server) FindRoute(method, path string) (r Route, _ bool) {
+//
+// Note: this method does not unescape path or handle reserved characters in path properly. Use FindPath instead.
+func (s *Server) FindRoute(method, path string) (Route, bool) {
+	return s.FindPath(method, &url.URL{Path: path})
+}
+
+// FindPath finds Route for given method and URL.
+func (s *Server) FindPath(method string, u *url.URL) (r Route, _ bool) {
 	var (
-		args = [0]string{}
-		elem = path
+		elem = u.Path
+		args = r.args
 	)
-	r.args = args
-	if elem == "" {
-		return r, false
-	}
-	defer func() {
-		for i, arg := range r.args[:r.count] {
-			if unescaped, err := url.PathUnescape(arg); err == nil {
-				r.args[i] = unescaped
-			}
+	if rawPath := u.RawPath; rawPath != "" {
+		if normalized, ok := uri.NormalizeEscapedPath(rawPath); ok {
+			elem = normalized
 		}
-	}()
+		defer func() {
+			for i, arg := range r.args[:r.count] {
+				if unescaped, err := url.PathUnescape(arg); err == nil {
+					r.args[i] = unescaped
+				}
+			}
+		}()
+	}
 
 	// Static code generated router with unwrapped path search.
 	switch {
diff --git a/internal/integration/test_enum_naming/oas_router_gen.go b/internal/integration/test_enum_naming/oas_router_gen.go
index 194d5b0f..2d6caf5e 100644
--- a/internal/integration/test_enum_naming/oas_router_gen.go
+++ b/internal/integration/test_enum_naming/oas_router_gen.go
@@ -90,22 +90,30 @@ func (r Route) Args() []string {
 }
 
 // FindRoute finds Route for given method and path.
-func (s *Server) FindRoute(method, path string) (r Route, _ bool) {
+//
+// Note: this method does not unescape path or handle reserved characters in path properly. Use FindPath instead.
+func (s *Server) FindRoute(method, path string) (Route, bool) {
+	return s.FindPath(method, &url.URL{Path: path})
+}
+
+// FindPath finds Route for given method and URL.
+func (s *Server) FindPath(method string, u *url.URL) (r Route, _ bool) {
 	var (
-		args = [0]string{}
-		elem = path
+		elem = u.Path
+		args = r.args
 	)
-	r.args = args
-	if elem == "" {
-		return r, false
-	}
-	defer func() {
-		for i, arg := range r.args[:r.count] {
-			if unescaped, err := url.PathUnescape(arg); err == nil {
-				r.args[i] = unescaped
-			}
+	if rawPath := u.RawPath; rawPath != "" {
+		if normalized, ok := uri.NormalizeEscapedPath(rawPath); ok {
+			elem = normalized
 		}
-	}()
+		defer func() {
+			for i, arg := range r.args[:r.count] {
+				if unescaped, err := url.PathUnescape(arg); err == nil {
+					r.args[i] = unescaped
+				}
+			}
+		}()
+	}
 
 	// Static code generated router with unwrapped path search.
 	switch {
diff --git a/internal/integration/test_form/oas_router_gen.go b/internal/integration/test_form/oas_router_gen.go
index 3796fd62..cd838ad8 100644
--- a/internal/integration/test_form/oas_router_gen.go
+++ b/internal/integration/test_form/oas_router_gen.go
@@ -157,22 +157,30 @@ func (r Route) Args() []string {
 }
 
 // FindRoute finds Route for given method and path.
-func (s *Server) FindRoute(method, path string) (r Route, _ bool) {
+//
+// Note: this method does not unescape path or handle reserved characters in path properly. Use FindPath instead.
+func (s *Server) FindRoute(method, path string) (Route, bool) {
+	return s.FindPath(method, &url.URL{Path: path})
+}
+
+// FindPath finds Route for given method and URL.
+func (s *Server) FindPath(method string, u *url.URL) (r Route, _ bool) {
 	var (
-		args = [0]string{}
-		elem = path
+		elem = u.Path
+		args = r.args
 	)
-	r.args = args
-	if elem == "" {
-		return r, false
-	}
-	defer func() {
-		for i, arg := range r.args[:r.count] {
-			if unescaped, err := url.PathUnescape(arg); err == nil {
-				r.args[i] = unescaped
-			}
+	if rawPath := u.RawPath; rawPath != "" {
+		if normalized, ok := uri.NormalizeEscapedPath(rawPath); ok {
+			elem = normalized
 		}
-	}()
+		defer func() {
+			for i, arg := range r.args[:r.count] {
+				if unescaped, err := url.PathUnescape(arg); err == nil {
+					r.args[i] = unescaped
+				}
+			}
+		}()
+	}
 
 	// Static code generated router with unwrapped path search.
 	switch {
diff --git a/internal/integration/test_http_requests/oas_router_gen.go b/internal/integration/test_http_requests/oas_router_gen.go
index 29f0de16..b714dcda 100644
--- a/internal/integration/test_http_requests/oas_router_gen.go
+++ b/internal/integration/test_http_requests/oas_router_gen.go
@@ -176,22 +176,30 @@ func (r Route) Args() []string {
 }
 
 // FindRoute finds Route for given method and path.
-func (s *Server) FindRoute(method, path string) (r Route, _ bool) {
+//
+// Note: this method does not unescape path or handle reserved characters in path properly. Use FindPath instead.
+func (s *Server) FindRoute(method, path string) (Route, bool) {
+	return s.FindPath(method, &url.URL{Path: path})
+}
+
+// FindPath finds Route for given method and URL.
+func (s *Server) FindPath(method string, u *url.URL) (r Route, _ bool) {
 	var (
-		args = [0]string{}
-		elem = path
+		elem = u.Path
+		args = r.args
 	)
-	r.args = args
-	if elem == "" {
-		return r, false
-	}
-	defer func() {
-		for i, arg := range r.args[:r.count] {
-			if unescaped, err := url.PathUnescape(arg); err == nil {
-				r.args[i] = unescaped
-			}
+	if rawPath := u.RawPath; rawPath != "" {
+		if normalized, ok := uri.NormalizeEscapedPath(rawPath); ok {
+			elem = normalized
 		}
-	}()
+		defer func() {
+			for i, arg := range r.args[:r.count] {
+				if unescaped, err := url.PathUnescape(arg); err == nil {
+					r.args[i] = unescaped
+				}
+			}
+		}()
+	}
 
 	// Static code generated router with unwrapped path search.
 	switch {
diff --git a/internal/integration/test_http_responses/oas_router_gen.go b/internal/integration/test_http_responses/oas_router_gen.go
index bb060f80..05269c57 100644
--- a/internal/integration/test_http_responses/oas_router_gen.go
+++ b/internal/integration/test_http_responses/oas_router_gen.go
@@ -343,22 +343,30 @@ func (r Route) Args() []string {
 }
 
 // FindRoute finds Route for given method and path.
-func (s *Server) FindRoute(method, path string) (r Route, _ bool) {
+//
+// Note: this method does not unescape path or handle reserved characters in path properly. Use FindPath instead.
+func (s *Server) FindRoute(method, path string) (Route, bool) {
+	return s.FindPath(method, &url.URL{Path: path})
+}
+
+// FindPath finds Route for given method and URL.
+func (s *Server) FindPath(method string, u *url.URL) (r Route, _ bool) {
 	var (
-		args = [0]string{}
-		elem = path
+		elem = u.Path
+		args = r.args
 	)
-	r.args = args
-	if elem == "" {
-		return r, false
-	}
-	defer func() {
-		for i, arg := range r.args[:r.count] {
-			if unescaped, err := url.PathUnescape(arg); err == nil {
-				r.args[i] = unescaped
-			}
+	if rawPath := u.RawPath; rawPath != "" {
+		if normalized, ok := uri.NormalizeEscapedPath(rawPath); ok {
+			elem = normalized
 		}
-	}()
+		defer func() {
+			for i, arg := range r.args[:r.count] {
+				if unescaped, err := url.PathUnescape(arg); err == nil {
+					r.args[i] = unescaped
+				}
+			}
+		}()
+	}
 
 	// Static code generated router with unwrapped path search.
 	switch {
diff --git a/internal/integration/test_parameters/oas_router_gen.go b/internal/integration/test_parameters/oas_router_gen.go
index 3d5aed6c..d850c1d9 100644
--- a/internal/integration/test_parameters/oas_router_gen.go
+++ b/internal/integration/test_parameters/oas_router_gen.go
@@ -219,22 +219,30 @@ func (r Route) Args() []string {
 }
 
 // FindRoute finds Route for given method and path.
-func (s *Server) FindRoute(method, path string) (r Route, _ bool) {
+//
+// Note: this method does not unescape path or handle reserved characters in path properly. Use FindPath instead.
+func (s *Server) FindRoute(method, path string) (Route, bool) {
+	return s.FindPath(method, &url.URL{Path: path})
+}
+
+// FindPath finds Route for given method and URL.
+func (s *Server) FindPath(method string, u *url.URL) (r Route, _ bool) {
 	var (
-		args = [1]string{}
-		elem = path
+		elem = u.Path
+		args = r.args
 	)
-	r.args = args
-	if elem == "" {
-		return r, false
-	}
-	defer func() {
-		for i, arg := range r.args[:r.count] {
-			if unescaped, err := url.PathUnescape(arg); err == nil {
-				r.args[i] = unescaped
-			}
+	if rawPath := u.RawPath; rawPath != "" {
+		if normalized, ok := uri.NormalizeEscapedPath(rawPath); ok {
+			elem = normalized
 		}
-	}()
+		defer func() {
+			for i, arg := range r.args[:r.count] {
+				if unescaped, err := url.PathUnescape(arg); err == nil {
+					r.args[i] = unescaped
+				}
+			}
+		}()
+	}
 
 	// Static code generated router with unwrapped path search.
 	switch {
diff --git a/internal/integration/test_servers/oas_router_gen.go b/internal/integration/test_servers/oas_router_gen.go
index 194d5b0f..2d6caf5e 100644
--- a/internal/integration/test_servers/oas_router_gen.go
+++ b/internal/integration/test_servers/oas_router_gen.go
@@ -90,22 +90,30 @@ func (r Route) Args() []string {
 }
 
 // FindRoute finds Route for given method and path.
-func (s *Server) FindRoute(method, path string) (r Route, _ bool) {
+//
+// Note: this method does not unescape path or handle reserved characters in path properly. Use FindPath instead.
+func (s *Server) FindRoute(method, path string) (Route, bool) {
+	return s.FindPath(method, &url.URL{Path: path})
+}
+
+// FindPath finds Route for given method and URL.
+func (s *Server) FindPath(method string, u *url.URL) (r Route, _ bool) {
 	var (
-		args = [0]string{}
-		elem = path
+		elem = u.Path
+		args = r.args
 	)
-	r.args = args
-	if elem == "" {
-		return r, false
-	}
-	defer func() {
-		for i, arg := range r.args[:r.count] {
-			if unescaped, err := url.PathUnescape(arg); err == nil {
-				r.args[i] = unescaped
-			}
+	if rawPath := u.RawPath; rawPath != "" {
+		if normalized, ok := uri.NormalizeEscapedPath(rawPath); ok {
+			elem = normalized
 		}
-	}()
+		defer func() {
+			for i, arg := range r.args[:r.count] {
+				if unescaped, err := url.PathUnescape(arg); err == nil {
+					r.args[i] = unescaped
+				}
+			}
+		}()
+	}
 
 	// Static code generated router with unwrapped path search.
 	switch {
diff --git a/internal/integration/test_single_endpoint/oas_router_gen.go b/internal/integration/test_single_endpoint/oas_router_gen.go
index 194d5b0f..2d6caf5e 100644
--- a/internal/integration/test_single_endpoint/oas_router_gen.go
+++ b/internal/integration/test_single_endpoint/oas_router_gen.go
@@ -90,22 +90,30 @@ func (r Route) Args() []string {
 }
 
 // FindRoute finds Route for given method and path.
-func (s *Server) FindRoute(method, path string) (r Route, _ bool) {
+//
+// Note: this method does not unescape path or handle reserved characters in path properly. Use FindPath instead.
+func (s *Server) FindRoute(method, path string) (Route, bool) {
+	return s.FindPath(method, &url.URL{Path: path})
+}
+
+// FindPath finds Route for given method and URL.
+func (s *Server) FindPath(method string, u *url.URL) (r Route, _ bool) {
 	var (
-		args = [0]string{}
-		elem = path
+		elem = u.Path
+		args = r.args
 	)
-	r.args = args
-	if elem == "" {
-		return r, false
-	}
-	defer func() {
-		for i, arg := range r.args[:r.count] {
-			if unescaped, err := url.PathUnescape(arg); err == nil {
-				r.args[i] = unescaped
-			}
+	if rawPath := u.RawPath; rawPath != "" {
+		if normalized, ok := uri.NormalizeEscapedPath(rawPath); ok {
+			elem = normalized
 		}
-	}()
+		defer func() {
+			for i, arg := range r.args[:r.count] {
+				if unescaped, err := url.PathUnescape(arg); err == nil {
+					r.args[i] = unescaped
+				}
+			}
+		}()
+	}
 
 	// Static code generated router with unwrapped path search.
 	switch {
diff --git a/internal/integration/test_webhooks/oas_router_gen.go b/internal/integration/test_webhooks/oas_router_gen.go
index 7fa63fc3..3a2374ba 100644
--- a/internal/integration/test_webhooks/oas_router_gen.go
+++ b/internal/integration/test_webhooks/oas_router_gen.go
@@ -90,22 +90,30 @@ func (r Route) Args() []string {
 }
 
 // FindRoute finds Route for given method and path.
-func (s *Server) FindRoute(method, path string) (r Route, _ bool) {
+//
+// Note: this method does not unescape path or handle reserved characters in path properly. Use FindPath instead.
+func (s *Server) FindRoute(method, path string) (Route, bool) {
+	return s.FindPath(method, &url.URL{Path: path})
+}
+
+// FindPath finds Route for given method and URL.
+func (s *Server) FindPath(method string, u *url.URL) (r Route, _ bool) {
 	var (
-		args = [0]string{}
-		elem = path
+		elem = u.Path
+		args = r.args
 	)
-	r.args = args
-	if elem == "" {
-		return r, false
-	}
-	defer func() {
-		for i, arg := range r.args[:r.count] {
-			if unescaped, err := url.PathUnescape(arg); err == nil {
-				r.args[i] = unescaped
-			}
+	if rawPath := u.RawPath; rawPath != "" {
+		if normalized, ok := uri.NormalizeEscapedPath(rawPath); ok {
+			elem = normalized
 		}
-	}()
+		defer func() {
+			for i, arg := range r.args[:r.count] {
+				if unescaped, err := url.PathUnescape(arg); err == nil {
+					r.args[i] = unescaped
+				}
+			}
+		}()
+	}
 
 	// Static code generated router with unwrapped path search.
 	switch {