diff --git a/codec-http2/src/main/java/io/netty/handler/codec/http2/DefaultHttp2ConnectionDecoder.java b/codec-http2/src/main/java/io/netty/handler/codec/http2/DefaultHttp2ConnectionDecoder.java index c47b83a9fd..7cd935269b 100644 --- a/codec-http2/src/main/java/io/netty/handler/codec/http2/DefaultHttp2ConnectionDecoder.java +++ b/codec-http2/src/main/java/io/netty/handler/codec/http2/DefaultHttp2ConnectionDecoder.java @@ -149,8 +149,7 @@ public class DefaultHttp2ConnectionDecoder implements Http2ConnectionDecoder { * @return the threshold in bytes which should trigger a {@code GO_AWAY} if a set of headers exceeds this amount. */ protected long calculateMaxHeaderListSizeGoAway(long maxHeaderListSize) { - // This is equivalent to `maxHeaderListSize * 1.25` but we avoid floating point multiplication. - return maxHeaderListSize + (maxHeaderListSize >>> 2); + return Http2CodecUtil.calculateMaxHeaderListSizeGoAway(maxHeaderListSize); } private int unconsumedBytes(Http2Stream stream) { diff --git a/codec-http2/src/main/java/io/netty/handler/codec/http2/Http2CodecUtil.java b/codec-http2/src/main/java/io/netty/handler/codec/http2/Http2CodecUtil.java index 4b2860cd53..0de81ecaed 100644 --- a/codec-http2/src/main/java/io/netty/handler/codec/http2/Http2CodecUtil.java +++ b/codec-http2/src/main/java/io/netty/handler/codec/http2/Http2CodecUtil.java @@ -112,6 +112,18 @@ public final class Http2CodecUtil { public static final long DEFAULT_HEADER_LIST_SIZE = 8192; public static final int DEFAULT_MAX_FRAME_SIZE = MAX_FRAME_SIZE_LOWER_BOUND; + /** + * Calculate the threshold in bytes which should trigger a {@code GO_AWAY} if a set of headers exceeds this amount. + * @param maxHeaderListSize + * SETTINGS_MAX_HEADER_LIST_SIZE for the local + * endpoint. + * @return the threshold in bytes which should trigger a {@code GO_AWAY} if a set of headers exceeds this amount. + */ + public static long calculateMaxHeaderListSizeGoAway(long maxHeaderListSize) { + // This is equivalent to `maxHeaderListSize * 1.25` but we avoid floating point multiplication. + return maxHeaderListSize + (maxHeaderListSize >>> 2); + } + /** * Returns {@code true} if the stream is an outbound stream. * diff --git a/codec-http2/src/main/java/io/netty/handler/codec/http2/internal/hpack/Decoder.java b/codec-http2/src/main/java/io/netty/handler/codec/http2/internal/hpack/Decoder.java index 045c66c6a1..3e8c8f8050 100644 --- a/codec-http2/src/main/java/io/netty/handler/codec/http2/internal/hpack/Decoder.java +++ b/codec-http2/src/main/java/io/netty/handler/codec/http2/internal/hpack/Decoder.java @@ -32,6 +32,7 @@ package io.netty.handler.codec.http2.internal.hpack; import io.netty.buffer.ByteBuf; +import io.netty.handler.codec.http2.Http2CodecUtil; import io.netty.handler.codec.http2.Http2Exception; import io.netty.handler.codec.http2.Http2Headers; import io.netty.handler.codec.http2.internal.hpack.HpackUtil.IndexType; @@ -106,7 +107,9 @@ public final class Decoder { * for testing but violate the RFC if used outside the scope of testing. */ Decoder(long maxHeaderListSize, int initialHuffmanDecodeCapacity, int maxHeaderTableSize) { - this.maxHeaderListSize = maxHeaderListSizeGoAway = checkPositive(maxHeaderListSize, "maxHeaderListSize"); + this.maxHeaderListSize = checkPositive(maxHeaderListSize, "maxHeaderListSize"); + this.maxHeaderListSizeGoAway = Http2CodecUtil.calculateMaxHeaderListSizeGoAway(maxHeaderListSize); + maxDynamicTableSize = encoderMaxDynamicTableSize = maxHeaderTableSize; maxDynamicTableSizeChangeRequired = false; dynamicTable = new DynamicTable(maxHeaderTableSize); diff --git a/codec-http2/src/test/java/io/netty/handler/codec/http2/DefaultHttp2HeadersDecoderTest.java b/codec-http2/src/test/java/io/netty/handler/codec/http2/DefaultHttp2HeadersDecoderTest.java index b6a6a3dd1b..efa52ab22c 100644 --- a/codec-http2/src/test/java/io/netty/handler/codec/http2/DefaultHttp2HeadersDecoderTest.java +++ b/codec-http2/src/test/java/io/netty/handler/codec/http2/DefaultHttp2HeadersDecoderTest.java @@ -84,6 +84,21 @@ public class DefaultHttp2HeadersDecoderTest { } } + @Test + public void decodeLargerThanHeaderListSizeButLessThanGoAwayWithInitialDecoderSettings() throws Exception { + ByteBuf buf = encode(b(":method"), b("GET"), b("test_header"), + b(String.format("%09000d", 0).replace('0', 'A'))); + final int streamId = 1; + try { + decoder.decodeHeaders(streamId, buf); + fail(); + } catch (Http2Exception.HeaderListSizeException e) { + assertEquals(streamId, e.streamId()); + } finally { + buf.release(); + } + } + @Test public void decodeLargerThanHeaderListSizeGoAway() throws Exception { decoder.maxHeaderListSize(MIN_HEADER_LIST_SIZE, MIN_HEADER_LIST_SIZE);