From fa02c869e647ef6d9ead94b3d55508ce232e6d0c Mon Sep 17 00:00:00 2001 From: Arturo Bernal Date: Tue, 29 Sep 2026 12:49:56 +0200 Subject: [PATCH] Fix H2 stream flow control overflow Reset the affected stream when WINDOW_UPDATE overflows its window. Keep connection-level overflow as a connection error. --- .../core5/http2/impl/nio/AbstractH2StreamMultiplexer.java | 3 ++- .../http2/impl/nio/TestAbstractH2StreamMultiplexer.java | 8 ++++++-- 2 files changed, 8 insertions(+), 3 deletions(-) diff --git a/httpcore5-h2/src/main/java/org/apache/hc/core5/http2/impl/nio/AbstractH2StreamMultiplexer.java b/httpcore5-h2/src/main/java/org/apache/hc/core5/http2/impl/nio/AbstractH2StreamMultiplexer.java index dadbf2799..dc296eb75 100644 --- a/httpcore5-h2/src/main/java/org/apache/hc/core5/http2/impl/nio/AbstractH2StreamMultiplexer.java +++ b/httpcore5-h2/src/main/java/org/apache/hc/core5/http2/impl/nio/AbstractH2StreamMultiplexer.java @@ -927,7 +927,8 @@ private void consumeFrame(final RawFrame frame) throws HttpException, IOExceptio try { updateOutputWindow(streamId, stream.getOutputWindow(), delta); } catch (final ArithmeticException ex) { - throw new H2ConnectionException(H2Error.FLOW_CONTROL_ERROR, ex.getMessage()); + stream.localReset(new H2StreamResetException(H2Error.FLOW_CONTROL_ERROR, ex.getMessage())); + requestSessionOutput(); } } } diff --git a/httpcore5-h2/src/test/java/org/apache/hc/core5/http2/impl/nio/TestAbstractH2StreamMultiplexer.java b/httpcore5-h2/src/test/java/org/apache/hc/core5/http2/impl/nio/TestAbstractH2StreamMultiplexer.java index 4b72cfec3..b40898e62 100644 --- a/httpcore5-h2/src/test/java/org/apache/hc/core5/http2/impl/nio/TestAbstractH2StreamMultiplexer.java +++ b/httpcore5-h2/src/test/java/org/apache/hc/core5/http2/impl/nio/TestAbstractH2StreamMultiplexer.java @@ -498,9 +498,13 @@ void testIncrementOverflow() throws Exception { writableChannel.reset(); final RawFrame incrementFrame2 = FRAME_FACTORY.createWindowUpdate(1, 0x7fffffff - 50); outBuffer.write(incrementFrame2, writableChannel); - final H2ConnectionException exception = Assertions.assertThrows(H2ConnectionException.class, () -> + Assertions.assertDoesNotThrow(() -> streamMultiplexer.onInput(ByteBuffer.wrap(writableChannel.toByteArray()))); - Assertions.assertEquals(H2Error.FLOW_CONTROL_ERROR, H2Error.getByCode(exception.getCode())); + Mockito.verify(streamHandler).failed(exceptionCaptor.capture()); + final Exception exception = exceptionCaptor.getValue(); + Assertions.assertInstanceOf(H2StreamResetException.class, exception); + Assertions.assertEquals(H2Error.FLOW_CONTROL_ERROR, + H2Error.getByCode(((H2StreamResetException) exception).getCode())); } @Test