This is an automated email from the ASF dual-hosted git repository.

markt-asf pushed a commit to branch 10.1.x
in repository https://gitbox.apache.org/repos/asf/tomcat.git


The following commit(s) were added to refs/heads/10.1.x by this push:
     new bc67a5f37a Treat DATA on a RST-closed stream as a connection error 
(#1129)
bc67a5f37a is described below

commit bc67a5f37a3d9feca7b1eade6819f9e24a8ac473
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 4af9b40c9a..044d52eb0e 100644
--- a/java/org/apache/coyote/http2/StreamStateMachine.java
+++ b/java/org/apache/coyote/http2/StreamStateMachine.java
@@ -207,8 +207,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 24f3c03f3a..24fd9063ab 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.
@@ -170,8 +174,47 @@ public class TestHttp2Section_5_1 extends Http2TestBase {
         // Then try sending some data (which should fail)
         sendData(3, new byte[] {});
 
-        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]

Reply via email to