Skip to content

Commit 78c4dc3

Browse files
luantombergan
authored andcommitted
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 <[email protected]> TryBot-Result: Gobot Gobot <[email protected]> Reviewed-by: Tom Bergan <[email protected]>
1 parent cf872fa commit 78c4dc3

File tree

2 files changed

+29
-0
lines changed

2 files changed

+29
-0
lines changed

src/net/http/transport.go

+1
Original file line numberDiff line numberDiff line change
@@ -1616,6 +1616,7 @@ func (pc *persistConn) readLoop() {
16161616
body: resp.Body,
16171617
earlyCloseFn: func() error {
16181618
waitForBodyRead <- false
1619+
<-eofc // will be closed by deferred call at the end of the function
16191620
return nil
16201621

16211622
},

src/net/http/transport_test.go

+28
Original file line numberDiff line numberDiff line change
@@ -124,6 +124,34 @@ func (tcs *testConnSet) check(t *testing.T) {
124124
}
125125
}
126126

127+
func TestReuseRequest(t *testing.T) {
128+
defer afterTest(t)
129+
ts := httptest.NewServer(HandlerFunc(func(w ResponseWriter, r *Request) {
130+
w.Write([]byte("{}"))
131+
}))
132+
defer ts.Close()
133+
134+
c := ts.Client()
135+
req, _ := NewRequest("GET", ts.URL, nil)
136+
res, err := c.Do(req)
137+
if err != nil {
138+
t.Fatal(err)
139+
}
140+
err = res.Body.Close()
141+
if err != nil {
142+
t.Fatal(err)
143+
}
144+
145+
res, err = c.Do(req)
146+
if err != nil {
147+
t.Fatal(err)
148+
}
149+
err = res.Body.Close()
150+
if err != nil {
151+
t.Fatal(err)
152+
}
153+
}
154+
127155
// Two subsequent requests and verify their response is the same.
128156
// The response from the server is our own IP:port
129157
func TestTransportKeepAlives(t *testing.T) {

0 commit comments

Comments
 (0)