From 9a44908bee01e65cfdbb2348f6c97de24b920c74 Mon Sep 17 00:00:00 2001 From: Ludovic Orban Date: Fri, 10 Jan 2025 16:31:14 +0100 Subject: [PATCH 1/2] #12690 cap MAX_HEADER_LIST_SIZE Signed-off-by: Ludovic Orban --- .../org/eclipse/jetty/http2/HTTP2Session.java | 7 +++- .../jetty/http2/hpack/HpackEncoder.java | 2 +- .../jetty/http2/tests/SettingsTest.java | 36 +++++++++++++++++++ 3 files changed, 43 insertions(+), 2 deletions(-) diff --git a/jetty-core/jetty-http2/jetty-http2-common/src/main/java/org/eclipse/jetty/http2/HTTP2Session.java b/jetty-core/jetty-http2/jetty-http2-common/src/main/java/org/eclipse/jetty/http2/HTTP2Session.java index 5f622fa09a47..07281e28ec50 100644 --- a/jetty-core/jetty-http2/jetty-http2-common/src/main/java/org/eclipse/jetty/http2/HTTP2Session.java +++ b/jetty-core/jetty-http2/jetty-http2-common/src/main/java/org/eclipse/jetty/http2/HTTP2Session.java @@ -464,9 +464,14 @@ private void configure(Map settings, boolean local) if (LOG.isDebugEnabled()) LOG.debug("Updating {} max header list size to {} for {}", local ? "decoder" : "encoder", value, this); if (local) + { parser.getHpackDecoder().setMaxHeaderListSize(value); + } else - generator.getHpackEncoder().setMaxHeaderListSize(value); + { + HpackEncoder hpackEncoder = generator.getHpackEncoder(); + hpackEncoder.setMaxHeaderListSize(Math.min(value, hpackEncoder.getMaxHeaderListSize())); + } } case SettingsFrame.ENABLE_CONNECT_PROTOCOL -> { diff --git a/jetty-core/jetty-http2/jetty-http2-hpack/src/main/java/org/eclipse/jetty/http2/hpack/HpackEncoder.java b/jetty-core/jetty-http2/jetty-http2-hpack/src/main/java/org/eclipse/jetty/http2/hpack/HpackEncoder.java index bcbac88974d4..d58182c76520 100644 --- a/jetty-core/jetty-http2/jetty-http2-hpack/src/main/java/org/eclipse/jetty/http2/hpack/HpackEncoder.java +++ b/jetty-core/jetty-http2/jetty-http2-hpack/src/main/java/org/eclipse/jetty/http2/hpack/HpackEncoder.java @@ -156,7 +156,7 @@ public int getMaxHeaderListSize() public void setMaxHeaderListSize(int maxHeaderListSize) { - _maxHeaderListSize = maxHeaderListSize; + _maxHeaderListSize = maxHeaderListSize > 0 ? maxHeaderListSize : HpackContext.DEFAULT_MAX_HEADER_LIST_SIZE; } public HpackContext getHpackContext() diff --git a/jetty-core/jetty-http2/jetty-http2-tests/src/test/java/org/eclipse/jetty/http2/tests/SettingsTest.java b/jetty-core/jetty-http2/jetty-http2-tests/src/test/java/org/eclipse/jetty/http2/tests/SettingsTest.java index f7224ec82edc..578a64d18659 100644 --- a/jetty-core/jetty-http2/jetty-http2-tests/src/test/java/org/eclipse/jetty/http2/tests/SettingsTest.java +++ b/jetty-core/jetty-http2/jetty-http2-tests/src/test/java/org/eclipse/jetty/http2/tests/SettingsTest.java @@ -446,6 +446,42 @@ public void onGoAway(Session session, GoAwayFrame frame) assertTrue(goAwayLatch.await(5, TimeUnit.SECONDS)); } + @Test + public void testMaxHeaderListSizeCappedByClient() throws Exception + { + int maxHeadersSize = 2 * 1024; + CountDownLatch goAwayLatch = new CountDownLatch(1); + start(new ServerSessionListener() + { + @Override + public Map onPreface(Session session) + { + return Map.of(SettingsFrame.MAX_HEADER_LIST_SIZE, maxHeadersSize); + } + + @Override + public void onGoAway(Session session, GoAwayFrame frame) + { + goAwayLatch.countDown(); + } + }); + http2Client.setMaxRequestHeadersSize(maxHeadersSize / 2); + + Session clientSession = newClientSession(new Session.Listener() {}); + HttpFields requestHeaders = HttpFields.build() + .put("X-Large", "x".repeat(maxHeadersSize - 256)); // 256 bytes to account for the other headers + MetaData.Request request = newRequest("GET", requestHeaders); + HeadersFrame frame = new HeadersFrame(request, null, true); + + Throwable failure = assertThrows(ExecutionException.class, + () -> clientSession.newStream(frame, new Stream.Listener() {}).get(5, TimeUnit.SECONDS)) + .getCause(); + // The HPACK context is compromised trying to encode the large header. + assertThat(failure, Matchers.instanceOf(HpackException.SessionException.class)); + + assertTrue(goAwayLatch.await(5, TimeUnit.SECONDS)); + } + @Test public void testMaxHeaderListSizeExceededByServer() throws Exception { From 652583cb5fe228a1a0cefc9167be6656255738b9 Mon Sep 17 00:00:00 2001 From: Ludovic Orban Date: Fri, 10 Jan 2025 16:57:48 +0100 Subject: [PATCH 2/2] #12690 fix test Signed-off-by: Ludovic Orban --- .../src/test/java/org/eclipse/jetty/http2/tests/HTTP2Test.java | 1 + 1 file changed, 1 insertion(+) diff --git a/jetty-core/jetty-http2/jetty-http2-tests/src/test/java/org/eclipse/jetty/http2/tests/HTTP2Test.java b/jetty-core/jetty-http2/jetty-http2-tests/src/test/java/org/eclipse/jetty/http2/tests/HTTP2Test.java index 6245602464ca..16c35a251c33 100644 --- a/jetty-core/jetty-http2/jetty-http2-tests/src/test/java/org/eclipse/jetty/http2/tests/HTTP2Test.java +++ b/jetty-core/jetty-http2/jetty-http2-tests/src/test/java/org/eclipse/jetty/http2/tests/HTTP2Test.java @@ -1315,6 +1315,7 @@ public boolean handle(Request request, Response response, Callback callback) }, httpConfig); connector.getBean(AbstractHTTP2ServerConnectionFactory.class).setMaxFrameSize(17 * 1024); http2Client.setMaxFrameSize(18 * 1024); + http2Client.setMaxRequestHeadersSize(2 * maxHeadersSize); // Wait for the SETTINGS frame to be exchanged. CountDownLatch settingsLatch = new CountDownLatch(1);