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)
 	})
 }