aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorLuan Santos <cfcluan@gmail.com>2017-09-11 08:37:50 -0700
committerTom Bergan <tombergan@google.com>2017-09-11 23:10:06 +0000
commit78c4dc37097fa98f73de02ffe1709b776a78354d (patch)
treedf8fc6f9eed5033714c450cf0f789aebbac1c0ed /src
parentcf872fae78c48b89814379d7e4a53d1a92b7388f (diff)
downloadgo-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.go1
-rw-r--r--src/net/http/transport_test.go28
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) {