AbstractHttp2ConnectionHandlerBuilder support for HPACK huffman decoder initial size

Motivation:
Depending on the use case it may make sense to increase or decrease the initial size of the buffer used during the HPACK huffman decode process. This is currently not exposed through the AbstractHttp2ConnectionHandlerBuilder.

Modifications:
- Add a method to AbstractHttp2ConnectionHandlerBuilder which allows the initial size of the buffer used during the HPACK huffman decode prcoess to be configured.

Result:
AbstractHttp2ConnectionHandlerBuilder provides more control of codec-http2 knobs.
This commit is contained in:
Scott Mitchell 2017-06-12 12:37:57 -07:00
parent 1cc4607f07
commit f00638af52
5 changed files with 33 additions and 4 deletions

View File

@ -19,8 +19,11 @@ package io.netty.handler.codec.http2;
import io.netty.handler.codec.http2.Http2HeadersEncoder.SensitivityDetector; import io.netty.handler.codec.http2.Http2HeadersEncoder.SensitivityDetector;
import io.netty.util.internal.UnstableApi; import io.netty.util.internal.UnstableApi;
import static io.netty.handler.codec.http2.Http2CodecUtil.DEFAULT_HEADER_LIST_SIZE;
import static io.netty.handler.codec.http2.Http2CodecUtil.DEFAULT_INITIAL_HUFFMAN_DECODE_CAPACITY;
import static io.netty.handler.codec.http2.Http2CodecUtil.DEFAULT_MAX_RESERVED_STREAMS; import static io.netty.handler.codec.http2.Http2CodecUtil.DEFAULT_MAX_RESERVED_STREAMS;
import static io.netty.util.internal.ObjectUtil.checkNotNull; import static io.netty.util.internal.ObjectUtil.checkNotNull;
import static io.netty.util.internal.ObjectUtil.checkPositive;
import static io.netty.util.internal.ObjectUtil.checkPositiveOrZero; import static io.netty.util.internal.ObjectUtil.checkPositiveOrZero;
import static java.util.concurrent.TimeUnit.MILLISECONDS; import static java.util.concurrent.TimeUnit.MILLISECONDS;
import static java.util.concurrent.TimeUnit.SECONDS; import static java.util.concurrent.TimeUnit.SECONDS;
@ -61,6 +64,7 @@ import static java.util.concurrent.TimeUnit.SECONDS;
* <li>{@link #headerSensitivityDetector(SensitivityDetector)}</li> * <li>{@link #headerSensitivityDetector(SensitivityDetector)}</li>
* <li>{@link #encoderEnforceMaxConcurrentStreams(boolean)}</li> * <li>{@link #encoderEnforceMaxConcurrentStreams(boolean)}</li>
* <li>{@link #encoderIgnoreMaxHeaderListSize(boolean)}</li> * <li>{@link #encoderIgnoreMaxHeaderListSize(boolean)}</li>
* <li>{@link #initialHuffmanDecodeCapacity(int)}</li>
* </ul> * </ul>
* *
* <h3>Exposing necessary methods in a subclass</h3> * <h3>Exposing necessary methods in a subclass</h3>
@ -102,6 +106,7 @@ public abstract class AbstractHttp2ConnectionHandlerBuilder<T extends Http2Conne
private SensitivityDetector headerSensitivityDetector; private SensitivityDetector headerSensitivityDetector;
private Boolean encoderEnforceMaxConcurrentStreams; private Boolean encoderEnforceMaxConcurrentStreams;
private Boolean encoderIgnoreMaxHeaderListSize; private Boolean encoderIgnoreMaxHeaderListSize;
private int initialHuffmanDecodeCapacity = DEFAULT_INITIAL_HUFFMAN_DECODE_CAPACITY;
/** /**
* Sets the {@link Http2Settings} to use for the initial connection settings exchange. * Sets the {@link Http2Settings} to use for the initial connection settings exchange.
@ -344,6 +349,17 @@ public abstract class AbstractHttp2ConnectionHandlerBuilder<T extends Http2Conne
return self(); return self();
} }
/**
* Sets the initial size of an intermediate buffer used during HPACK huffman decoding.
* @param initialHuffmanDecodeCapacity initial size of an intermediate buffer used during HPACK huffman decoding.
* @return this.
*/
protected B initialHuffmanDecodeCapacity(int initialHuffmanDecodeCapacity) {
enforceNonCodecConstraints("initialHuffmanDecodeCapacity");
this.initialHuffmanDecodeCapacity = checkPositive(initialHuffmanDecodeCapacity, "initialHuffmanDecodeCapacity");
return self();
}
/** /**
* Create a new {@link Http2ConnectionHandler}. * Create a new {@link Http2ConnectionHandler}.
*/ */
@ -363,9 +379,9 @@ public abstract class AbstractHttp2ConnectionHandlerBuilder<T extends Http2Conne
private T buildFromConnection(Http2Connection connection) { private T buildFromConnection(Http2Connection connection) {
Long maxHeaderListSize = initialSettings.maxHeaderListSize(); Long maxHeaderListSize = initialSettings.maxHeaderListSize();
Http2FrameReader reader = new DefaultHttp2FrameReader(maxHeaderListSize == null ? Http2FrameReader reader = new DefaultHttp2FrameReader(new DefaultHttp2HeadersDecoder(isValidateHeaders(),
new DefaultHttp2HeadersDecoder(isValidateHeaders()) : maxHeaderListSize == null ? DEFAULT_HEADER_LIST_SIZE : maxHeaderListSize,
new DefaultHttp2HeadersDecoder(isValidateHeaders(), maxHeaderListSize)); initialHuffmanDecodeCapacity));
Http2FrameWriter writer = encoderIgnoreMaxHeaderListSize == null ? Http2FrameWriter writer = encoderIgnoreMaxHeaderListSize == null ?
new DefaultHttp2FrameWriter(headerSensitivityDetector()) : new DefaultHttp2FrameWriter(headerSensitivityDetector()) :
new DefaultHttp2FrameWriter(headerSensitivityDetector(), encoderIgnoreMaxHeaderListSize); new DefaultHttp2FrameWriter(headerSensitivityDetector(), encoderIgnoreMaxHeaderListSize);

View File

@ -20,6 +20,7 @@ import io.netty.util.internal.ObjectUtil;
import io.netty.util.internal.UnstableApi; import io.netty.util.internal.UnstableApi;
import static io.netty.handler.codec.http2.Http2CodecUtil.DEFAULT_HEADER_LIST_SIZE; import static io.netty.handler.codec.http2.Http2CodecUtil.DEFAULT_HEADER_LIST_SIZE;
import static io.netty.handler.codec.http2.Http2CodecUtil.DEFAULT_INITIAL_HUFFMAN_DECODE_CAPACITY;
import static io.netty.handler.codec.http2.Http2Error.COMPRESSION_ERROR; import static io.netty.handler.codec.http2.Http2Error.COMPRESSION_ERROR;
import static io.netty.handler.codec.http2.Http2Exception.connectionError; import static io.netty.handler.codec.http2.Http2Exception.connectionError;
@ -30,6 +31,7 @@ public class DefaultHttp2HeadersDecoder implements Http2HeadersDecoder, Http2Hea
private final HpackDecoder hpackDecoder; private final HpackDecoder hpackDecoder;
private final boolean validateHeaders; private final boolean validateHeaders;
/** /**
* Used to calculate an exponential moving average of header sizes to get an estimate of how large the data * Used to calculate an exponential moving average of header sizes to get an estimate of how large the data
* structure for storing headers should be. * structure for storing headers should be.
@ -53,7 +55,7 @@ public class DefaultHttp2HeadersDecoder implements Http2HeadersDecoder, Http2Hea
* (which is dangerous). * (which is dangerous).
*/ */
public DefaultHttp2HeadersDecoder(boolean validateHeaders, long maxHeaderListSize) { public DefaultHttp2HeadersDecoder(boolean validateHeaders, long maxHeaderListSize) {
this(validateHeaders, maxHeaderListSize, 32); this(validateHeaders, maxHeaderListSize, DEFAULT_INITIAL_HUFFMAN_DECODE_CAPACITY);
} }
/** /**

View File

@ -118,6 +118,7 @@ public final class Http2CodecUtil {
public static final int SMALLEST_MAX_CONCURRENT_STREAMS = 100; public static final int SMALLEST_MAX_CONCURRENT_STREAMS = 100;
static final int DEFAULT_MAX_RESERVED_STREAMS = SMALLEST_MAX_CONCURRENT_STREAMS; static final int DEFAULT_MAX_RESERVED_STREAMS = SMALLEST_MAX_CONCURRENT_STREAMS;
static final int DEFAULT_MIN_ALLOCATION_CHUNK = 1024; static final int DEFAULT_MIN_ALLOCATION_CHUNK = 1024;
static final int DEFAULT_INITIAL_HUFFMAN_DECODE_CAPACITY = 32;
/** /**
* Calculate the threshold in bytes which should trigger a {@code GO_AWAY} if a set of headers exceeds this amount. * Calculate the threshold in bytes which should trigger a {@code GO_AWAY} if a set of headers exceeds this amount.

View File

@ -87,6 +87,11 @@ public final class Http2ConnectionHandlerBuilder
return super.headerSensitivityDetector(headerSensitivityDetector); return super.headerSensitivityDetector(headerSensitivityDetector);
} }
@Override
public Http2ConnectionHandlerBuilder initialHuffmanDecodeCapacity(int initialHuffmanDecodeCapacity) {
return super.initialHuffmanDecodeCapacity(initialHuffmanDecodeCapacity);
}
@Override @Override
public Http2ConnectionHandler build() { public Http2ConnectionHandler build() {
return super.build(); return super.build();

View File

@ -79,6 +79,11 @@ public final class HttpToHttp2ConnectionHandlerBuilder extends
return super.headerSensitivityDetector(headerSensitivityDetector); return super.headerSensitivityDetector(headerSensitivityDetector);
} }
@Override
public HttpToHttp2ConnectionHandlerBuilder initialHuffmanDecodeCapacity(int initialHuffmanDecodeCapacity) {
return super.initialHuffmanDecodeCapacity(initialHuffmanDecodeCapacity);
}
@Override @Override
public HttpToHttp2ConnectionHandler build() { public HttpToHttp2ConnectionHandler build() {
return super.build(); return super.build();