http2: fix conn flow control when stream closes on bad content-length
HTTP2 server does not send WINDOW_UPDATE when the client
sends more data than declared in the content-length header.
Client flow control can eventually run out of available bytes which
hangs the client connection as it cannot write DATA frames for any
stream any longer.
Fixes: golang/go#54185
Change-Id: I48ae3212fb31ce302715abe129adf5c9625faf12
GitHub-Last-Rev: 1351d3b416b6ecbfc396b7a7d43dba5115b4aaf7
GitHub-Pull-Request: golang/net#143
Reviewed-on: https://go-review.googlesource.com/c/net/+/421974
Reviewed-by: Than McIntosh <thanm@google.com>
Run-TryBot: Damien Neil <dneil@google.com>
Reviewed-by: Damien Neil <dneil@google.com>
TryBot-Result: Gopher Robot <gobot@golang.org>
diff --git a/http2/server.go b/http2/server.go
index 47524a6..2368499 100644
--- a/http2/server.go
+++ b/http2/server.go
@@ -1747,6 +1747,12 @@
// Sender sending more than they'd declared?
if st.declBodyBytes != -1 && st.bodyBytes+int64(len(data)) > st.declBodyBytes {
+ if sc.inflow.available() < int32(f.Length) {
+ return sc.countError("data_flow", streamError(id, ErrCodeFlowControl))
+ }
+ sc.inflow.take(int32(f.Length))
+ sc.sendWindowUpdate(nil, int(f.Length)) // conn-level
+
st.body.CloseWithError(fmt.Errorf("sender tried to send more than declared Content-Length of %d bytes", st.declBodyBytes))
// RFC 7540, sec 8.1.2.6: A request or response is also malformed if the
// value of a content-length header field does not equal the sum of the
diff --git a/http2/server_test.go b/http2/server_test.go
index 2a677b9..ddd3daf 100644
--- a/http2/server_test.go
+++ b/http2/server_test.go
@@ -809,6 +809,9 @@
EndHeaders: true,
})
st.writeData(1, true, []byte("12345"))
+ // Return flow control bytes back, since the data handler closed
+ // the stream.
+ st.wantWindowUpdate(0, 5)
})
}
@@ -3918,7 +3921,7 @@
EndHeaders: true,
})
st.writeData(1, true, []byte("12345"))
-
+ st.wantWindowUpdate(0, 5)
st.wantRSTStream(1, ErrCodeProtocol)
})
}