Update hpack Decoder CTOR to allow for overflow in maxHeaderList size, as we do when we apply our ack'ed settings

This prevents us from having the first request, that hasn't ack'ed the setting causing a GOAWAY when we'd would
be under the maxHeaderListSizeGoAway that would have been set after the settings ack.
This commit is contained in:
Christopher Exell 2017-01-20 15:14:42 -08:00 committed by Scott Mitchell
parent e9fa40d770
commit 907726988d
4 changed files with 32 additions and 3 deletions

View File

@ -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) {

View File

@ -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
* <a href="https://tools.ietf.org/html/rfc7540#section-6.5.2">SETTINGS_MAX_HEADER_LIST_SIZE</a> 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.
*

View File

@ -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);

View File

@ -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);