rewrite: preserve non-canonical path encoding after uri replace (#7907)

changePath cleared RawPath whenever it equalled url.Path, which
discarded a valid non-canonical percent-encoding produced by a
replacement. This compare `RawPath` against the default escaping of Path
instead.
This commit is contained in:
Saleh
2026-07-26 01:49:44 +03:00
committed by GitHub
parent c5b66cf8ea
commit c96bca1269
2 changed files with 24 additions and 2 deletions

View File

@@ -513,12 +513,21 @@ func changePath(req *http.Request, newVal func(pathOrRawPath string) string) {
} else {
req.URL.Path = newVal(req.URL.Path)
}
// RawPath is only set if it's different from the normalized Path (std lib)
if req.URL.RawPath == req.URL.Path {
// RawPath is only needed if it is a valid, non-canonical encoding of Path;
// (see #6578). Mirror net/url.URL.setPath by comparing against the default
// escaping of Path instead.
if req.URL.RawPath == defaultEscapedPath(req.URL.Path) {
req.URL.RawPath = ""
}
}
// defaultEscapedPath returns the canonical percent-encoding of p, matching
// what net/url.URL.EscapedPath() produces when RawPath is empty. It mirrors
// the comparison net/url.URL.setPath uses to decide whether RawPath is needed.
func defaultEscapedPath(p string) string {
return (&url.URL{Path: p}).EscapedPath()
}
// queryOps describes the operations to perform on query keys: add, set, rename and delete.
type queryOps struct {
// Renames a query key from Key to Val, without affecting the value.

View File

@@ -351,6 +351,19 @@ func TestRewrite(t *testing.T) {
input: newRequest(t, "GET", "/foo/findme%2Fbar"),
expect: newRequest(t, "GET", "/foo/replaced%2Fbar"),
},
{
rule: Rewrite{URISubstring: []substrReplacer{{Find: "%28", Replace: "("}}},
input: newRequest(t, "GET", "/hello/%28%29"),
expect: newRequest(t, "GET", "/hello/(%29"),
},
{
rule: Rewrite{URISubstring: []substrReplacer{
{Find: "%28", Replace: "("},
{Find: "%29", Replace: ")"},
}},
input: newRequest(t, "GET", "/hello/%28%29"),
expect: newRequest(t, "GET", "/hello/()"),
},
{
rule: Rewrite{PathRegexp: []*regexReplacer{{Find: "/{2,}", Replace: "/"}}},