HTTP/2 MaxStreams cleanup

Motivation:
765e944d4d imposed a limit on the maximum number of stream in all states. However the default limit did not allow room for streams in addition to SETTINGS_MAX_CONCURRENT_STREAMS. This can mean streams in states outside the states which SETTINGS_MAX_CONCURRENT_STREAMS applies to may not be reliably created.

Modifications:
- The default limit should be larger than SETTINGS_MAX_CONCURRENT_STREAMS

Result:
More lenient limit is applied to maxStreams by default.
This commit is contained in:
Scott Mitchell 2016-08-11 09:30:17 -07:00
parent 765e944d4d
commit 4d74bf3984

View File

@ -16,6 +16,7 @@ package io.netty.handler.codec.http2;
import io.netty.buffer.ByteBuf; import io.netty.buffer.ByteBuf;
import io.netty.channel.ChannelHandlerContext; import io.netty.channel.ChannelHandlerContext;
import io.netty.handler.codec.http2.Http2Connection.Endpoint;
import io.netty.handler.codec.http2.Http2Exception.ClosedStreamCreationException; import io.netty.handler.codec.http2.Http2Exception.ClosedStreamCreationException;
import io.netty.util.internal.UnstableApi; import io.netty.util.internal.UnstableApi;
import io.netty.util.internal.logging.InternalLogger; import io.netty.util.internal.logging.InternalLogger;
@ -24,6 +25,7 @@ import io.netty.util.internal.logging.InternalLoggerFactory;
import java.util.List; import java.util.List;
import static io.netty.handler.codec.http2.Http2CodecUtil.DEFAULT_PRIORITY_WEIGHT; import static io.netty.handler.codec.http2.Http2CodecUtil.DEFAULT_PRIORITY_WEIGHT;
import static io.netty.handler.codec.http2.Http2CodecUtil.SMALLEST_MAX_CONCURRENT_STREAMS;
import static io.netty.handler.codec.http2.Http2Error.PROTOCOL_ERROR; import static io.netty.handler.codec.http2.Http2Error.PROTOCOL_ERROR;
import static io.netty.handler.codec.http2.Http2Error.STREAM_CLOSED; import static io.netty.handler.codec.http2.Http2Error.STREAM_CLOSED;
import static io.netty.handler.codec.http2.Http2Exception.connectionError; import static io.netty.handler.codec.http2.Http2Exception.connectionError;
@ -32,6 +34,8 @@ import static io.netty.handler.codec.http2.Http2PromisedRequestVerifier.ALWAYS_V
import static io.netty.handler.codec.http2.Http2Stream.State.CLOSED; import static io.netty.handler.codec.http2.Http2Stream.State.CLOSED;
import static io.netty.handler.codec.http2.Http2Stream.State.HALF_CLOSED_REMOTE; import static io.netty.handler.codec.http2.Http2Stream.State.HALF_CLOSED_REMOTE;
import static io.netty.util.internal.ObjectUtil.checkNotNull; import static io.netty.util.internal.ObjectUtil.checkNotNull;
import static java.lang.Integer.MAX_VALUE;
import static java.lang.Math.min;
/** /**
* Provides the default implementation for processing inbound frame events and delegates to a * Provides the default implementation for processing inbound frame events and delegates to a
@ -385,14 +389,13 @@ public class DefaultHttp2ConnectionDecoder implements Http2ConnectionDecoder {
Long maxConcurrentStreams = settings.maxConcurrentStreams(); Long maxConcurrentStreams = settings.maxConcurrentStreams();
if (maxConcurrentStreams != null) { if (maxConcurrentStreams != null) {
int value = (int) Math.min(maxConcurrentStreams, Integer.MAX_VALUE); int value = (int) min(maxConcurrentStreams, MAX_VALUE);
// By default just enforce the SETTINGS_MAX_CONCURRENT_STREAMS limit for stream in all states. connection.remote().maxStreams(value, calculateMaxStreams(value));
connection.remote().maxStreams(value, value);
} }
Long headerTableSize = settings.headerTableSize(); Long headerTableSize = settings.headerTableSize();
if (headerTableSize != null) { if (headerTableSize != null) {
headerTable.maxHeaderTableSize((int) Math.min(headerTableSize, Integer.MAX_VALUE)); headerTable.maxHeaderTableSize((int) min(headerTableSize, MAX_VALUE));
} }
Integer maxHeaderListSize = settings.maxHeaderListSize(); Integer maxHeaderListSize = settings.maxHeaderListSize();
@ -411,6 +414,18 @@ public class DefaultHttp2ConnectionDecoder implements Http2ConnectionDecoder {
} }
} }
/**
* Calculate the {@code maxStreams} paramter for the {@link Endpoint#maxStreams(int, int)} method based upon
* SETTINGS_MAX_CONCURRENT_STREAMS.
* @param maxConcurrentStreams SETTINGS_MAX_CONCURRENT_STREAMS
* @return the {@code maxStreams} paramter for the {@link Endpoint#maxStreams(int, int)} method.
*/
@UnstableApi
protected int calculateMaxStreams(int maxConcurrentStreams) {
int maxStreams = maxConcurrentStreams + SMALLEST_MAX_CONCURRENT_STREAMS;
return maxStreams < 0 ? MAX_VALUE : maxStreams;
}
@Override @Override
public void onSettingsRead(ChannelHandlerContext ctx, Http2Settings settings) throws Http2Exception { public void onSettingsRead(ChannelHandlerContext ctx, Http2Settings settings) throws Http2Exception {
encoder.remoteSettings(settings); encoder.remoteSettings(settings);
@ -552,7 +567,7 @@ public class DefaultHttp2ConnectionDecoder implements Http2ConnectionDecoder {
* <p/> * <p/>
*/ */
private boolean streamCreatedAfterGoAwaySent(int streamId) { private boolean streamCreatedAfterGoAwaySent(int streamId) {
Http2Connection.Endpoint<?> remote = connection.remote(); Endpoint<?> remote = connection.remote();
return connection.goAwaySent() && remote.isValidStreamId(streamId) && return connection.goAwaySent() && remote.isValidStreamId(streamId) &&
streamId > remote.lastStreamKnownByPeer(); streamId > remote.lastStreamKnownByPeer();
} }