Skip to content

Commit

Permalink
[release-branch.go1.15-bundle] net/http2: send WINDOW_UPDATE on a bod…
Browse files Browse the repository at this point in the history
…y'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.
For golang/go#41387.

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/+/264058
Run-TryBot: Dmitri Shuralyov <[email protected]>
Reviewed-by: Alexander Rakoczy <[email protected]>
Trust: Dmitri Shuralyov <[email protected]>
  • Loading branch information
fraenkel authored and dmitshur committed Oct 22, 2020
1 parent d64cff4 commit abf26a1
Show file tree
Hide file tree
Showing 2 changed files with 60 additions and 0 deletions.
1 change: 1 addition & 0 deletions http2/server.go
Original file line number Diff line number Diff line change
Expand Up @@ -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) {
Expand Down
59 changes: 59 additions & 0 deletions http2/server_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -4098,3 +4098,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)
}
}

0 comments on commit abf26a1

Please sign in to comment.