mirror of
https://github.com/golang/net.git
synced 2026-03-31 18:37:08 +09:00
net/http2: send WINDOW_UPDATE on a body's write failure
When the body.Write fails during processData, the connection flow control must be updated to account for the data received. The connection's WINDOW_UPDATE should reflect the amount of data that was not successfully written. The stream is about to be closed, so no update is required. Fixes golang/go#40423 Change-Id: I546597cedf3715e6617babcb3b62140bf1857a27 Reviewed-on: https://go-review.googlesource.com/c/net/+/245158 Reviewed-by: Emmanuel Odeke <emm.odeke@gmail.com> Reviewed-by: Ian Lance Taylor <iant@golang.org> Run-TryBot: Emmanuel Odeke <emm.odeke@gmail.com> TryBot-Result: Go Bot <gobot@golang.org> Trust: Emmanuel Odeke <emm.odeke@gmail.com>
This commit is contained in:
committed by
Emmanuel Odeke
parent
05aa5d4ee3
commit
5d4f700557
@@ -1694,6 +1694,7 @@ func (sc *serverConn) processData(f *DataFrame) error {
|
||||
if len(data) > 0 {
|
||||
wrote, err := st.body.Write(data)
|
||||
if err != nil {
|
||||
sc.sendWindowUpdate(nil, int(f.Length)-wrote)
|
||||
return streamError(id, ErrCodeStreamClosed)
|
||||
}
|
||||
if wrote != len(data) {
|
||||
|
||||
@@ -4209,3 +4209,62 @@ func TestContentEncodingNoSniffing(t *testing.T) {
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestServerWindowUpdateOnBodyClose(t *testing.T) {
|
||||
const content = "12345678"
|
||||
blockCh := make(chan bool)
|
||||
errc := make(chan error, 1)
|
||||
st := newServerTester(t, func(w http.ResponseWriter, r *http.Request) {
|
||||
buf := make([]byte, 4)
|
||||
n, err := io.ReadFull(r.Body, buf)
|
||||
if err != nil {
|
||||
errc <- err
|
||||
return
|
||||
}
|
||||
if n != len(buf) {
|
||||
errc <- fmt.Errorf("too few bytes read: %d", n)
|
||||
return
|
||||
}
|
||||
blockCh <- true
|
||||
<-blockCh
|
||||
errc <- nil
|
||||
})
|
||||
defer st.Close()
|
||||
|
||||
st.greet()
|
||||
st.writeHeaders(HeadersFrameParam{
|
||||
StreamID: 1, // clients send odd numbers
|
||||
BlockFragment: st.encodeHeader(
|
||||
":method", "POST",
|
||||
"content-length", strconv.Itoa(len(content)),
|
||||
),
|
||||
EndStream: false, // to say DATA frames are coming
|
||||
EndHeaders: true,
|
||||
})
|
||||
st.writeData(1, false, []byte(content[:5]))
|
||||
<-blockCh
|
||||
st.stream(1).body.CloseWithError(io.EOF)
|
||||
st.writeData(1, false, []byte(content[5:]))
|
||||
blockCh <- true
|
||||
|
||||
increments := len(content)
|
||||
for {
|
||||
f, err := st.readFrame()
|
||||
if err == io.EOF {
|
||||
break
|
||||
}
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if wu, ok := f.(*WindowUpdateFrame); ok && wu.StreamID == 0 {
|
||||
increments -= int(wu.Increment)
|
||||
if increments == 0 {
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if err := <-errc; err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user