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 83fb7d248..c5c82f91b 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 @@ -1263,17 +1263,18 @@ private void consumeSettingsFrame(final ByteBuffer payload) throws IOException { final H2Param param = H2Param.valueOf(code); if (param != null) { validateSetting(param, value); + final int boundedValue = value < 0 ? Integer.MAX_VALUE : value; switch (param) { case HEADER_TABLE_SIZE: try { - configBuilder.setHeaderTableSize(value); + configBuilder.setHeaderTableSize(boundedValue); } catch (final IllegalArgumentException ex) { throw new H2ConnectionException(H2Error.PROTOCOL_ERROR, ex.getMessage()); } break; case MAX_CONCURRENT_STREAMS: try { - configBuilder.setMaxConcurrentStreams(value); + configBuilder.setMaxConcurrentStreams(boundedValue); } catch (final IllegalArgumentException ex) { throw new H2ConnectionException(H2Error.PROTOCOL_ERROR, ex.getMessage()); } @@ -1301,7 +1302,7 @@ private void consumeSettingsFrame(final ByteBuffer payload) throws IOException { break; case MAX_HEADER_LIST_SIZE: try { - configBuilder.setMaxHeaderListSize(value); + configBuilder.setMaxHeaderListSize(boundedValue); } catch (final IllegalArgumentException ex) { throw new H2ConnectionException(H2Error.PROTOCOL_ERROR, ex.getMessage()); } 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 b5f50a96c..6d4f385ad 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 @@ -2393,6 +2393,91 @@ void testRemoteHeaderTableSizeChangesRemainLocallyBounded() throws Exception { } } + + @Test + void testUnsignedHeaderTableSizeSettingAccepted() throws Exception { + final AbstractH2StreamMultiplexer mux = new H2StreamMultiplexerImpl( + protocolIOSession, + FRAME_FACTORY, + StreamIdGenerator.ODD, + httpProcessor, + CharCodingConfig.DEFAULT, + H2Config.custom().build(), + h2StreamListener, + () -> streamHandler); + try { + final ByteBuffer payload = ByteBuffer.allocate(6); + payload.putShort((short) H2Param.HEADER_TABLE_SIZE.getCode()); + payload.putInt(-1); // 0xffffffff + payload.flip(); + + final RawFrame settingsFrame = + new RawFrame(FrameType.SETTINGS.getValue(), 0, 0, payload); + + Assertions.assertDoesNotThrow( + () -> mux.onInput(ByteBuffer.wrap(encodeFrame(settingsFrame)))); + Assertions.assertEquals( + H2Config.INIT.getHeaderTableSize(), + getHPackEncoder(mux).getMaxTableSize()); + } finally { + mux.close(); + } + } + + @Test + void testUnsignedMaxConcurrentStreamsSettingAccepted() throws Exception { + final AbstractH2StreamMultiplexer mux = new H2StreamMultiplexerImpl( + protocolIOSession, + FRAME_FACTORY, + StreamIdGenerator.ODD, + httpProcessor, + CharCodingConfig.DEFAULT, + H2Config.custom().build(), + h2StreamListener, + () -> streamHandler); + try { + final ByteBuffer payload = ByteBuffer.allocate(6); + payload.putShort((short) H2Param.MAX_CONCURRENT_STREAMS.getCode()); + payload.putInt(Integer.MIN_VALUE); // 0x80000000 + payload.flip(); + + final RawFrame settingsFrame = + new RawFrame(FrameType.SETTINGS.getValue(), 0, 0, payload); + + Assertions.assertDoesNotThrow( + () -> mux.onInput(ByteBuffer.wrap(encodeFrame(settingsFrame)))); + } finally { + mux.close(); + } + } + + @Test + void testUnsignedMaxHeaderListSizeSettingAccepted() throws Exception { + final AbstractH2StreamMultiplexer mux = new H2StreamMultiplexerImpl( + protocolIOSession, + FRAME_FACTORY, + StreamIdGenerator.ODD, + httpProcessor, + CharCodingConfig.DEFAULT, + H2Config.custom().build(), + h2StreamListener, + () -> streamHandler); + try { + final ByteBuffer payload = ByteBuffer.allocate(6); + payload.putShort((short) H2Param.MAX_HEADER_LIST_SIZE.getCode()); + payload.putInt(-1); // 0xffffffff + payload.flip(); + + final RawFrame settingsFrame = + new RawFrame(FrameType.SETTINGS.getValue(), 0, 0, payload); + + Assertions.assertDoesNotThrow( + () -> mux.onInput(ByteBuffer.wrap(encodeFrame(settingsFrame)))); + } finally { + mux.close(); + } + } + private static HPackEncoder getHPackEncoder(final AbstractH2StreamMultiplexer multiplexer) throws Exception { final Field field = AbstractH2StreamMultiplexer.class.getDeclaredField("hPackEncoder"); field.setAccessible(true);