aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorSean Liao <sean@liao.dev>2025-10-09 02:26:02 +0100
committerGopher Robot <gobot@golang.org>2025-10-10 14:39:53 -0700
commitaced4c79a2b2c60e464410cec1e5378d1011fa18 (patch)
tree919329b65bab5ca283b9afb128cdc71aa3c199bd /src
parent584a89fe7455470b09643b30bdc3cc55bb75a552 (diff)
downloadgo-aced4c79a2b2c60e464410cec1e5378d1011fa18.tar.xz
net/http: strip request body headers on POST to GET redirects
According to WHATWG Fetch, when the body is dropped in a redirect, headers that describe the body should also be dropped. https://fetch.spec.whatwg.org/#http-redirect-fetch Fixes #57273 Change-Id: I84598f69608e95c1b556ea0ce5953ed43bf2d824 Reviewed-on: https://go-review.googlesource.com/c/go/+/710395 Auto-Submit: Damien Neil <dneil@google.com> Reviewed-by: Michael Pratt <mpratt@google.com> Reviewed-by: Damien Neil <dneil@google.com> LUCI-TryBot-Result: Go LUCI <golang-scoped@luci-project-accounts.iam.gserviceaccount.com>
Diffstat (limited to 'src')
-rw-r--r--src/net/http/client.go18
-rw-r--r--src/net/http/client_test.go33
2 files changed, 46 insertions, 5 deletions
diff --git a/src/net/http/client.go b/src/net/http/client.go
index 8faab2b17a..d6a8010735 100644
--- a/src/net/http/client.go
+++ b/src/net/http/client.go
@@ -690,8 +690,7 @@ func (c *Client) do(req *Request) (retres *Response, reterr error) {
stripSensitiveHeaders = true
}
}
- copyHeaders(req, stripSensitiveHeaders)
-
+ copyHeaders(req, stripSensitiveHeaders, !includeBody)
// Add the Referer header from the most recent
// request URL to the new one, if it's not https->http:
if ref := refererForURL(reqs[len(reqs)-1].URL, req.URL, req.Header.Get("Referer")); ref != "" {
@@ -758,7 +757,7 @@ func (c *Client) do(req *Request) (retres *Response, reterr error) {
// makeHeadersCopier makes a function that copies headers from the
// initial Request, ireq. For every redirect, this function must be called
// so that it can copy headers into the upcoming Request.
-func (c *Client) makeHeadersCopier(ireq *Request) func(req *Request, stripSensitiveHeaders bool) {
+func (c *Client) makeHeadersCopier(ireq *Request) func(req *Request, stripSensitiveHeaders, stripBodyHeaders bool) {
// The headers to copy are from the very initial request.
// We use a closured callback to keep a reference to these original headers.
var (
@@ -772,7 +771,7 @@ func (c *Client) makeHeadersCopier(ireq *Request) func(req *Request, stripSensit
}
}
- return func(req *Request, stripSensitiveHeaders bool) {
+ return func(req *Request, stripSensitiveHeaders, stripBodyHeaders bool) {
// If Jar is present and there was some initial cookies provided
// via the request header, then we may need to alter the initial
// cookies as we follow redirects since each redirect may end up
@@ -810,12 +809,21 @@ func (c *Client) makeHeadersCopier(ireq *Request) func(req *Request, stripSensit
// (at least the safe ones).
for k, vv := range ireqhdr {
sensitive := false
+ body := false
switch CanonicalHeaderKey(k) {
case "Authorization", "Www-Authenticate", "Cookie", "Cookie2",
"Proxy-Authorization", "Proxy-Authenticate":
sensitive = true
+
+ case "Content-Encoding", "Content-Language", "Content-Location",
+ "Content-Type":
+ // Headers relating to the body which is removed for
+ // POST to GET redirects
+ // https://fetch.spec.whatwg.org/#http-redirect-fetch
+ body = true
+
}
- if !(sensitive && stripSensitiveHeaders) {
+ if !(sensitive && stripSensitiveHeaders) && !(body && stripBodyHeaders) {
req.Header[k] = vv
}
}
diff --git a/src/net/http/client_test.go b/src/net/http/client_test.go
index 2a3ee385f3..d184f72031 100644
--- a/src/net/http/client_test.go
+++ b/src/net/http/client_test.go
@@ -1621,6 +1621,39 @@ func testClientStripHeadersOnRepeatedRedirect(t *testing.T, mode testMode) {
}
}
+func TestClientStripHeadersOnPostToGetRedirect(t *testing.T) {
+ run(t, testClientStripHeadersOnPostToGetRedirect)
+}
+func testClientStripHeadersOnPostToGetRedirect(t *testing.T, mode testMode) {
+ ts := newClientServerTest(t, mode, HandlerFunc(func(w ResponseWriter, r *Request) {
+ if r.Method == "POST" {
+ Redirect(w, r, "/redirected", StatusFound)
+ return
+ } else if r.Method != "GET" {
+ t.Errorf("unexpected request method: %v", r.Method)
+ return
+ }
+ for key, val := range r.Header {
+ if strings.HasPrefix(key, "Content-") {
+ t.Errorf("unexpected request body header after redirect: %v: %v", key, val)
+ }
+ }
+ })).ts
+
+ c := ts.Client()
+
+ req, _ := NewRequest("POST", ts.URL, strings.NewReader("hello world"))
+ req.Header.Set("Content-Encoding", "a")
+ req.Header.Set("Content-Language", "b")
+ req.Header.Set("Content-Length", "c")
+ req.Header.Set("Content-Type", "d")
+ res, err := c.Do(req)
+ if err != nil {
+ t.Fatal(err)
+ }
+ defer res.Body.Close()
+}
+
// Issue 22233: copy host when Client follows a relative redirect.
func TestClientCopyHostOnRedirect(t *testing.T) { run(t, testClientCopyHostOnRedirect) }
func testClientCopyHostOnRedirect(t *testing.T, mode testMode) {