Skip to content

Commit d418f37

Browse files
committed
http2: ignore read errors after closing the request body
We close the request body after receiving an error status code. This is supposed to cause cs.writeRequestBody to return errStopReqBodyWrite. Ensure that it does so if it gets an error reading from the post-close body, rather than returning an error which causes the entire request to be aborted. Change-Id: I7c51928cb678f5baf37148f0df6ab196518d39d4 Reviewed-on: https://go-review.googlesource.com/c/net/+/356969 Trust: Damien Neil <[email protected]> Run-TryBot: Damien Neil <[email protected]> TryBot-Result: Go Bot <[email protected]> Reviewed-by: Brad Fitzpatrick <[email protected]>
1 parent c6ed85c commit d418f37

File tree

2 files changed

+48
-5
lines changed

2 files changed

+48
-5
lines changed

http2/transport.go

Lines changed: 13 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1539,11 +1539,19 @@ func (cs *clientStream) writeRequestBody(req *http.Request) (err error) {
15391539
return err
15401540
}
15411541
}
1542-
if err == io.EOF {
1543-
sawEOF = true
1544-
err = nil
1545-
} else if err != nil {
1546-
return err
1542+
if err != nil {
1543+
cc.mu.Lock()
1544+
bodyClosed := cs.reqBodyClosed
1545+
cc.mu.Unlock()
1546+
switch {
1547+
case bodyClosed:
1548+
return errStopReqBodyWrite
1549+
case err == io.EOF:
1550+
sawEOF = true
1551+
err = nil
1552+
default:
1553+
return err
1554+
}
15471555
}
15481556

15491557
remain := buf[:n]

http2/transport_test.go

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5701,3 +5701,38 @@ func TestTransportCloseResponseBodyWhileRequestBodyHangs(t *testing.T) {
57015701
res.Body.Close()
57025702
pw.Close()
57035703
}
5704+
5705+
func TestTransport300ResponseBody(t *testing.T) {
5706+
reqc := make(chan struct{})
5707+
body := []byte("response body")
5708+
st := newServerTester(t, func(w http.ResponseWriter, r *http.Request) {
5709+
w.WriteHeader(300)
5710+
w.(http.Flusher).Flush()
5711+
<-reqc
5712+
w.Write(body)
5713+
}, optOnlyServer)
5714+
defer st.Close()
5715+
5716+
tr := &Transport{TLSClientConfig: tlsConfigInsecure}
5717+
defer tr.CloseIdleConnections()
5718+
5719+
pr, pw := net.Pipe()
5720+
req, err := http.NewRequest("GET", st.ts.URL, pr)
5721+
if err != nil {
5722+
t.Fatal(err)
5723+
}
5724+
res, err := tr.RoundTrip(req)
5725+
if err != nil {
5726+
t.Fatal(err)
5727+
}
5728+
close(reqc)
5729+
got, err := io.ReadAll(res.Body)
5730+
if err != nil {
5731+
t.Fatalf("error reading response body: %v", err)
5732+
}
5733+
if !bytes.Equal(got, body) {
5734+
t.Errorf("got response body %q, want %q", string(got), string(body))
5735+
}
5736+
res.Body.Close()
5737+
pw.Close()
5738+
}

0 commit comments

Comments
 (0)