This is an automated email from the ASF dual-hosted git repository.
markt-asf pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/tomcat.git
The following commit(s) were added to refs/heads/main by this push:
new 2be4fea500 Treat DATA on a RST-closed stream as a connection error
(#1129)
2be4fea500 is described below
commit 2be4fea50011b50e2bac267351fd131afa5e88a8
Author: Arturo Bernal <[email protected]>
AuthorDate: Wed Nov 11 21:31:51 2026 +0100
Treat DATA on a RST-closed stream as a connection error (#1129)
RFC 9113, section 5.1 permits an endpoint to treat receipt of any frame
other than PRIORITY, WINDOW_UPDATE, or RST_STREAM on a closed stream as
a connection error (Section 5.4.1) of type STREAM_CLOSED.
The CLOSED_RST_RX state (stream closed because a RST_STREAM was received
from the peer) had connectionErrorForInvalidFrame=false, so any frame not
in the permitted set — in particular DATA — triggered a StreamException
and caused the server to reply with a RST_STREAM (stream error) instead
of closing the connection with GOAWAY (connection error).
Fix: set connectionErrorForInvalidFrame=true for CLOSED_RST_RX so that
unexpected frames such as DATA trigger a connection error (GOAWAY
STREAM_CLOSED). Add RST and WINDOW_UPDATE to the permitted set so they
are silently discarded as expected for in-flight frames after a reset.
Update TestHttp2Section_5_1#testClosedInvalidFrame01 to assert the
correct connection-error (GOAWAY STREAM_CLOSED) response.
---
.../apache/coyote/http2/StreamStateMachine.java | 6 ++-
.../apache/coyote/http2/TestHttp2Section_5_1.java | 49 ++++++++++++++++++++--
2 files changed, 50 insertions(+), 5 deletions(-)
diff --git a/java/org/apache/coyote/http2/StreamStateMachine.java
b/java/org/apache/coyote/http2/StreamStateMachine.java
index 469cce99b3..faec05b27b 100644
--- a/java/org/apache/coyote/http2/StreamStateMachine.java
+++ b/java/org/apache/coyote/http2/StreamStateMachine.java
@@ -202,8 +202,10 @@ class StreamStateMachine {
Http2Error.STREAM_CLOSED, FrameType.PRIORITY,
FrameType.RST,
FrameType.WINDOW_UPDATE),
- CLOSED_RST_RX (false, false, false, false,
- Http2Error.STREAM_CLOSED, FrameType.PRIORITY),
+ CLOSED_RST_RX (false, false, false, true,
+ Http2Error.STREAM_CLOSED, FrameType.PRIORITY,
+ FrameType.RST,
+
FrameType.WINDOW_UPDATE),
CLOSED_RST_TX (false, false, false, false,
Http2Error.STREAM_CLOSED, FrameType.DATA,
FrameType.HEADERS,
diff --git a/test/org/apache/coyote/http2/TestHttp2Section_5_1.java
b/test/org/apache/coyote/http2/TestHttp2Section_5_1.java
index fea6b584f7..83614dfb7a 100644
--- a/test/org/apache/coyote/http2/TestHttp2Section_5_1.java
+++ b/test/org/apache/coyote/http2/TestHttp2Section_5_1.java
@@ -156,7 +156,11 @@ public class TestHttp2Section_5_1 extends Http2TestBase {
@Test
public void testClosedInvalidFrame01() throws Exception {
- // HTTP2 upgrade
+ // RFC 9113, section 5.1 permits an endpoint to treat receipt of any
frame other than
+ // PRIORITY, WINDOW_UPDATE, or RST_STREAM on a closed stream as a
connection error of
+ // type STREAM_CLOSED. Tomcat adopts this stricter policy for the
CLOSED_RST_RX state,
+ // so receiving DATA after RST_STREAM produces a GOAWAY rather than a
RST_STREAM.
+
http2Connect();
// Send the headers for a POST (END_HEADERS set, END_STREAM not set)
that promises a body but does not send it.
@@ -171,8 +175,47 @@ public class TestHttp2Section_5_1 extends Http2TestBase {
sendData(3, new byte[] {});
parser.readFrame();
- Assert.assertTrue(output.getTrace(),
- output.getTrace().startsWith("3-RST-[" +
Http2Error.STREAM_CLOSED.getCode() + "]"));
+ handleGoAwayResponse(3, Http2Error.STREAM_CLOSED);
+ }
+
+
+ @Test
+ public void testRstStreamAfterRstStreamReceived() throws Exception {
+ // RFC 9113, section 5.1: RST_STREAM on a closed stream must be
silently ignored.
+ // A second RST_STREAM after the stream has entered CLOSED_RST_RX must
not produce
+ // a connection error; the connection must remain open.
+ http2Connect();
+
+ sendSimpleGetRequest(3);
+ readSimpleGetResponse();
+ output.clearTrace();
+
+ sendRst(3, Http2Error.CANCEL.getCode());
+ sendRst(3, Http2Error.CANCEL.getCode());
+
+ sendSimpleGetRequest(5);
+ readSimpleGetResponse();
+ Assert.assertTrue(output.getTrace(),
output.getTrace().contains(getSimpleResponseTrace(5)));
+ }
+
+
+ @Test
+ public void testWindowUpdateAfterRstStreamReceived() throws Exception {
+ // RFC 9113, section 5.1: WINDOW_UPDATE on a closed stream must be
silently ignored.
+ // Receiving WINDOW_UPDATE after the stream has entered CLOSED_RST_RX
must not produce
+ // a connection error; the connection must remain open.
+ http2Connect();
+
+ sendSimpleGetRequest(3);
+ readSimpleGetResponse();
+ output.clearTrace();
+
+ sendRst(3, Http2Error.CANCEL.getCode());
+ sendWindowUpdate(3, 100);
+
+ sendSimpleGetRequest(5);
+ readSimpleGetResponse();
+ Assert.assertTrue(output.getTrace(),
output.getTrace().contains(getSimpleResponseTrace(5)));
}
---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]