netty5/codec-http2/src/main/java/io/netty/handler/codec/http2/Http2Settings.java
Moses Nakamura cf26227c6c Supply a builder for Http2Codec
Motivation:

DefaultHttp2FrameWriter has constructors that it would be a hassle to
expose as configuration parameters on Http2Codec. We should instead
make a builder for Http2Codec.

Modifications:

Get rid of the public constructors on Http2Codec and instead make sure
you can always use the builder where you would have used the constructor
before.

Result:

Http2Codec can be configured more flexibly, and the SensitivityDetector
can be configured.
2017-05-05 09:32:46 -07:00

271 lines
10 KiB
Java

/*
* Copyright 2014 The Netty Project
*
* The Netty Project licenses this file to you under the Apache License, version 2.0 (the
* "License"); you may not use this file except in compliance with the License. You may obtain a
* copy of the License at:
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software distributed under the License
* is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
* or implied. See the License for the specific language governing permissions and limitations under
* the License.
*/
package io.netty.handler.codec.http2;
import io.netty.util.collection.CharObjectHashMap;
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.MAX_CONCURRENT_STREAMS;
import static io.netty.handler.codec.http2.Http2CodecUtil.MAX_HEADER_LIST_SIZE;
import static io.netty.handler.codec.http2.Http2CodecUtil.MAX_HEADER_TABLE_SIZE;
import static io.netty.handler.codec.http2.Http2CodecUtil.MAX_INITIAL_WINDOW_SIZE;
import static io.netty.handler.codec.http2.Http2CodecUtil.MIN_CONCURRENT_STREAMS;
import static io.netty.handler.codec.http2.Http2CodecUtil.MIN_HEADER_LIST_SIZE;
import static io.netty.handler.codec.http2.Http2CodecUtil.MIN_HEADER_TABLE_SIZE;
import static io.netty.handler.codec.http2.Http2CodecUtil.MIN_INITIAL_WINDOW_SIZE;
import static io.netty.handler.codec.http2.Http2CodecUtil.NUM_STANDARD_SETTINGS;
import static io.netty.handler.codec.http2.Http2CodecUtil.SETTINGS_ENABLE_PUSH;
import static io.netty.handler.codec.http2.Http2CodecUtil.SETTINGS_HEADER_TABLE_SIZE;
import static io.netty.handler.codec.http2.Http2CodecUtil.SETTINGS_INITIAL_WINDOW_SIZE;
import static io.netty.handler.codec.http2.Http2CodecUtil.SETTINGS_MAX_CONCURRENT_STREAMS;
import static io.netty.handler.codec.http2.Http2CodecUtil.SETTINGS_MAX_FRAME_SIZE;
import static io.netty.handler.codec.http2.Http2CodecUtil.SETTINGS_MAX_HEADER_LIST_SIZE;
import static io.netty.handler.codec.http2.Http2CodecUtil.isMaxFrameSizeValid;
import static io.netty.util.internal.ObjectUtil.checkNotNull;
/**
* Settings for one endpoint in an HTTP/2 connection. Each of the values are optional as defined in
* the spec for the SETTINGS frame. Permits storage of arbitrary key/value pairs but provides helper
* methods for standard settings.
*/
@UnstableApi
public final class Http2Settings extends CharObjectHashMap<Long> {
/**
* Default capacity based on the number of standard settings from the HTTP/2 spec, adjusted so that adding all of
* the standard settings will not cause the map capacity to change.
*/
private static final int DEFAULT_CAPACITY = (int) (NUM_STANDARD_SETTINGS / DEFAULT_LOAD_FACTOR) + 1;
private static final Long FALSE = 0L;
private static final Long TRUE = 1L;
public Http2Settings() {
this(DEFAULT_CAPACITY);
}
public Http2Settings(int initialCapacity, float loadFactor) {
super(initialCapacity, loadFactor);
}
public Http2Settings(int initialCapacity) {
super(initialCapacity);
}
/**
* Adds the given setting key/value pair. For standard settings defined by the HTTP/2 spec, performs
* validation on the values.
*
* @throws IllegalArgumentException if verification for a standard HTTP/2 setting fails.
*/
@Override
public Long put(char key, Long value) {
verifyStandardSetting(key, value);
return super.put(key, value);
}
/**
* Gets the {@code SETTINGS_HEADER_TABLE_SIZE} value. If unavailable, returns {@code null}.
*/
public Long headerTableSize() {
return get(SETTINGS_HEADER_TABLE_SIZE);
}
/**
* Sets the {@code SETTINGS_HEADER_TABLE_SIZE} value.
*
* @throws IllegalArgumentException if verification of the setting fails.
*/
public Http2Settings headerTableSize(long value) {
put(SETTINGS_HEADER_TABLE_SIZE, Long.valueOf(value));
return this;
}
/**
* Gets the {@code SETTINGS_ENABLE_PUSH} value. If unavailable, returns {@code null}.
*/
public Boolean pushEnabled() {
Long value = get(SETTINGS_ENABLE_PUSH);
if (value == null) {
return null;
}
return TRUE.equals(value);
}
/**
* Sets the {@code SETTINGS_ENABLE_PUSH} value.
*/
public Http2Settings pushEnabled(boolean enabled) {
put(SETTINGS_ENABLE_PUSH, enabled ? TRUE : FALSE);
return this;
}
/**
* Gets the {@code SETTINGS_MAX_CONCURRENT_STREAMS} value. If unavailable, returns {@code null}.
*/
public Long maxConcurrentStreams() {
return get(SETTINGS_MAX_CONCURRENT_STREAMS);
}
/**
* Sets the {@code SETTINGS_MAX_CONCURRENT_STREAMS} value.
*
* @throws IllegalArgumentException if verification of the setting fails.
*/
public Http2Settings maxConcurrentStreams(long value) {
put(SETTINGS_MAX_CONCURRENT_STREAMS, Long.valueOf(value));
return this;
}
/**
* Gets the {@code SETTINGS_INITIAL_WINDOW_SIZE} value. If unavailable, returns {@code null}.
*/
public Integer initialWindowSize() {
return getIntValue(SETTINGS_INITIAL_WINDOW_SIZE);
}
/**
* Sets the {@code SETTINGS_INITIAL_WINDOW_SIZE} value.
*
* @throws IllegalArgumentException if verification of the setting fails.
*/
public Http2Settings initialWindowSize(int value) {
put(SETTINGS_INITIAL_WINDOW_SIZE, Long.valueOf(value));
return this;
}
/**
* Gets the {@code SETTINGS_MAX_FRAME_SIZE} value. If unavailable, returns {@code null}.
*/
public Integer maxFrameSize() {
return getIntValue(SETTINGS_MAX_FRAME_SIZE);
}
/**
* Sets the {@code SETTINGS_MAX_FRAME_SIZE} value.
*
* @throws IllegalArgumentException if verification of the setting fails.
*/
public Http2Settings maxFrameSize(int value) {
put(SETTINGS_MAX_FRAME_SIZE, Long.valueOf(value));
return this;
}
/**
* Gets the {@code SETTINGS_MAX_HEADER_LIST_SIZE} value. If unavailable, returns {@code null}.
*/
public Long maxHeaderListSize() {
return get(SETTINGS_MAX_HEADER_LIST_SIZE);
}
/**
* Sets the {@code SETTINGS_MAX_HEADER_LIST_SIZE} value.
*
* @throws IllegalArgumentException if verification of the setting fails.
*/
public Http2Settings maxHeaderListSize(long value) {
put(SETTINGS_MAX_HEADER_LIST_SIZE, Long.valueOf(value));
return this;
}
/**
* Clears and then copies the given settings into this object.
*/
public Http2Settings copyFrom(Http2Settings settings) {
clear();
putAll(settings);
return this;
}
/**
* A helper method that returns {@link Long#intValue()} on the return of {@link #get(char)}, if present. Note that
* if the range of the value exceeds {@link Integer#MAX_VALUE}, the {@link #get(char)} method should
* be used instead to avoid truncation of the value.
*/
public Integer getIntValue(char key) {
Long value = get(key);
if (value == null) {
return null;
}
return value.intValue();
}
private static void verifyStandardSetting(int key, Long value) {
checkNotNull(value, "value");
switch (key) {
case SETTINGS_HEADER_TABLE_SIZE:
if (value < MIN_HEADER_TABLE_SIZE || value > MAX_HEADER_TABLE_SIZE) {
throw new IllegalArgumentException("Setting HEADER_TABLE_SIZE is invalid: " + value);
}
break;
case SETTINGS_ENABLE_PUSH:
if (value != 0L && value != 1L) {
throw new IllegalArgumentException("Setting ENABLE_PUSH is invalid: " + value);
}
break;
case SETTINGS_MAX_CONCURRENT_STREAMS:
if (value < MIN_CONCURRENT_STREAMS || value > MAX_CONCURRENT_STREAMS) {
throw new IllegalArgumentException(
"Setting MAX_CONCURRENT_STREAMS is invalid: " + value);
}
break;
case SETTINGS_INITIAL_WINDOW_SIZE:
if (value < MIN_INITIAL_WINDOW_SIZE || value > MAX_INITIAL_WINDOW_SIZE) {
throw new IllegalArgumentException("Setting INITIAL_WINDOW_SIZE is invalid: "
+ value);
}
break;
case SETTINGS_MAX_FRAME_SIZE:
if (!isMaxFrameSizeValid(value.intValue())) {
throw new IllegalArgumentException("Setting MAX_FRAME_SIZE is invalid: " + value);
}
break;
case SETTINGS_MAX_HEADER_LIST_SIZE:
if (value < MIN_HEADER_LIST_SIZE || value > MAX_HEADER_LIST_SIZE) {
throw new IllegalArgumentException("Setting MAX_HEADER_LIST_SIZE is invalid: " + value);
}
break;
default:
// Non-standard HTTP/2 setting - don't do validation.
break;
}
}
@Override
protected String keyToString(char key) {
switch (key) {
case SETTINGS_HEADER_TABLE_SIZE:
return "HEADER_TABLE_SIZE";
case SETTINGS_ENABLE_PUSH:
return "ENABLE_PUSH";
case SETTINGS_MAX_CONCURRENT_STREAMS:
return "MAX_CONCURRENT_STREAMS";
case SETTINGS_INITIAL_WINDOW_SIZE:
return "INITIAL_WINDOW_SIZE";
case SETTINGS_MAX_FRAME_SIZE:
return "MAX_FRAME_SIZE";
case SETTINGS_MAX_HEADER_LIST_SIZE:
return "MAX_HEADER_LIST_SIZE";
default:
// Unknown keys.
return super.keyToString(key);
}
}
public static Http2Settings defaultSettings() {
return new Http2Settings().maxHeaderListSize(DEFAULT_HEADER_LIST_SIZE);
}
}