Skip to content

Commit 9ef5ab9

Browse files
fraenkeldmitshur
authored andcommitted
[release-branch.go1.14] 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. Updates golang/go#40423. Fixes golang/go#41386. Change-Id: I546597cedf3715e6617babcb3b62140bf1857a27 Reviewed-on: https://go-review.googlesource.com/c/net/+/245158 Reviewed-by: Emmanuel Odeke <[email protected]> Reviewed-by: Ian Lance Taylor <[email protected]> Run-TryBot: Emmanuel Odeke <[email protected]> TryBot-Result: Go Bot <[email protected]> Trust: Emmanuel Odeke <[email protected]> (cherry picked from commit 5d4f700) Reviewed-on: https://go-review.googlesource.com/c/net/+/258497 Trust: Dmitri Shuralyov <[email protected]> Run-TryBot: Dmitri Shuralyov <[email protected]>
1 parent ef20fe5 commit 9ef5ab9

File tree

2 files changed

+60
-0
lines changed

2 files changed

+60
-0
lines changed

http2/server.go

+1
Original file line numberDiff line numberDiff line change
@@ -1696,6 +1696,7 @@ func (sc *serverConn) processData(f *DataFrame) error {
16961696
if len(data) > 0 {
16971697
wrote, err := st.body.Write(data)
16981698
if err != nil {
1699+
sc.sendWindowUpdate(nil, int(f.Length)-wrote)
16991700
return streamError(id, ErrCodeStreamClosed)
17001701
}
17011702
if wrote != len(data) {

http2/server_test.go

+59
Original file line numberDiff line numberDiff line change
@@ -4098,3 +4098,62 @@ func TestContentEncodingNoSniffing(t *testing.T) {
40984098
})
40994099
}
41004100
}
4101+
4102+
func TestServerWindowUpdateOnBodyClose(t *testing.T) {
4103+
const content = "12345678"
4104+
blockCh := make(chan bool)
4105+
errc := make(chan error, 1)
4106+
st := newServerTester(t, func(w http.ResponseWriter, r *http.Request) {
4107+
buf := make([]byte, 4)
4108+
n, err := io.ReadFull(r.Body, buf)
4109+
if err != nil {
4110+
errc <- err
4111+
return
4112+
}
4113+
if n != len(buf) {
4114+
errc <- fmt.Errorf("too few bytes read: %d", n)
4115+
return
4116+
}
4117+
blockCh <- true
4118+
<-blockCh
4119+
errc <- nil
4120+
})
4121+
defer st.Close()
4122+
4123+
st.greet()
4124+
st.writeHeaders(HeadersFrameParam{
4125+
StreamID: 1, // clients send odd numbers
4126+
BlockFragment: st.encodeHeader(
4127+
":method", "POST",
4128+
"content-length", strconv.Itoa(len(content)),
4129+
),
4130+
EndStream: false, // to say DATA frames are coming
4131+
EndHeaders: true,
4132+
})
4133+
st.writeData(1, false, []byte(content[:5]))
4134+
<-blockCh
4135+
st.stream(1).body.CloseWithError(io.EOF)
4136+
st.writeData(1, false, []byte(content[5:]))
4137+
blockCh <- true
4138+
4139+
increments := len(content)
4140+
for {
4141+
f, err := st.readFrame()
4142+
if err == io.EOF {
4143+
break
4144+
}
4145+
if err != nil {
4146+
t.Fatal(err)
4147+
}
4148+
if wu, ok := f.(*WindowUpdateFrame); ok && wu.StreamID == 0 {
4149+
increments -= int(wu.Increment)
4150+
if increments == 0 {
4151+
break
4152+
}
4153+
}
4154+
}
4155+
4156+
if err := <-errc; err != nil {
4157+
t.Error(err)
4158+
}
4159+
}

0 commit comments

Comments
 (0)