aboutsummaryrefslogtreecommitdiff
path: root/src/net/http/httputil/reverseproxy.go
diff options
context:
space:
mode:
authorDaniel Kumor <rdkumor@gmail.com>2020-01-07 02:16:40 +0000
committerBrad Fitzpatrick <bradfitz@golang.org>2020-05-02 20:20:16 +0000
commit2d323f900df420a29de29cbab949eea08e3d1a61 (patch)
tree91c3037ab736ebe015675270f075f9625b23a1e9 /src/net/http/httputil/reverseproxy.go
parent9439a7d87f90b97e00717fc0849d4460628d82d0 (diff)
downloadgo-2d323f900df420a29de29cbab949eea08e3d1a61.tar.gz
go-2d323f900df420a29de29cbab949eea08e3d1a61.zip
net/http/httputil: handle escaped paths in SingleHostReverseProxy
When forwarding a request, a SingleHostReverseProxy appends the request's path to the target URL's path. However, if certain path elements are encoded, (such as %2F for slash in either the request or target path), simply joining the URL.Path elements is not sufficient, since the field holds the decoded path. Since 87a605, the RawPath field was added which holds a decoding hint for the URL. When joining URL paths, this decoding hint needs to be taken into consideration. As an example, if the target URL.Path is /a/b, and URL.RawPath is /a%2Fb, joining the path with /c should result in /a/b/c in URL.Path, and /a%2Fb/c in RawPath. The added joinURLPath function combines the two URL's Paths, while taking into account escaping, and replaces the previously used singleJoiningSlash in NewSingleHostReverseProxy. Fixes #35908 Change-Id: I45886aee548431fe4031883ab1629a41e35f1727 GitHub-Last-Rev: 7be6b8d421c63928639f499b984a821585992c2b GitHub-Pull-Request: golang/go#36378 Reviewed-on: https://go-review.googlesource.com/c/go/+/213257 Run-TryBot: Ian Lance Taylor <iant@golang.org> TryBot-Result: Gobot Gobot <gobot@golang.org> Reviewed-by: Brad Fitzpatrick <bradfitz@golang.org>
Diffstat (limited to 'src/net/http/httputil/reverseproxy.go')
-rw-r--r--src/net/http/httputil/reverseproxy.go23
1 files changed, 22 insertions, 1 deletions
diff --git a/src/net/http/httputil/reverseproxy.go b/src/net/http/httputil/reverseproxy.go
index 6e5bc4753e..70de7b107d 100644
--- a/src/net/http/httputil/reverseproxy.go
+++ b/src/net/http/httputil/reverseproxy.go
@@ -110,6 +110,27 @@ func singleJoiningSlash(a, b string) string {
return a + b
}
+func joinURLPath(a, b *url.URL) (path, rawpath string) {
+ if a.RawPath == "" && b.RawPath == "" {
+ return singleJoiningSlash(a.Path, b.Path), ""
+ }
+ // Same as singleJoiningSlash, but uses EscapedPath to determine
+ // whether a slash should be added
+ apath := a.EscapedPath()
+ bpath := b.EscapedPath()
+
+ aslash := strings.HasSuffix(apath, "/")
+ bslash := strings.HasPrefix(bpath, "/")
+
+ switch {
+ case aslash && bslash:
+ return a.Path + b.Path[1:], apath + bpath[1:]
+ case !aslash && !bslash:
+ return a.Path + "/" + b.Path, apath + "/" + bpath
+ }
+ return a.Path + b.Path, apath + bpath
+}
+
// NewSingleHostReverseProxy returns a new ReverseProxy that routes
// URLs to the scheme, host, and base path provided in target. If the
// target's path is "/base" and the incoming request was for "/dir",
@@ -122,7 +143,7 @@ func NewSingleHostReverseProxy(target *url.URL) *ReverseProxy {
director := func(req *http.Request) {
req.URL.Scheme = target.Scheme
req.URL.Host = target.Host
- req.URL.Path = singleJoiningSlash(target.Path, req.URL.Path)
+ req.URL.Path, req.URL.RawPath = joinURLPath(target, req.URL)
if targetQuery == "" || req.URL.RawQuery == "" {
req.URL.RawQuery = targetQuery + req.URL.RawQuery
} else {