mirror of https://github.com/golang/go.git
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>
This commit is contained in:
parent
df9888ea4e
commit
b69f50faef
|
|
@ -672,6 +672,7 @@ func (c *Client) do(req *Request) (retres *Response, reterr error) {
|
||||||
resp.closeBody()
|
resp.closeBody()
|
||||||
return nil, uerr(err)
|
return nil, uerr(err)
|
||||||
}
|
}
|
||||||
|
req.GetBody = ireq.GetBody
|
||||||
req.ContentLength = ireq.ContentLength
|
req.ContentLength = ireq.ContentLength
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1962,6 +1962,61 @@ func testTransportBodyReadError(t *testing.T, mode testMode) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Make sure the retries copies the GetBody in the request.
|
||||||
|
func TestRedirectGetBody(t *testing.T) { run(t, testRedirectGetBody) }
|
||||||
|
|
||||||
|
func testRedirectGetBody(t *testing.T, mode testMode) {
|
||||||
|
ts := newClientServerTest(t, mode, HandlerFunc(func(w ResponseWriter, r *Request) {
|
||||||
|
b, err := io.ReadAll(r.Body)
|
||||||
|
if err != nil {
|
||||||
|
t.Error(err)
|
||||||
|
}
|
||||||
|
if err = r.Body.Close(); err != nil {
|
||||||
|
t.Error(err)
|
||||||
|
}
|
||||||
|
if s := string(b); s != "hello" {
|
||||||
|
t.Errorf("expected hello, got %s", s)
|
||||||
|
}
|
||||||
|
if r.URL.Path == "/first" {
|
||||||
|
Redirect(w, r, "/second", StatusTemporaryRedirect)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
w.Write([]byte("world"))
|
||||||
|
})).ts
|
||||||
|
c := ts.Client()
|
||||||
|
c.Transport = &roundTripperGetBody{c.Transport, t}
|
||||||
|
req, err := NewRequest("POST", ts.URL+"/first", strings.NewReader("hello"))
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
res, err := c.Do(req.WithT(t))
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
b, err := io.ReadAll(res.Body)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
if err = res.Body.Close(); err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
if s := string(b); s != "world" {
|
||||||
|
t.Fatalf("expected world, got %s", s)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
type roundTripperGetBody struct {
|
||||||
|
Transport RoundTripper
|
||||||
|
t *testing.T
|
||||||
|
}
|
||||||
|
|
||||||
|
func (r *roundTripperGetBody) RoundTrip(req *Request) (*Response, error) {
|
||||||
|
if req.GetBody == nil {
|
||||||
|
r.t.Error("missing Request.GetBody")
|
||||||
|
}
|
||||||
|
return r.Transport.RoundTrip(req)
|
||||||
|
}
|
||||||
|
|
||||||
type roundTripperWithoutCloseIdle struct{}
|
type roundTripperWithoutCloseIdle struct{}
|
||||||
|
|
||||||
func (roundTripperWithoutCloseIdle) RoundTrip(*Request) (*Response, error) { panic("unused") }
|
func (roundTripperWithoutCloseIdle) RoundTrip(*Request) (*Response, error) { panic("unused") }
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue