Skip to content

Commit

Permalink
[release-branch.go1.14] net/http2: send WINDOW_UPDATE on a body's wri…
Browse files Browse the repository at this point in the history
…te 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]>
  • Loading branch information
fraenkel authored and dmitshur committed Oct 12, 2020
1 parent ef20fe5 commit 9ef5ab9
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 @@ -1696,6 +1696,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 9ef5ab9

Please sign in to comment.