Skip to content

Commit b69f50f

Browse files
maruelgopherbot
authored andcommitted
net/http: upon http redirect, copy Request.GetBody in new request
This enable http.RoundTripper implementation to retry POST request (let's say after a 500) after a 307/308 redirect. Fixes #73439 Change-Id: I4365ff58b012c7f0d60e0317a08c98b1d48f657e Reviewed-on: https://go-review.googlesource.com/c/go/+/666735 Reviewed-by: Sean Liao <sean@liao.dev> Auto-Submit: Damien Neil <dneil@google.com> LUCI-TryBot-Result: Go LUCI <golang-scoped@luci-project-accounts.iam.gserviceaccount.com> Reviewed-by: Dmitri Shuralyov <dmitshur@google.com> Reviewed-by: Damien Neil <dneil@google.com>
1 parent df9888e commit b69f50f

File tree

2 files changed

+56
-0
lines changed

2 files changed

+56
-0
lines changed

src/net/http/client.go

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -672,6 +672,7 @@ func (c *Client) do(req *Request) (retres *Response, reterr error) {
672672
resp.closeBody()
673673
return nil, uerr(err)
674674
}
675+
req.GetBody = ireq.GetBody
675676
req.ContentLength = ireq.ContentLength
676677
}
677678

src/net/http/client_test.go

Lines changed: 55 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1962,6 +1962,61 @@ func testTransportBodyReadError(t *testing.T, mode testMode) {
19621962
}
19631963
}
19641964

1965+
// Make sure the retries copies the GetBody in the request.
1966+
func TestRedirectGetBody(t *testing.T) { run(t, testRedirectGetBody) }
1967+
1968+
func testRedirectGetBody(t *testing.T, mode testMode) {
1969+
ts := newClientServerTest(t, mode, HandlerFunc(func(w ResponseWriter, r *Request) {
1970+
b, err := io.ReadAll(r.Body)
1971+
if err != nil {
1972+
t.Error(err)
1973+
}
1974+
if err = r.Body.Close(); err != nil {
1975+
t.Error(err)
1976+
}
1977+
if s := string(b); s != "hello" {
1978+
t.Errorf("expected hello, got %s", s)
1979+
}
1980+
if r.URL.Path == "/first" {
1981+
Redirect(w, r, "/second", StatusTemporaryRedirect)
1982+
return
1983+
}
1984+
w.Write([]byte("world"))
1985+
})).ts
1986+
c := ts.Client()
1987+
c.Transport = &roundTripperGetBody{c.Transport, t}
1988+
req, err := NewRequest("POST", ts.URL+"/first", strings.NewReader("hello"))
1989+
if err != nil {
1990+
t.Fatal(err)
1991+
}
1992+
res, err := c.Do(req.WithT(t))
1993+
if err != nil {
1994+
t.Fatal(err)
1995+
}
1996+
b, err := io.ReadAll(res.Body)
1997+
if err != nil {
1998+
t.Fatal(err)
1999+
}
2000+
if err = res.Body.Close(); err != nil {
2001+
t.Fatal(err)
2002+
}
2003+
if s := string(b); s != "world" {
2004+
t.Fatalf("expected world, got %s", s)
2005+
}
2006+
}
2007+
2008+
type roundTripperGetBody struct {
2009+
Transport RoundTripper
2010+
t *testing.T
2011+
}
2012+
2013+
func (r *roundTripperGetBody) RoundTrip(req *Request) (*Response, error) {
2014+
if req.GetBody == nil {
2015+
r.t.Error("missing Request.GetBody")
2016+
}
2017+
return r.Transport.RoundTrip(req)
2018+
}
2019+
19652020
type roundTripperWithoutCloseIdle struct{}
19662021

19672022
func (roundTripperWithoutCloseIdle) RoundTrip(*Request) (*Response, error) { panic("unused") }

0 commit comments

Comments
 (0)