diff options
| author | Luan Santos <cfcluan@gmail.com> | 2017-09-11 08:37:50 -0700 |
|---|---|---|
| committer | Tom Bergan <tombergan@google.com> | 2017-09-11 23:10:06 +0000 |
| commit | 78c4dc37097fa98f73de02ffe1709b776a78354d (patch) | |
| tree | df8fc6f9eed5033714c450cf0f789aebbac1c0ed /src | |
| parent | cf872fae78c48b89814379d7e4a53d1a92b7388f (diff) | |
| download | go-78c4dc37097fa98f73de02ffe1709b776a78354d.tar.xz | |
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 <tombergan@google.com>
TryBot-Result: Gobot Gobot <gobot@golang.org>
Reviewed-by: Tom Bergan <tombergan@google.com>
Diffstat (limited to 'src')
| -rw-r--r-- | src/net/http/transport.go | 1 | ||||
| -rw-r--r-- | src/net/http/transport_test.go | 28 |
2 files changed, 29 insertions, 0 deletions
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) { |
