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 <dneil@google.com>
Run-TryBot: Damien Neil <dneil@google.com>
TryBot-Result: Go Bot <gobot@golang.org>
Reviewed-by: Brad Fitzpatrick <bradfitz@golang.org>
This commit is contained in:
Damien Neil
2021-10-19 11:18:33 -07:00
parent c6ed85c7a1
commit d418f374d3
2 changed files with 48 additions and 5 deletions

View File

@@ -1539,11 +1539,19 @@ func (cs *clientStream) writeRequestBody(req *http.Request) (err error) {
return err
}
}
if err == io.EOF {
sawEOF = true
err = nil
} else if err != nil {
return err
if err != nil {
cc.mu.Lock()
bodyClosed := cs.reqBodyClosed
cc.mu.Unlock()
switch {
case bodyClosed:
return errStopReqBodyWrite
case err == io.EOF:
sawEOF = true
err = nil
default:
return err
}
}
remain := buf[:n]

View File

@@ -5701,3 +5701,38 @@ func TestTransportCloseResponseBodyWhileRequestBodyHangs(t *testing.T) {
res.Body.Close()
pw.Close()
}
func TestTransport300ResponseBody(t *testing.T) {
reqc := make(chan struct{})
body := []byte("response body")
st := newServerTester(t, func(w http.ResponseWriter, r *http.Request) {
w.WriteHeader(300)
w.(http.Flusher).Flush()
<-reqc
w.Write(body)
}, optOnlyServer)
defer st.Close()
tr := &Transport{TLSClientConfig: tlsConfigInsecure}
defer tr.CloseIdleConnections()
pr, pw := net.Pipe()
req, err := http.NewRequest("GET", st.ts.URL, pr)
if err != nil {
t.Fatal(err)
}
res, err := tr.RoundTrip(req)
if err != nil {
t.Fatal(err)
}
close(reqc)
got, err := io.ReadAll(res.Body)
if err != nil {
t.Fatalf("error reading response body: %v", err)
}
if !bytes.Equal(got, body) {
t.Errorf("got response body %q, want %q", string(got), string(body))
}
res.Body.Close()
pw.Close()
}