Skip to content

Commit bd4fcd0

Browse files
nerdatmathbradfitz
authored andcommitted
net/http: fix double-close of req.Body
Add a test and fix for the request body being closed twice. Fixes #19186 Change-Id: I1e35ad4aebfef68e6099c1dba7986883afdef4d7 Reviewed-on: https://go-review.googlesource.com/37298 Reviewed-by: Emmanuel Odeke <[email protected]> Reviewed-by: Brad Fitzpatrick <[email protected]> Run-TryBot: Emmanuel Odeke <[email protected]> TryBot-Result: Gobot Gobot <[email protected]>
1 parent eab99a8 commit bd4fcd0

File tree

2 files changed

+38
-5
lines changed

2 files changed

+38
-5
lines changed

src/net/http/client.go

Lines changed: 11 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -494,17 +494,21 @@ func (c *Client) Do(req *Request) (*Response, error) {
494494
}
495495

496496
var (
497-
deadline = c.deadline()
498-
reqs []*Request
499-
resp *Response
500-
copyHeaders = c.makeHeadersCopier(req)
497+
deadline = c.deadline()
498+
reqs []*Request
499+
resp *Response
500+
copyHeaders = c.makeHeadersCopier(req)
501+
reqBodyClosed = false // have we closed the current req.Body?
501502

502503
// Redirect behavior:
503504
redirectMethod string
504505
includeBody bool
505506
)
506507
uerr := func(err error) error {
507-
req.closeBody()
508+
// the body may have been closed already by c.send()
509+
if !reqBodyClosed {
510+
req.closeBody()
511+
}
508512
method := valueOrDefault(reqs[0].Method, "GET")
509513
var urlStr string
510514
if resp != nil && resp.Request != nil {
@@ -596,6 +600,8 @@ func (c *Client) Do(req *Request) (*Response, error) {
596600
var err error
597601
var didTimeout func() bool
598602
if resp, didTimeout, err = c.send(req, deadline); err != nil {
603+
// c.send() always closes req.Body
604+
reqBodyClosed = true
599605
if !deadline.IsZero() && didTimeout() {
600606
err = &httpError{
601607
err: err.Error() + " (Client.Timeout exceeded while awaiting headers)",

src/net/http/clientserver_test.go

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1381,3 +1381,30 @@ func testServerUndeclaredTrailers(t *testing.T, h2 bool) {
13811381
t.Errorf("Trailer = %#v; want %#v", res.Trailer, want)
13821382
}
13831383
}
1384+
1385+
func TestBadResponseAfterReadingBody(t *testing.T) {
1386+
defer afterTest(t)
1387+
cst := newClientServerTest(t, false, HandlerFunc(func(w ResponseWriter, r *Request) {
1388+
_, err := io.Copy(ioutil.Discard, r.Body)
1389+
if err != nil {
1390+
t.Fatal(err)
1391+
}
1392+
c, _, err := w.(Hijacker).Hijack()
1393+
if err != nil {
1394+
t.Fatal(err)
1395+
}
1396+
defer c.Close()
1397+
fmt.Fprintln(c, "some bogus crap")
1398+
}))
1399+
defer cst.close()
1400+
1401+
closes := 0
1402+
res, err := cst.c.Post(cst.ts.URL, "text/plain", countCloseReader{&closes, strings.NewReader("hello")})
1403+
if err == nil {
1404+
res.Body.Close()
1405+
t.Fatal("expected an error to be returned from Post")
1406+
}
1407+
if closes != 1 {
1408+
t.Errorf("closes = %d; want 1", closes)
1409+
}
1410+
}

0 commit comments

Comments
 (0)