]> Cypherpunks repositories - gostls13.git/commitdiff
net/http: allow reuse of http.Request objects
authorLuan Santos <cfcluan@gmail.com>
Mon, 11 Sep 2017 15:37:50 +0000 (08:37 -0700)
committerTom Bergan <tombergan@google.com>
Mon, 11 Sep 2017 23:10:06 +0000 (23:10 +0000)
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>
src/net/http/transport.go
src/net/http/transport_test.go

index b31b7805b9179c2f8cb34b76c31f45d5c2bb6011..9182e9454b98625b03cf4f212ebec9708e5f7984 100644 (file)
@@ -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
 
                        },
index 27b55dca2f322789cea031bec9b33cf6a67bc6dd..39b5cd358f810a006007ba5f4d86200cccbe9fd1 100644 (file)
@@ -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) {