fix: preserve percent-encoded characters

Signed-off-by: Mladjan Gadzic <gadzic.mladjan@gmail.com>
This commit is contained in:
Mladjan Gadzic 2026-06-04 11:06:49 +02:00
parent 10b68716e5
commit 876d50e563
3 changed files with 35 additions and 1 deletions

View File

@ -32,6 +32,7 @@
## Breaking Changes ## Breaking Changes
## Changes since v7.15.2 ## Changes since v7.15.2
- [#3449](https://github.com/oauth2-proxy/oauth2-proxy/pull/3449) fix: preserve percent-encoded characters in upstream rewrite targets (#2105) (@mladjan-gadzic)
- [#3477](https://github.com/oauth2-proxy/oauth2-proxy/pull/3477) chore(dep): bump go to 1.26 and migrate of reverse proxy handling - [#3477](https://github.com/oauth2-proxy/oauth2-proxy/pull/3477) chore(dep): bump go to 1.26 and migrate of reverse proxy handling

View File

@ -49,8 +49,20 @@ func rewritePath(rewriteRegExp *regexp.Regexp, rewriteTarget string, writer page
return return
} }
// When the original path was percent-encoded, RawPath holds the escaped
// form. Rewrite it too so the encoding is preserved when proxying to the
// upstream; otherwise EscapedPath() (via reqURL.String()) re-encodes the
// decoded Path and drops characters such as %2F and %3A. See issue #2105.
if reqURL.RawPath != "" {
newRawPath := rewriteRegExp.ReplaceAllString(reqURL.RawPath, rewriteTarget)
reqURL.RawPath = strings.SplitN(newRawPath, "?", 2)[0]
}
req.RequestURI = reqURL.String() req.RequestURI = reqURL.String()
req.URL.Path = reqURL.Path // set path for websocket connections // Set path and raw (encoded) path for websocket connections, which are
// proxied using req.URL rather than req.RequestURI.
req.URL.Path = reqURL.Path
req.URL.RawPath = reqURL.RawPath
next.ServeHTTP(rw, req) next.ServeHTTP(rw, req)
}) })
} }

View File

@ -63,5 +63,26 @@ var _ = Describe("Rewrite", func() {
expectedRequestURI: "http://example.com/article?id=blog-2021-01-01", expectedRequestURI: "http://example.com/article?id=blog-2021-01-01",
expectedURLPath: "/article", expectedURLPath: "/article",
}), }),
Entry("when the path contains percent-encoded characters, the encoding is preserved", rewritePathTableInput{
rewriteRegex: regexp.MustCompile("^/app/prefix/(.*)$"),
rewriteTarget: "/$1",
requestTarget: "http://example.com/app/prefix/v1/id/data%3Aabc%2Fdef",
expectedRequestURI: "http://example.com/v1/id/data%3Aabc%2Fdef",
expectedURLPath: "/v1/id/data:abc/def",
}),
Entry("when the encoded path is rewritten and an original query is preserved", rewritePathTableInput{
rewriteRegex: regexp.MustCompile("^/app/prefix/(.*)$"),
rewriteTarget: "/$1",
requestTarget: "http://example.com/app/prefix/data%2Fone?foo=bar",
expectedRequestURI: "http://example.com/data%2Fone?foo=bar",
expectedURLPath: "/data/one",
}),
Entry("when the encoded path is matched by a non-anchored regexp", rewritePathTableInput{
rewriteRegex: regexp.MustCompile("/prefix/(.*)"),
rewriteTarget: "/$1",
requestTarget: "http://example.com/app/prefix/data%2Fone",
expectedRequestURI: "http://example.com/app/data%2Fone",
expectedURLPath: "/app/data/one",
}),
) )
}) })