This is an automated email from the ASF dual-hosted git repository.
markt-asf pushed a commit to branch 11.0.x
in repository https://gitbox.apache.org/repos/asf/tomcat.git
The following commit(s) were added to refs/heads/11.0.x by this push:
new 37727724dd Clarify stream flow-control comment; add RST_STREAM
regression test (#1133)
37727724dd is described below
commit 37727724dd91df260beb9c605b710774227c0ccc
Author: Arturo Bernal <[email protected]>
AuthorDate: Thu Nov 12 17:33:06 2026 +0100
Clarify stream flow-control comment; add RST_STREAM regression test (#1133)
When a DATA frame payload exceeds the remaining capacity of the stream's
receive buffer, Http2Parser throws StreamException(FLOW_CONTROL_ERROR),
resulting in RST_STREAM. This is a stream-level check: the inBuffer is
scoped to the per-stream initial window, so the violation affects only
that stream; the connection and other streams remain open.
RFC 9113, section 6.9, permits either a stream error or a connection
error for this case (MAY). Tomcat's choice of RST_STREAM is correct and
avoids unnecessary collateral damage to multiplexed streams.
Adds TestHttp2Section_6_9.testDataFrameExceedsFlowControlWindow as a
regression guard for this behavior.
---
java/org/apache/coyote/http2/Http2Parser.java | 2 +-
.../apache/coyote/http2/TestHttp2Section_6_9.java | 53 ++++++++++++++++++++++
2 files changed, 54 insertions(+), 1 deletion(-)
diff --git a/java/org/apache/coyote/http2/Http2Parser.java
b/java/org/apache/coyote/http2/Http2Parser.java
index 5566314e7e..ff3adb89a4 100644
--- a/java/org/apache/coyote/http2/Http2Parser.java
+++ b/java/org/apache/coyote/http2/Http2Parser.java
@@ -202,7 +202,7 @@ class Http2Parser {
} else {
synchronized (dest) {
if (dest.remaining() < dataLength) {
- // Client has sent more data than permitted by Window size
+ // Client has sent more data than permitted by the stream
flow-control window.
swallowPayload(streamId, FrameType.DATA.getId(),
dataLength, false, buffer);
if (Flags.hasPadding(flags)) {
swallowPayload(streamId, FrameType.DATA.getId(),
padLength, true, buffer);
diff --git a/test/org/apache/coyote/http2/TestHttp2Section_6_9.java
b/test/org/apache/coyote/http2/TestHttp2Section_6_9.java
index 28ad585761..bb2c4c663a 100644
--- a/test/org/apache/coyote/http2/TestHttp2Section_6_9.java
+++ b/test/org/apache/coyote/http2/TestHttp2Section_6_9.java
@@ -269,4 +269,57 @@ public class TestHttp2Section_6_9 extends Http2TestBase {
sendSettings(0, false, new SettingValue(4, 1 << 30));
handleGoAwayResponse(3, Http2Error.FLOW_CONTROL_ERROR);
}
+
+
+ @Test
+ public void testDataFrameExceedsFlowControlWindow() throws Exception {
+ // Configure the server with a small initial flow-control window so it
+ // is easy to exceed from a test.
+ enableHttp2();
+ http2Protocol.setInitialWindowSize(1024);
+ configureAndStartWebApplication();
+ openClientConnection();
+ doHttpUpgrade();
+ sendClientPreface();
+
+ // Read initial server frames. The exact count varies (SETTINGS,
SETTINGS-ACK,
+ // PING, response HEADERS and DATA for the upgrade request on stream
1).
+ parser.readFrame();
+ parser.readFrame();
+ parser.readFrame();
+ parser.readFrame();
+ parser.readFrame();
+
+ // Confirm the expected SETTINGS frame is present
+ String trace = output.getTrace();
+ Assert.assertTrue(trace, trace.contains("0-Settings-[4]-[1024]"));
+ output.clearTrace();
+
+ // Open a stream so the server expects request body data.
+ sendSimplePostRequest(3, null, false);
+ output.clearTrace();
+
+ // Send 2 kB of data, exceeding the advertised 1 kB stream window.
+ // Expect the stream to be reset with FLOW_CONTROL_ERROR; the
connection
+ // must remain open because this is a stream-level window violation.
+ sendData(3, new byte[2048]);
+
+ // A connection-level WINDOW_UPDATE may precede the RST_STREAM as a
+ // side-effect of consuming the excess payload.
+ while (!output.getTrace().contains("3-RST-")) {
+ parser.readFrame();
+ }
+ Assert.assertTrue(output.getTrace(),
+ output.getTrace().contains("3-RST-[" +
Http2Error.FLOW_CONTROL_ERROR.getCode() + "]"));
+ output.clearTrace();
+
+ // The connection must still be open and usable for other streams.
+ sendSimpleGetRequest(5);
+ // The response to the upgrade request on stream 1 may still be
pending so
+ // keep reading until the end of the response on stream 5 has been
seen.
+ while (!output.getTrace().contains("5-EndOfStream")) {
+ parser.readFrame();
+ }
+ Assert.assertTrue(output.getTrace(),
output.getTrace().contains(getSimpleResponseTrace(5)));
+ }
}
---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]