From 29b349708f055335c23c793a9bf91526c84c848a Mon Sep 17 00:00:00 2001 From: potoo0 <1415615232@qq.com> Date: Fri, 28 Jun 2024 16:36:44 +0800 Subject: [PATCH] net/http/httputil: fix joinURLPath unexpectedly appends a trailing slash Fixes #50337 --- src/net/http/httputil/reverseproxy.go | 19 +++++++++++------- src/net/http/httputil/reverseproxy_test.go | 23 ++++++++++++++++++++++ 2 files changed, 35 insertions(+), 7 deletions(-) diff --git a/src/net/http/httputil/reverseproxy.go b/src/net/http/httputil/reverseproxy.go index 04248d5f531..6bf826f4da4 100644 --- a/src/net/http/httputil/reverseproxy.go +++ b/src/net/http/httputil/reverseproxy.go @@ -207,6 +207,9 @@ type BufferPool interface { } func singleJoiningSlash(a, b string) string { + if b == "" { + return a + } aslash := strings.HasSuffix(a, "/") bslash := strings.HasPrefix(b, "/") switch { @@ -227,14 +230,16 @@ func joinURLPath(a, b *url.URL) (path, rawpath string) { apath := a.EscapedPath() bpath := b.EscapedPath() - aslash := strings.HasSuffix(apath, "/") - bslash := strings.HasPrefix(bpath, "/") + if bpath != "" { + 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 + 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 } diff --git a/src/net/http/httputil/reverseproxy_test.go b/src/net/http/httputil/reverseproxy_test.go index eac8b7ec81d..c66e3110ddd 100644 --- a/src/net/http/httputil/reverseproxy_test.go +++ b/src/net/http/httputil/reverseproxy_test.go @@ -1662,6 +1662,29 @@ func TestJoinURLPath(t *testing.T) { } } +func TestJoinURLPath_trailingSlash(t *testing.T) { + tests := []struct { + a *url.URL + b *url.URL + wantPath string + wantRaw string + }{ + {&url.URL{Path: "/a/b"}, &url.URL{Path: ""}, "/a/b", ""}, + {&url.URL{Path: "/a/b", RawPath: "/a%2Fb"}, &url.URL{Path: ""}, "/a/b", "/a%2Fb"}, + } + + for _, tt := range tests { + p, rp := joinURLPath(tt.a, tt.b) + if p != tt.wantPath || rp != tt.wantRaw { + t.Errorf("joinURLPath(URL(%q,%q),URL(%q,%q)) want (%q,%q) got (%q,%q)", + tt.a.Path, tt.a.RawPath, + tt.b.Path, tt.b.RawPath, + tt.wantPath, tt.wantRaw, + p, rp) + } + } +} + func TestReverseProxyRewriteReplacesOut(t *testing.T) { const content = "response_content" backend := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {