diff --git a/java/org/apache/coyote/http2/Http2Parser.java b/java/org/apache/coyote/http2/Http2Parser.java index 2b07e2d4e32c..76bf1e96b4bd 100644 --- a/java/org/apache/coyote/http2/Http2Parser.java +++ b/java/org/apache/coyote/http2/Http2Parser.java @@ -743,7 +743,7 @@ protected void validateFrame(FrameType expected, FrameType frameType, int stream // NO-OP: RST is OK here } else if (frameType != FrameType.CONTINUATION) { throw new ConnectionException(sm.getString("http2Parser.headers.wrongFrameType", connectionId, - Integer.toString(headersCurrentStream), frameType), Http2Error.COMPRESSION_ERROR); + Integer.toString(headersCurrentStream), frameType), Http2Error.PROTOCOL_ERROR); } } diff --git a/test/org/apache/coyote/http2/TestHttp2Section_4_3.java b/test/org/apache/coyote/http2/TestHttp2Section_4_3.java index 48798b3cd1bf..5d9baeb95dd2 100644 --- a/test/org/apache/coyote/http2/TestHttp2Section_4_3.java +++ b/test/org/apache/coyote/http2/TestHttp2Section_4_3.java @@ -248,4 +248,25 @@ public void testHeaderContinuationNonContiguous() throws Exception { handleGoAwayResponse(3, Http2Error.COMPRESSION_ERROR); } + + + @Test + public void testHeaderContinuationInterleavedDataSameStream() throws Exception { + // HTTP2 upgrade + http2Connect(); + + // Start header block on stream 3 without END_HEADERS + byte[] frameHeader = new byte[9]; + ByteBuffer headersPayload = ByteBuffer.allocate(128); + buildSimpleGetRequestPart1(frameHeader, headersPayload, 3); + writeFrame(frameHeader, headersPayload); + + // Send a DATA frame on the same stream while the header block is open. + // RFC 9113, section 4.3: any frame other than CONTINUATION interleaved + // in a header block MUST be treated as a connection error of type + // PROTOCOL_ERROR. + sendData(3, new byte[0]); + + handleGoAwayResponse(3, Http2Error.PROTOCOL_ERROR); + } }