From: Luan Santos Date: Mon, 11 Sep 2017 15:37:50 +0000 (-0700) Subject: net/http: allow reuse of http.Request objects X-Git-Tag: go1.10beta1~1133 X-Git-Url: http://www.git.cypherpunks.su/?a=commitdiff_plain;h=78c4dc37097fa98f73de02ffe1709b776a78354d;p=gostls13.git net/http: allow reuse of http.Request objects Calling response.Body.Close() early would generarate a race before this. Since closing would return early before the main code path had a chance to reset the request canceler. Having a non-nil request canceler at the start of the next request would cause a "request canceled" error. Here we simply wait for the eofc channel to be closed before returning from earlyCloseFn, ensuring that the caller won't be re-using that Request object before we have a chance to reset the request canceler to nil. Fixes #21838 Change-Id: I641815526c6ac63d1816c9b6ad49d73715f7a5cb Reviewed-on: https://go-review.googlesource.com/62891 Run-TryBot: Tom Bergan TryBot-Result: Gobot Gobot Reviewed-by: Tom Bergan --- diff --git a/src/net/http/transport.go b/src/net/http/transport.go index b31b7805b9..9182e9454b 100644 --- a/src/net/http/transport.go +++ b/src/net/http/transport.go @@ -1616,6 +1616,7 @@ func (pc *persistConn) readLoop() { body: resp.Body, earlyCloseFn: func() error { waitForBodyRead <- false + <-eofc // will be closed by deferred call at the end of the function return nil }, diff --git a/src/net/http/transport_test.go b/src/net/http/transport_test.go index 27b55dca2f..39b5cd358f 100644 --- a/src/net/http/transport_test.go +++ b/src/net/http/transport_test.go @@ -124,6 +124,34 @@ func (tcs *testConnSet) check(t *testing.T) { } } +func TestReuseRequest(t *testing.T) { + defer afterTest(t) + ts := httptest.NewServer(HandlerFunc(func(w ResponseWriter, r *Request) { + w.Write([]byte("{}")) + })) + defer ts.Close() + + c := ts.Client() + req, _ := NewRequest("GET", ts.URL, nil) + res, err := c.Do(req) + if err != nil { + t.Fatal(err) + } + err = res.Body.Close() + if err != nil { + t.Fatal(err) + } + + res, err = c.Do(req) + if err != nil { + t.Fatal(err) + } + err = res.Body.Close() + if err != nil { + t.Fatal(err) + } +} + // Two subsequent requests and verify their response is the same. // The response from the server is our own IP:port func TestTransportKeepAlives(t *testing.T) {