mirror of https://github.com/grpc/grpc-java.git
netty: add soft Metadata size limit enforcement. (#11603)
This commit is contained in:
parent
fe350cfd50
commit
735b3f3fe6
|
|
@ -42,7 +42,8 @@ abstract class AbstractNettyHandler extends GrpcHttp2ConnectionHandler {
|
||||||
|
|
||||||
private final int initialConnectionWindow;
|
private final int initialConnectionWindow;
|
||||||
private final FlowControlPinger flowControlPing;
|
private final FlowControlPinger flowControlPing;
|
||||||
|
protected final int maxHeaderListSize;
|
||||||
|
protected final int softLimitHeaderListSize;
|
||||||
private boolean autoTuneFlowControlOn;
|
private boolean autoTuneFlowControlOn;
|
||||||
private ChannelHandlerContext ctx;
|
private ChannelHandlerContext ctx;
|
||||||
private boolean initialWindowSent = false;
|
private boolean initialWindowSent = false;
|
||||||
|
|
@ -58,7 +59,9 @@ abstract class AbstractNettyHandler extends GrpcHttp2ConnectionHandler {
|
||||||
ChannelLogger negotiationLogger,
|
ChannelLogger negotiationLogger,
|
||||||
boolean autoFlowControl,
|
boolean autoFlowControl,
|
||||||
PingLimiter pingLimiter,
|
PingLimiter pingLimiter,
|
||||||
Ticker ticker) {
|
Ticker ticker,
|
||||||
|
int maxHeaderListSize,
|
||||||
|
int softLimitHeaderListSize) {
|
||||||
super(channelUnused, decoder, encoder, initialSettings, negotiationLogger);
|
super(channelUnused, decoder, encoder, initialSettings, negotiationLogger);
|
||||||
|
|
||||||
// During a graceful shutdown, wait until all streams are closed.
|
// During a graceful shutdown, wait until all streams are closed.
|
||||||
|
|
@ -73,6 +76,8 @@ abstract class AbstractNettyHandler extends GrpcHttp2ConnectionHandler {
|
||||||
}
|
}
|
||||||
this.flowControlPing = new FlowControlPinger(pingLimiter);
|
this.flowControlPing = new FlowControlPinger(pingLimiter);
|
||||||
this.ticker = checkNotNull(ticker, "ticker");
|
this.ticker = checkNotNull(ticker, "ticker");
|
||||||
|
this.maxHeaderListSize = maxHeaderListSize;
|
||||||
|
this.softLimitHeaderListSize = softLimitHeaderListSize;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|
|
||||||
|
|
@ -104,6 +104,7 @@ public final class NettyChannelBuilder extends ForwardingChannelBuilder2<NettyCh
|
||||||
private boolean autoFlowControl = DEFAULT_AUTO_FLOW_CONTROL;
|
private boolean autoFlowControl = DEFAULT_AUTO_FLOW_CONTROL;
|
||||||
private int flowControlWindow = DEFAULT_FLOW_CONTROL_WINDOW;
|
private int flowControlWindow = DEFAULT_FLOW_CONTROL_WINDOW;
|
||||||
private int maxHeaderListSize = GrpcUtil.DEFAULT_MAX_HEADER_LIST_SIZE;
|
private int maxHeaderListSize = GrpcUtil.DEFAULT_MAX_HEADER_LIST_SIZE;
|
||||||
|
private int softLimitHeaderListSize = GrpcUtil.DEFAULT_MAX_HEADER_LIST_SIZE;
|
||||||
private int maxInboundMessageSize = GrpcUtil.DEFAULT_MAX_MESSAGE_SIZE;
|
private int maxInboundMessageSize = GrpcUtil.DEFAULT_MAX_MESSAGE_SIZE;
|
||||||
private long keepAliveTimeNanos = KEEPALIVE_TIME_NANOS_DISABLED;
|
private long keepAliveTimeNanos = KEEPALIVE_TIME_NANOS_DISABLED;
|
||||||
private long keepAliveTimeoutNanos = DEFAULT_KEEPALIVE_TIMEOUT_NANOS;
|
private long keepAliveTimeoutNanos = DEFAULT_KEEPALIVE_TIMEOUT_NANOS;
|
||||||
|
|
@ -452,6 +453,40 @@ public final class NettyChannelBuilder extends ForwardingChannelBuilder2<NettyCh
|
||||||
public NettyChannelBuilder maxInboundMetadataSize(int bytes) {
|
public NettyChannelBuilder maxInboundMetadataSize(int bytes) {
|
||||||
checkArgument(bytes > 0, "maxInboundMetadataSize must be > 0");
|
checkArgument(bytes > 0, "maxInboundMetadataSize must be > 0");
|
||||||
this.maxHeaderListSize = bytes;
|
this.maxHeaderListSize = bytes;
|
||||||
|
// Clear the soft limit setting, by setting soft limit to maxInboundMetadataSize. The
|
||||||
|
// maxInboundMetadataSize will take precedence be applied before soft limit check.
|
||||||
|
this.softLimitHeaderListSize = bytes;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets the size of metadata that clients are advised to not exceed. When a metadata with size
|
||||||
|
* larger than the soft limit is encountered there will be a probability the RPC will fail. The
|
||||||
|
* chance of failing increases as the metadata size approaches the hard limit.
|
||||||
|
* {@code Integer.MAX_VALUE} disables the enforcement. The default is implementation-dependent,
|
||||||
|
* but is not generally less than 8 KiB and may be unlimited.
|
||||||
|
*
|
||||||
|
* <p>This is cumulative size of the metadata. The precise calculation is
|
||||||
|
* implementation-dependent, but implementations are encouraged to follow the calculation used
|
||||||
|
* for
|
||||||
|
* <a href="http://httpwg.org/specs/rfc7540.html#rfc.section.6.5.2">HTTP/2's
|
||||||
|
* SETTINGS_MAX_HEADER_LIST_SIZE</a>. It sums the bytes from each entry's key and value, plus 32
|
||||||
|
* bytes of overhead per entry.
|
||||||
|
*
|
||||||
|
* @param soft the soft size limit of received metadata
|
||||||
|
* @param max the hard size limit of received metadata
|
||||||
|
* @return this
|
||||||
|
* @throws IllegalArgumentException if soft and/or max is non-positive, or max smaller than
|
||||||
|
* soft
|
||||||
|
* @since 1.68.0
|
||||||
|
*/
|
||||||
|
@CanIgnoreReturnValue
|
||||||
|
public NettyChannelBuilder maxInboundMetadataSize(int soft, int max) {
|
||||||
|
checkArgument(soft > 0, "softLimitHeaderListSize must be > 0");
|
||||||
|
checkArgument(max > soft,
|
||||||
|
"maxInboundMetadataSize must be greater than softLimitHeaderListSize");
|
||||||
|
this.softLimitHeaderListSize = soft;
|
||||||
|
this.maxHeaderListSize = max;
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -573,10 +608,22 @@ public final class NettyChannelBuilder extends ForwardingChannelBuilder2<NettyCh
|
||||||
|
|
||||||
ProtocolNegotiator negotiator = protocolNegotiatorFactory.newNegotiator();
|
ProtocolNegotiator negotiator = protocolNegotiatorFactory.newNegotiator();
|
||||||
return new NettyTransportFactory(
|
return new NettyTransportFactory(
|
||||||
negotiator, channelFactory, channelOptions,
|
negotiator,
|
||||||
eventLoopGroupPool, autoFlowControl, flowControlWindow, maxInboundMessageSize,
|
channelFactory,
|
||||||
maxHeaderListSize, keepAliveTimeNanos, keepAliveTimeoutNanos, keepAliveWithoutCalls,
|
channelOptions,
|
||||||
transportTracerFactory, localSocketPicker, useGetForSafeMethods, transportSocketType);
|
eventLoopGroupPool,
|
||||||
|
autoFlowControl,
|
||||||
|
flowControlWindow,
|
||||||
|
maxInboundMessageSize,
|
||||||
|
maxHeaderListSize,
|
||||||
|
softLimitHeaderListSize,
|
||||||
|
keepAliveTimeNanos,
|
||||||
|
keepAliveTimeoutNanos,
|
||||||
|
keepAliveWithoutCalls,
|
||||||
|
transportTracerFactory,
|
||||||
|
localSocketPicker,
|
||||||
|
useGetForSafeMethods,
|
||||||
|
transportSocketType);
|
||||||
}
|
}
|
||||||
|
|
||||||
@VisibleForTesting
|
@VisibleForTesting
|
||||||
|
|
@ -710,6 +757,7 @@ public final class NettyChannelBuilder extends ForwardingChannelBuilder2<NettyCh
|
||||||
private final int flowControlWindow;
|
private final int flowControlWindow;
|
||||||
private final int maxMessageSize;
|
private final int maxMessageSize;
|
||||||
private final int maxHeaderListSize;
|
private final int maxHeaderListSize;
|
||||||
|
private final int softLimitHeaderListSize;
|
||||||
private final long keepAliveTimeNanos;
|
private final long keepAliveTimeNanos;
|
||||||
private final AtomicBackoff keepAliveBackoff;
|
private final AtomicBackoff keepAliveBackoff;
|
||||||
private final long keepAliveTimeoutNanos;
|
private final long keepAliveTimeoutNanos;
|
||||||
|
|
@ -724,11 +772,20 @@ public final class NettyChannelBuilder extends ForwardingChannelBuilder2<NettyCh
|
||||||
NettyTransportFactory(
|
NettyTransportFactory(
|
||||||
ProtocolNegotiator protocolNegotiator,
|
ProtocolNegotiator protocolNegotiator,
|
||||||
ChannelFactory<? extends Channel> channelFactory,
|
ChannelFactory<? extends Channel> channelFactory,
|
||||||
Map<ChannelOption<?>, ?> channelOptions, ObjectPool<? extends EventLoopGroup> groupPool,
|
Map<ChannelOption<?>, ?> channelOptions,
|
||||||
boolean autoFlowControl, int flowControlWindow, int maxMessageSize, int maxHeaderListSize,
|
ObjectPool<? extends EventLoopGroup> groupPool,
|
||||||
long keepAliveTimeNanos, long keepAliveTimeoutNanos, boolean keepAliveWithoutCalls,
|
boolean autoFlowControl,
|
||||||
TransportTracer.Factory transportTracerFactory, LocalSocketPicker localSocketPicker,
|
int flowControlWindow,
|
||||||
boolean useGetForSafeMethods, Class<? extends SocketAddress> transportSocketType) {
|
int maxMessageSize,
|
||||||
|
int maxHeaderListSize,
|
||||||
|
int softLimitHeaderListSize,
|
||||||
|
long keepAliveTimeNanos,
|
||||||
|
long keepAliveTimeoutNanos,
|
||||||
|
boolean keepAliveWithoutCalls,
|
||||||
|
TransportTracer.Factory transportTracerFactory,
|
||||||
|
LocalSocketPicker localSocketPicker,
|
||||||
|
boolean useGetForSafeMethods,
|
||||||
|
Class<? extends SocketAddress> transportSocketType) {
|
||||||
this.protocolNegotiator = checkNotNull(protocolNegotiator, "protocolNegotiator");
|
this.protocolNegotiator = checkNotNull(protocolNegotiator, "protocolNegotiator");
|
||||||
this.channelFactory = channelFactory;
|
this.channelFactory = channelFactory;
|
||||||
this.channelOptions = new HashMap<ChannelOption<?>, Object>(channelOptions);
|
this.channelOptions = new HashMap<ChannelOption<?>, Object>(channelOptions);
|
||||||
|
|
@ -738,6 +795,7 @@ public final class NettyChannelBuilder extends ForwardingChannelBuilder2<NettyCh
|
||||||
this.flowControlWindow = flowControlWindow;
|
this.flowControlWindow = flowControlWindow;
|
||||||
this.maxMessageSize = maxMessageSize;
|
this.maxMessageSize = maxMessageSize;
|
||||||
this.maxHeaderListSize = maxHeaderListSize;
|
this.maxHeaderListSize = maxHeaderListSize;
|
||||||
|
this.softLimitHeaderListSize = softLimitHeaderListSize;
|
||||||
this.keepAliveTimeNanos = keepAliveTimeNanos;
|
this.keepAliveTimeNanos = keepAliveTimeNanos;
|
||||||
this.keepAliveBackoff = new AtomicBackoff("keepalive time nanos", keepAliveTimeNanos);
|
this.keepAliveBackoff = new AtomicBackoff("keepalive time nanos", keepAliveTimeNanos);
|
||||||
this.keepAliveTimeoutNanos = keepAliveTimeoutNanos;
|
this.keepAliveTimeoutNanos = keepAliveTimeoutNanos;
|
||||||
|
|
@ -774,13 +832,30 @@ public final class NettyChannelBuilder extends ForwardingChannelBuilder2<NettyCh
|
||||||
};
|
};
|
||||||
|
|
||||||
// TODO(carl-mastrangelo): Pass channelLogger in.
|
// TODO(carl-mastrangelo): Pass channelLogger in.
|
||||||
NettyClientTransport transport = new NettyClientTransport(
|
NettyClientTransport transport =
|
||||||
serverAddress, channelFactory, channelOptions, group,
|
new NettyClientTransport(
|
||||||
localNegotiator, autoFlowControl, flowControlWindow,
|
serverAddress,
|
||||||
maxMessageSize, maxHeaderListSize, keepAliveTimeNanosState.get(), keepAliveTimeoutNanos,
|
channelFactory,
|
||||||
keepAliveWithoutCalls, options.getAuthority(), options.getUserAgent(),
|
channelOptions,
|
||||||
tooManyPingsRunnable, transportTracerFactory.create(), options.getEagAttributes(),
|
group,
|
||||||
localSocketPicker, channelLogger, useGetForSafeMethods, Ticker.systemTicker());
|
localNegotiator,
|
||||||
|
autoFlowControl,
|
||||||
|
flowControlWindow,
|
||||||
|
maxMessageSize,
|
||||||
|
maxHeaderListSize,
|
||||||
|
softLimitHeaderListSize,
|
||||||
|
keepAliveTimeNanosState.get(),
|
||||||
|
keepAliveTimeoutNanos,
|
||||||
|
keepAliveWithoutCalls,
|
||||||
|
options.getAuthority(),
|
||||||
|
options.getUserAgent(),
|
||||||
|
tooManyPingsRunnable,
|
||||||
|
transportTracerFactory.create(),
|
||||||
|
options.getEagAttributes(),
|
||||||
|
localSocketPicker,
|
||||||
|
channelLogger,
|
||||||
|
useGetForSafeMethods,
|
||||||
|
Ticker.systemTicker());
|
||||||
return transport;
|
return transport;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -796,11 +871,24 @@ public final class NettyChannelBuilder extends ForwardingChannelBuilder2<NettyCh
|
||||||
if (result.error != null) {
|
if (result.error != null) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
ClientTransportFactory factory = new NettyTransportFactory(
|
ClientTransportFactory factory =
|
||||||
result.negotiator.newNegotiator(), channelFactory, channelOptions, groupPool,
|
new NettyTransportFactory(
|
||||||
autoFlowControl, flowControlWindow, maxMessageSize, maxHeaderListSize, keepAliveTimeNanos,
|
result.negotiator.newNegotiator(),
|
||||||
keepAliveTimeoutNanos, keepAliveWithoutCalls, transportTracerFactory, localSocketPicker,
|
channelFactory,
|
||||||
useGetForSafeMethods, transportSocketType);
|
channelOptions,
|
||||||
|
groupPool,
|
||||||
|
autoFlowControl,
|
||||||
|
flowControlWindow,
|
||||||
|
maxMessageSize,
|
||||||
|
maxHeaderListSize,
|
||||||
|
softLimitHeaderListSize,
|
||||||
|
keepAliveTimeNanos,
|
||||||
|
keepAliveTimeoutNanos,
|
||||||
|
keepAliveWithoutCalls,
|
||||||
|
transportTracerFactory,
|
||||||
|
localSocketPicker,
|
||||||
|
useGetForSafeMethods,
|
||||||
|
transportSocketType);
|
||||||
return new SwapChannelCredentialsResult(factory, result.callCredentials);
|
return new SwapChannelCredentialsResult(factory, result.callCredentials);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -142,6 +142,7 @@ class NettyClientHandler extends AbstractNettyHandler {
|
||||||
boolean autoFlowControl,
|
boolean autoFlowControl,
|
||||||
int flowControlWindow,
|
int flowControlWindow,
|
||||||
int maxHeaderListSize,
|
int maxHeaderListSize,
|
||||||
|
int softLimitHeaderListSize,
|
||||||
Supplier<Stopwatch> stopwatchFactory,
|
Supplier<Stopwatch> stopwatchFactory,
|
||||||
Runnable tooManyPingsRunnable,
|
Runnable tooManyPingsRunnable,
|
||||||
TransportTracer transportTracer,
|
TransportTracer transportTracer,
|
||||||
|
|
@ -171,6 +172,7 @@ class NettyClientHandler extends AbstractNettyHandler {
|
||||||
autoFlowControl,
|
autoFlowControl,
|
||||||
flowControlWindow,
|
flowControlWindow,
|
||||||
maxHeaderListSize,
|
maxHeaderListSize,
|
||||||
|
softLimitHeaderListSize,
|
||||||
stopwatchFactory,
|
stopwatchFactory,
|
||||||
tooManyPingsRunnable,
|
tooManyPingsRunnable,
|
||||||
transportTracer,
|
transportTracer,
|
||||||
|
|
@ -190,6 +192,7 @@ class NettyClientHandler extends AbstractNettyHandler {
|
||||||
boolean autoFlowControl,
|
boolean autoFlowControl,
|
||||||
int flowControlWindow,
|
int flowControlWindow,
|
||||||
int maxHeaderListSize,
|
int maxHeaderListSize,
|
||||||
|
int softLimitHeaderListSize,
|
||||||
Supplier<Stopwatch> stopwatchFactory,
|
Supplier<Stopwatch> stopwatchFactory,
|
||||||
Runnable tooManyPingsRunnable,
|
Runnable tooManyPingsRunnable,
|
||||||
TransportTracer transportTracer,
|
TransportTracer transportTracer,
|
||||||
|
|
@ -202,6 +205,8 @@ class NettyClientHandler extends AbstractNettyHandler {
|
||||||
Preconditions.checkNotNull(lifecycleManager, "lifecycleManager");
|
Preconditions.checkNotNull(lifecycleManager, "lifecycleManager");
|
||||||
Preconditions.checkArgument(flowControlWindow > 0, "flowControlWindow must be positive");
|
Preconditions.checkArgument(flowControlWindow > 0, "flowControlWindow must be positive");
|
||||||
Preconditions.checkArgument(maxHeaderListSize > 0, "maxHeaderListSize must be positive");
|
Preconditions.checkArgument(maxHeaderListSize > 0, "maxHeaderListSize must be positive");
|
||||||
|
Preconditions.checkArgument(softLimitHeaderListSize > 0,
|
||||||
|
"softLimitHeaderListSize must be positive");
|
||||||
Preconditions.checkNotNull(stopwatchFactory, "stopwatchFactory");
|
Preconditions.checkNotNull(stopwatchFactory, "stopwatchFactory");
|
||||||
Preconditions.checkNotNull(tooManyPingsRunnable, "tooManyPingsRunnable");
|
Preconditions.checkNotNull(tooManyPingsRunnable, "tooManyPingsRunnable");
|
||||||
Preconditions.checkNotNull(eagAttributes, "eagAttributes");
|
Preconditions.checkNotNull(eagAttributes, "eagAttributes");
|
||||||
|
|
@ -247,7 +252,9 @@ class NettyClientHandler extends AbstractNettyHandler {
|
||||||
authority,
|
authority,
|
||||||
autoFlowControl,
|
autoFlowControl,
|
||||||
pingCounter,
|
pingCounter,
|
||||||
ticker);
|
ticker,
|
||||||
|
maxHeaderListSize,
|
||||||
|
softLimitHeaderListSize);
|
||||||
}
|
}
|
||||||
|
|
||||||
private NettyClientHandler(
|
private NettyClientHandler(
|
||||||
|
|
@ -264,9 +271,20 @@ class NettyClientHandler extends AbstractNettyHandler {
|
||||||
String authority,
|
String authority,
|
||||||
boolean autoFlowControl,
|
boolean autoFlowControl,
|
||||||
PingLimiter pingLimiter,
|
PingLimiter pingLimiter,
|
||||||
Ticker ticker) {
|
Ticker ticker,
|
||||||
super(/* channelUnused= */ null, decoder, encoder, settings,
|
int maxHeaderListSize,
|
||||||
negotiationLogger, autoFlowControl, pingLimiter, ticker);
|
int softLimitHeaderListSize) {
|
||||||
|
super(
|
||||||
|
/* channelUnused= */ null,
|
||||||
|
decoder,
|
||||||
|
encoder,
|
||||||
|
settings,
|
||||||
|
negotiationLogger,
|
||||||
|
autoFlowControl,
|
||||||
|
pingLimiter,
|
||||||
|
ticker,
|
||||||
|
maxHeaderListSize,
|
||||||
|
softLimitHeaderListSize);
|
||||||
this.lifecycleManager = lifecycleManager;
|
this.lifecycleManager = lifecycleManager;
|
||||||
this.keepAliveManager = keepAliveManager;
|
this.keepAliveManager = keepAliveManager;
|
||||||
this.stopwatchFactory = stopwatchFactory;
|
this.stopwatchFactory = stopwatchFactory;
|
||||||
|
|
@ -380,6 +398,28 @@ class NettyClientHandler extends AbstractNettyHandler {
|
||||||
if (streamId != Http2CodecUtil.HTTP_UPGRADE_STREAM_ID) {
|
if (streamId != Http2CodecUtil.HTTP_UPGRADE_STREAM_ID) {
|
||||||
NettyClientStream.TransportState stream = clientStream(requireHttp2Stream(streamId));
|
NettyClientStream.TransportState stream = clientStream(requireHttp2Stream(streamId));
|
||||||
PerfMark.event("NettyClientHandler.onHeadersRead", stream.tag());
|
PerfMark.event("NettyClientHandler.onHeadersRead", stream.tag());
|
||||||
|
// check metadata size vs soft limit
|
||||||
|
int h2HeadersSize = Utils.getH2HeadersSize(headers);
|
||||||
|
boolean shouldFail =
|
||||||
|
Utils.shouldRejectOnMetadataSizeSoftLimitExceeded(
|
||||||
|
h2HeadersSize, softLimitHeaderListSize, maxHeaderListSize);
|
||||||
|
if (shouldFail && endStream) {
|
||||||
|
stream.transportReportStatus(Status.RESOURCE_EXHAUSTED
|
||||||
|
.withDescription(
|
||||||
|
String.format(
|
||||||
|
"Server Status + Trailers of size %d exceeded Metadata size soft limit: %d",
|
||||||
|
h2HeadersSize,
|
||||||
|
softLimitHeaderListSize)), true, new Metadata());
|
||||||
|
return;
|
||||||
|
} else if (shouldFail) {
|
||||||
|
stream.transportReportStatus(Status.RESOURCE_EXHAUSTED
|
||||||
|
.withDescription(
|
||||||
|
String.format(
|
||||||
|
"Server Headers of size %d exceeded Metadata size soft limit: %d",
|
||||||
|
h2HeadersSize,
|
||||||
|
softLimitHeaderListSize)), true, new Metadata());
|
||||||
|
return;
|
||||||
|
}
|
||||||
stream.transportHeadersReceived(headers, endStream);
|
stream.transportHeadersReceived(headers, endStream);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -83,6 +83,7 @@ class NettyClientTransport implements ConnectionClientTransport {
|
||||||
private final int flowControlWindow;
|
private final int flowControlWindow;
|
||||||
private final int maxMessageSize;
|
private final int maxMessageSize;
|
||||||
private final int maxHeaderListSize;
|
private final int maxHeaderListSize;
|
||||||
|
private final int softLimitHeaderListSize;
|
||||||
private KeepAliveManager keepAliveManager;
|
private KeepAliveManager keepAliveManager;
|
||||||
private final long keepAliveTimeNanos;
|
private final long keepAliveTimeNanos;
|
||||||
private final long keepAliveTimeoutNanos;
|
private final long keepAliveTimeoutNanos;
|
||||||
|
|
@ -106,15 +107,28 @@ class NettyClientTransport implements ConnectionClientTransport {
|
||||||
private final Ticker ticker;
|
private final Ticker ticker;
|
||||||
|
|
||||||
NettyClientTransport(
|
NettyClientTransport(
|
||||||
SocketAddress address, ChannelFactory<? extends Channel> channelFactory,
|
SocketAddress address,
|
||||||
Map<ChannelOption<?>, ?> channelOptions, EventLoopGroup group,
|
ChannelFactory<? extends Channel> channelFactory,
|
||||||
ProtocolNegotiator negotiator, boolean autoFlowControl, int flowControlWindow,
|
Map<ChannelOption<?>, ?> channelOptions,
|
||||||
int maxMessageSize, int maxHeaderListSize,
|
EventLoopGroup group,
|
||||||
long keepAliveTimeNanos, long keepAliveTimeoutNanos,
|
ProtocolNegotiator negotiator,
|
||||||
boolean keepAliveWithoutCalls, String authority, @Nullable String userAgent,
|
boolean autoFlowControl,
|
||||||
Runnable tooManyPingsRunnable, TransportTracer transportTracer, Attributes eagAttributes,
|
int flowControlWindow,
|
||||||
LocalSocketPicker localSocketPicker, ChannelLogger channelLogger,
|
int maxMessageSize,
|
||||||
boolean useGetForSafeMethods, Ticker ticker) {
|
int maxHeaderListSize,
|
||||||
|
int softLimitHeaderListSize,
|
||||||
|
long keepAliveTimeNanos,
|
||||||
|
long keepAliveTimeoutNanos,
|
||||||
|
boolean keepAliveWithoutCalls,
|
||||||
|
String authority,
|
||||||
|
@Nullable String userAgent,
|
||||||
|
Runnable tooManyPingsRunnable,
|
||||||
|
TransportTracer transportTracer,
|
||||||
|
Attributes eagAttributes,
|
||||||
|
LocalSocketPicker localSocketPicker,
|
||||||
|
ChannelLogger channelLogger,
|
||||||
|
boolean useGetForSafeMethods,
|
||||||
|
Ticker ticker) {
|
||||||
|
|
||||||
this.negotiator = Preconditions.checkNotNull(negotiator, "negotiator");
|
this.negotiator = Preconditions.checkNotNull(negotiator, "negotiator");
|
||||||
this.negotiationScheme = this.negotiator.scheme();
|
this.negotiationScheme = this.negotiator.scheme();
|
||||||
|
|
@ -126,6 +140,7 @@ class NettyClientTransport implements ConnectionClientTransport {
|
||||||
this.flowControlWindow = flowControlWindow;
|
this.flowControlWindow = flowControlWindow;
|
||||||
this.maxMessageSize = maxMessageSize;
|
this.maxMessageSize = maxMessageSize;
|
||||||
this.maxHeaderListSize = maxHeaderListSize;
|
this.maxHeaderListSize = maxHeaderListSize;
|
||||||
|
this.softLimitHeaderListSize = softLimitHeaderListSize;
|
||||||
this.keepAliveTimeNanos = keepAliveTimeNanos;
|
this.keepAliveTimeNanos = keepAliveTimeNanos;
|
||||||
this.keepAliveTimeoutNanos = keepAliveTimeoutNanos;
|
this.keepAliveTimeoutNanos = keepAliveTimeoutNanos;
|
||||||
this.keepAliveWithoutCalls = keepAliveWithoutCalls;
|
this.keepAliveWithoutCalls = keepAliveWithoutCalls;
|
||||||
|
|
@ -225,6 +240,7 @@ class NettyClientTransport implements ConnectionClientTransport {
|
||||||
autoFlowControl,
|
autoFlowControl,
|
||||||
flowControlWindow,
|
flowControlWindow,
|
||||||
maxHeaderListSize,
|
maxHeaderListSize,
|
||||||
|
softLimitHeaderListSize,
|
||||||
GrpcUtil.STOPWATCH_SUPPLIER,
|
GrpcUtil.STOPWATCH_SUPPLIER,
|
||||||
tooManyPingsRunnable,
|
tooManyPingsRunnable,
|
||||||
transportTracer,
|
transportTracer,
|
||||||
|
|
|
||||||
|
|
@ -92,6 +92,7 @@ class NettyServer implements InternalServer, InternalWithLogId {
|
||||||
private final int flowControlWindow;
|
private final int flowControlWindow;
|
||||||
private final int maxMessageSize;
|
private final int maxMessageSize;
|
||||||
private final int maxHeaderListSize;
|
private final int maxHeaderListSize;
|
||||||
|
private final int softLimitHeaderListSize;
|
||||||
private final long keepAliveTimeInNanos;
|
private final long keepAliveTimeInNanos;
|
||||||
private final long keepAliveTimeoutInNanos;
|
private final long keepAliveTimeoutInNanos;
|
||||||
private final long maxConnectionIdleInNanos;
|
private final long maxConnectionIdleInNanos;
|
||||||
|
|
@ -123,9 +124,14 @@ class NettyServer implements InternalServer, InternalWithLogId {
|
||||||
ProtocolNegotiator protocolNegotiator,
|
ProtocolNegotiator protocolNegotiator,
|
||||||
List<? extends ServerStreamTracer.Factory> streamTracerFactories,
|
List<? extends ServerStreamTracer.Factory> streamTracerFactories,
|
||||||
TransportTracer.Factory transportTracerFactory,
|
TransportTracer.Factory transportTracerFactory,
|
||||||
int maxStreamsPerConnection, boolean autoFlowControl, int flowControlWindow,
|
int maxStreamsPerConnection,
|
||||||
int maxMessageSize, int maxHeaderListSize,
|
boolean autoFlowControl,
|
||||||
long keepAliveTimeInNanos, long keepAliveTimeoutInNanos,
|
int flowControlWindow,
|
||||||
|
int maxMessageSize,
|
||||||
|
int maxHeaderListSize,
|
||||||
|
int softLimitHeaderListSize,
|
||||||
|
long keepAliveTimeInNanos,
|
||||||
|
long keepAliveTimeoutInNanos,
|
||||||
long maxConnectionIdleInNanos,
|
long maxConnectionIdleInNanos,
|
||||||
long maxConnectionAgeInNanos, long maxConnectionAgeGraceInNanos,
|
long maxConnectionAgeInNanos, long maxConnectionAgeGraceInNanos,
|
||||||
boolean permitKeepAliveWithoutCalls, long permitKeepAliveTimeInNanos,
|
boolean permitKeepAliveWithoutCalls, long permitKeepAliveTimeInNanos,
|
||||||
|
|
@ -152,6 +158,7 @@ class NettyServer implements InternalServer, InternalWithLogId {
|
||||||
this.flowControlWindow = flowControlWindow;
|
this.flowControlWindow = flowControlWindow;
|
||||||
this.maxMessageSize = maxMessageSize;
|
this.maxMessageSize = maxMessageSize;
|
||||||
this.maxHeaderListSize = maxHeaderListSize;
|
this.maxHeaderListSize = maxHeaderListSize;
|
||||||
|
this.softLimitHeaderListSize = softLimitHeaderListSize;
|
||||||
this.keepAliveTimeInNanos = keepAliveTimeInNanos;
|
this.keepAliveTimeInNanos = keepAliveTimeInNanos;
|
||||||
this.keepAliveTimeoutInNanos = keepAliveTimeoutInNanos;
|
this.keepAliveTimeoutInNanos = keepAliveTimeoutInNanos;
|
||||||
this.maxConnectionIdleInNanos = maxConnectionIdleInNanos;
|
this.maxConnectionIdleInNanos = maxConnectionIdleInNanos;
|
||||||
|
|
@ -255,6 +262,7 @@ class NettyServer implements InternalServer, InternalWithLogId {
|
||||||
flowControlWindow,
|
flowControlWindow,
|
||||||
maxMessageSize,
|
maxMessageSize,
|
||||||
maxHeaderListSize,
|
maxHeaderListSize,
|
||||||
|
softLimitHeaderListSize,
|
||||||
keepAliveTimeInNanos,
|
keepAliveTimeInNanos,
|
||||||
keepAliveTimeoutInNanos,
|
keepAliveTimeoutInNanos,
|
||||||
maxConnectionIdleInNanos,
|
maxConnectionIdleInNanos,
|
||||||
|
|
|
||||||
|
|
@ -105,6 +105,7 @@ public final class NettyServerBuilder extends ForwardingServerBuilder<NettyServe
|
||||||
private int flowControlWindow = DEFAULT_FLOW_CONTROL_WINDOW;
|
private int flowControlWindow = DEFAULT_FLOW_CONTROL_WINDOW;
|
||||||
private int maxMessageSize = DEFAULT_MAX_MESSAGE_SIZE;
|
private int maxMessageSize = DEFAULT_MAX_MESSAGE_SIZE;
|
||||||
private int maxHeaderListSize = GrpcUtil.DEFAULT_MAX_HEADER_LIST_SIZE;
|
private int maxHeaderListSize = GrpcUtil.DEFAULT_MAX_HEADER_LIST_SIZE;
|
||||||
|
private int softLimitHeaderListSize = GrpcUtil.DEFAULT_MAX_HEADER_LIST_SIZE;
|
||||||
private long keepAliveTimeInNanos = DEFAULT_SERVER_KEEPALIVE_TIME_NANOS;
|
private long keepAliveTimeInNanos = DEFAULT_SERVER_KEEPALIVE_TIME_NANOS;
|
||||||
private long keepAliveTimeoutInNanos = DEFAULT_SERVER_KEEPALIVE_TIMEOUT_NANOS;
|
private long keepAliveTimeoutInNanos = DEFAULT_SERVER_KEEPALIVE_TIMEOUT_NANOS;
|
||||||
private long maxConnectionIdleInNanos = MAX_CONNECTION_IDLE_NANOS_DISABLED;
|
private long maxConnectionIdleInNanos = MAX_CONNECTION_IDLE_NANOS_DISABLED;
|
||||||
|
|
@ -492,6 +493,39 @@ public final class NettyServerBuilder extends ForwardingServerBuilder<NettyServe
|
||||||
public NettyServerBuilder maxInboundMetadataSize(int bytes) {
|
public NettyServerBuilder maxInboundMetadataSize(int bytes) {
|
||||||
checkArgument(bytes > 0, "maxInboundMetadataSize must be positive: %s", bytes);
|
checkArgument(bytes > 0, "maxInboundMetadataSize must be positive: %s", bytes);
|
||||||
this.maxHeaderListSize = bytes;
|
this.maxHeaderListSize = bytes;
|
||||||
|
// Clear the soft limit setting, by setting soft limit to maxInboundMetadataSize. The
|
||||||
|
// maxInboundMetadataSize will take precedence over soft limit check.
|
||||||
|
this.softLimitHeaderListSize = bytes;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets the size of metadata that clients are advised to not exceed. When a metadata with size
|
||||||
|
* larger than the soft limit is encountered there will be a probability the RPC will fail. The
|
||||||
|
* chance of failing increases as the metadata size approaches the hard limit.
|
||||||
|
* {@code Integer.MAX_VALUE} disables the enforcement. The default is implementation-dependent,
|
||||||
|
* but is not generally less than 8 KiB and may be unlimited.
|
||||||
|
*
|
||||||
|
* <p>This is cumulative size of the metadata. The precise calculation is
|
||||||
|
* implementation-dependent, but implementations are encouraged to follow the calculation used
|
||||||
|
* for
|
||||||
|
* <a href="http://httpwg.org/specs/rfc7540.html#rfc.section.6.5.2">HTTP/2's
|
||||||
|
* SETTINGS_MAX_HEADER_LIST_SIZE</a>. It sums the bytes from each entry's key and value, plus 32
|
||||||
|
* bytes of overhead per entry.
|
||||||
|
*
|
||||||
|
* @param soft the soft size limit of received metadata
|
||||||
|
* @param max the hard size limit of received metadata
|
||||||
|
* @return this
|
||||||
|
* @throws IllegalArgumentException if soft and/or max is non-positive, or max smaller than soft
|
||||||
|
* @since 1.68.0
|
||||||
|
*/
|
||||||
|
@CanIgnoreReturnValue
|
||||||
|
public NettyServerBuilder maxInboundMetadataSize(int soft, int max) {
|
||||||
|
checkArgument(soft > 0, "softLimitHeaderListSize must be positive: %s", soft);
|
||||||
|
checkArgument(max > soft,
|
||||||
|
"maxInboundMetadataSize: %s must be greater than softLimitHeaderListSize: %s", max, soft);
|
||||||
|
this.softLimitHeaderListSize = soft;
|
||||||
|
this.maxHeaderListSize = max;
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -677,14 +711,33 @@ public final class NettyServerBuilder extends ForwardingServerBuilder<NettyServe
|
||||||
this.serverImplBuilder.getExecutorPool());
|
this.serverImplBuilder.getExecutorPool());
|
||||||
|
|
||||||
return new NettyServer(
|
return new NettyServer(
|
||||||
listenAddresses, channelFactory, channelOptions, childChannelOptions,
|
listenAddresses,
|
||||||
bossEventLoopGroupPool, workerEventLoopGroupPool, forceHeapBuffer, negotiator,
|
channelFactory,
|
||||||
streamTracerFactories, transportTracerFactory, maxConcurrentCallsPerConnection,
|
channelOptions,
|
||||||
autoFlowControl, flowControlWindow, maxMessageSize, maxHeaderListSize,
|
childChannelOptions,
|
||||||
keepAliveTimeInNanos, keepAliveTimeoutInNanos,
|
bossEventLoopGroupPool,
|
||||||
maxConnectionIdleInNanos, maxConnectionAgeInNanos,
|
workerEventLoopGroupPool,
|
||||||
maxConnectionAgeGraceInNanos, permitKeepAliveWithoutCalls, permitKeepAliveTimeInNanos,
|
forceHeapBuffer,
|
||||||
maxRstCount, maxRstPeriodNanos, eagAttributes, this.serverImplBuilder.getChannelz());
|
negotiator,
|
||||||
|
streamTracerFactories,
|
||||||
|
transportTracerFactory,
|
||||||
|
maxConcurrentCallsPerConnection,
|
||||||
|
autoFlowControl,
|
||||||
|
flowControlWindow,
|
||||||
|
maxMessageSize,
|
||||||
|
maxHeaderListSize,
|
||||||
|
softLimitHeaderListSize,
|
||||||
|
keepAliveTimeInNanos,
|
||||||
|
keepAliveTimeoutInNanos,
|
||||||
|
maxConnectionIdleInNanos,
|
||||||
|
maxConnectionAgeInNanos,
|
||||||
|
maxConnectionAgeGraceInNanos,
|
||||||
|
permitKeepAliveWithoutCalls,
|
||||||
|
permitKeepAliveTimeInNanos,
|
||||||
|
maxRstCount,
|
||||||
|
maxRstPeriodNanos,
|
||||||
|
eagAttributes,
|
||||||
|
this.serverImplBuilder.getChannelz());
|
||||||
}
|
}
|
||||||
|
|
||||||
@VisibleForTesting
|
@VisibleForTesting
|
||||||
|
|
|
||||||
|
|
@ -152,7 +152,6 @@ class NettyServerHandler extends AbstractNettyHandler {
|
||||||
private int rstCount;
|
private int rstCount;
|
||||||
private long lastRstNanoTime;
|
private long lastRstNanoTime;
|
||||||
|
|
||||||
|
|
||||||
static NettyServerHandler newHandler(
|
static NettyServerHandler newHandler(
|
||||||
ServerTransportListener transportListener,
|
ServerTransportListener transportListener,
|
||||||
ChannelPromise channelUnused,
|
ChannelPromise channelUnused,
|
||||||
|
|
@ -162,6 +161,7 @@ class NettyServerHandler extends AbstractNettyHandler {
|
||||||
boolean autoFlowControl,
|
boolean autoFlowControl,
|
||||||
int flowControlWindow,
|
int flowControlWindow,
|
||||||
int maxHeaderListSize,
|
int maxHeaderListSize,
|
||||||
|
int softLimitHeaderListSize,
|
||||||
int maxMessageSize,
|
int maxMessageSize,
|
||||||
long keepAliveTimeInNanos,
|
long keepAliveTimeInNanos,
|
||||||
long keepAliveTimeoutInNanos,
|
long keepAliveTimeoutInNanos,
|
||||||
|
|
@ -192,6 +192,7 @@ class NettyServerHandler extends AbstractNettyHandler {
|
||||||
autoFlowControl,
|
autoFlowControl,
|
||||||
flowControlWindow,
|
flowControlWindow,
|
||||||
maxHeaderListSize,
|
maxHeaderListSize,
|
||||||
|
softLimitHeaderListSize,
|
||||||
maxMessageSize,
|
maxMessageSize,
|
||||||
keepAliveTimeInNanos,
|
keepAliveTimeInNanos,
|
||||||
keepAliveTimeoutInNanos,
|
keepAliveTimeoutInNanos,
|
||||||
|
|
@ -217,6 +218,7 @@ class NettyServerHandler extends AbstractNettyHandler {
|
||||||
boolean autoFlowControl,
|
boolean autoFlowControl,
|
||||||
int flowControlWindow,
|
int flowControlWindow,
|
||||||
int maxHeaderListSize,
|
int maxHeaderListSize,
|
||||||
|
int softLimitHeaderListSize,
|
||||||
int maxMessageSize,
|
int maxMessageSize,
|
||||||
long keepAliveTimeInNanos,
|
long keepAliveTimeInNanos,
|
||||||
long keepAliveTimeoutInNanos,
|
long keepAliveTimeoutInNanos,
|
||||||
|
|
@ -234,6 +236,9 @@ class NettyServerHandler extends AbstractNettyHandler {
|
||||||
flowControlWindow);
|
flowControlWindow);
|
||||||
Preconditions.checkArgument(maxHeaderListSize > 0, "maxHeaderListSize must be positive: %s",
|
Preconditions.checkArgument(maxHeaderListSize > 0, "maxHeaderListSize must be positive: %s",
|
||||||
maxHeaderListSize);
|
maxHeaderListSize);
|
||||||
|
Preconditions.checkArgument(
|
||||||
|
softLimitHeaderListSize > 0, "softLimitHeaderListSize must be positive: %s",
|
||||||
|
softLimitHeaderListSize);
|
||||||
Preconditions.checkArgument(maxMessageSize > 0, "maxMessageSize must be positive: %s",
|
Preconditions.checkArgument(maxMessageSize > 0, "maxMessageSize must be positive: %s",
|
||||||
maxMessageSize);
|
maxMessageSize);
|
||||||
|
|
||||||
|
|
@ -273,7 +278,10 @@ class NettyServerHandler extends AbstractNettyHandler {
|
||||||
transportTracer,
|
transportTracer,
|
||||||
decoder, encoder, settings,
|
decoder, encoder, settings,
|
||||||
maxMessageSize,
|
maxMessageSize,
|
||||||
keepAliveTimeInNanos, keepAliveTimeoutInNanos,
|
maxHeaderListSize,
|
||||||
|
softLimitHeaderListSize,
|
||||||
|
keepAliveTimeInNanos,
|
||||||
|
keepAliveTimeoutInNanos,
|
||||||
maxConnectionIdleInNanos,
|
maxConnectionIdleInNanos,
|
||||||
maxConnectionAgeInNanos, maxConnectionAgeGraceInNanos,
|
maxConnectionAgeInNanos, maxConnectionAgeGraceInNanos,
|
||||||
keepAliveEnforcer,
|
keepAliveEnforcer,
|
||||||
|
|
@ -293,6 +301,8 @@ class NettyServerHandler extends AbstractNettyHandler {
|
||||||
Http2ConnectionEncoder encoder,
|
Http2ConnectionEncoder encoder,
|
||||||
Http2Settings settings,
|
Http2Settings settings,
|
||||||
int maxMessageSize,
|
int maxMessageSize,
|
||||||
|
int maxHeaderListSize,
|
||||||
|
int softLimitHeaderListSize,
|
||||||
long keepAliveTimeInNanos,
|
long keepAliveTimeInNanos,
|
||||||
long keepAliveTimeoutInNanos,
|
long keepAliveTimeoutInNanos,
|
||||||
long maxConnectionIdleInNanos,
|
long maxConnectionIdleInNanos,
|
||||||
|
|
@ -304,8 +314,17 @@ class NettyServerHandler extends AbstractNettyHandler {
|
||||||
long maxRstPeriodNanos,
|
long maxRstPeriodNanos,
|
||||||
Attributes eagAttributes,
|
Attributes eagAttributes,
|
||||||
Ticker ticker) {
|
Ticker ticker) {
|
||||||
super(channelUnused, decoder, encoder, settings, new ServerChannelLogger(),
|
super(
|
||||||
autoFlowControl, null, ticker);
|
channelUnused,
|
||||||
|
decoder,
|
||||||
|
encoder,
|
||||||
|
settings,
|
||||||
|
new ServerChannelLogger(),
|
||||||
|
autoFlowControl,
|
||||||
|
null,
|
||||||
|
ticker,
|
||||||
|
maxHeaderListSize,
|
||||||
|
softLimitHeaderListSize);
|
||||||
|
|
||||||
final MaxConnectionIdleManager maxConnectionIdleManager;
|
final MaxConnectionIdleManager maxConnectionIdleManager;
|
||||||
if (maxConnectionIdleInNanos == MAX_CONNECTION_IDLE_NANOS_DISABLED) {
|
if (maxConnectionIdleInNanos == MAX_CONNECTION_IDLE_NANOS_DISABLED) {
|
||||||
|
|
@ -470,6 +489,16 @@ class NettyServerHandler extends AbstractNettyHandler {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int h2HeadersSize = Utils.getH2HeadersSize(headers);
|
||||||
|
if (Utils.shouldRejectOnMetadataSizeSoftLimitExceeded(
|
||||||
|
h2HeadersSize, softLimitHeaderListSize, maxHeaderListSize)) {
|
||||||
|
respondWithHttpError(ctx, streamId, 431, Status.Code.RESOURCE_EXHAUSTED, String.format(
|
||||||
|
"Client Headers of size %d exceeded Metadata size soft limit: %d",
|
||||||
|
h2HeadersSize,
|
||||||
|
softLimitHeaderListSize));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
if (!teWarningLogged && !TE_TRAILERS.contentEquals(headers.get(TE_HEADER))) {
|
if (!teWarningLogged && !TE_TRAILERS.contentEquals(headers.get(TE_HEADER))) {
|
||||||
logger.warning(String.format("Expected header TE: %s, but %s is received. This means "
|
logger.warning(String.format("Expected header TE: %s, but %s is received. This means "
|
||||||
+ "some intermediate proxy may not support trailers",
|
+ "some intermediate proxy may not support trailers",
|
||||||
|
|
|
||||||
|
|
@ -70,6 +70,7 @@ class NettyServerTransport implements ServerTransport {
|
||||||
private final int flowControlWindow;
|
private final int flowControlWindow;
|
||||||
private final int maxMessageSize;
|
private final int maxMessageSize;
|
||||||
private final int maxHeaderListSize;
|
private final int maxHeaderListSize;
|
||||||
|
private final int softLimitHeaderListSize;
|
||||||
private final long keepAliveTimeInNanos;
|
private final long keepAliveTimeInNanos;
|
||||||
private final long keepAliveTimeoutInNanos;
|
private final long keepAliveTimeoutInNanos;
|
||||||
private final long maxConnectionIdleInNanos;
|
private final long maxConnectionIdleInNanos;
|
||||||
|
|
@ -94,6 +95,7 @@ class NettyServerTransport implements ServerTransport {
|
||||||
int flowControlWindow,
|
int flowControlWindow,
|
||||||
int maxMessageSize,
|
int maxMessageSize,
|
||||||
int maxHeaderListSize,
|
int maxHeaderListSize,
|
||||||
|
int softLimitHeaderListSize,
|
||||||
long keepAliveTimeInNanos,
|
long keepAliveTimeInNanos,
|
||||||
long keepAliveTimeoutInNanos,
|
long keepAliveTimeoutInNanos,
|
||||||
long maxConnectionIdleInNanos,
|
long maxConnectionIdleInNanos,
|
||||||
|
|
@ -115,6 +117,7 @@ class NettyServerTransport implements ServerTransport {
|
||||||
this.flowControlWindow = flowControlWindow;
|
this.flowControlWindow = flowControlWindow;
|
||||||
this.maxMessageSize = maxMessageSize;
|
this.maxMessageSize = maxMessageSize;
|
||||||
this.maxHeaderListSize = maxHeaderListSize;
|
this.maxHeaderListSize = maxHeaderListSize;
|
||||||
|
this.softLimitHeaderListSize = softLimitHeaderListSize;
|
||||||
this.keepAliveTimeInNanos = keepAliveTimeInNanos;
|
this.keepAliveTimeInNanos = keepAliveTimeInNanos;
|
||||||
this.keepAliveTimeoutInNanos = keepAliveTimeoutInNanos;
|
this.keepAliveTimeoutInNanos = keepAliveTimeoutInNanos;
|
||||||
this.maxConnectionIdleInNanos = maxConnectionIdleInNanos;
|
this.maxConnectionIdleInNanos = maxConnectionIdleInNanos;
|
||||||
|
|
@ -275,6 +278,7 @@ class NettyServerTransport implements ServerTransport {
|
||||||
autoFlowControl,
|
autoFlowControl,
|
||||||
flowControlWindow,
|
flowControlWindow,
|
||||||
maxHeaderListSize,
|
maxHeaderListSize,
|
||||||
|
softLimitHeaderListSize,
|
||||||
maxMessageSize,
|
maxMessageSize,
|
||||||
keepAliveTimeInNanos,
|
keepAliveTimeInNanos,
|
||||||
keepAliveTimeoutInNanos,
|
keepAliveTimeoutInNanos,
|
||||||
|
|
|
||||||
|
|
@ -23,6 +23,7 @@ import static io.grpc.internal.TransportFrameUtil.toRawSerializedHeaders;
|
||||||
import static io.netty.channel.ChannelOption.SO_LINGER;
|
import static io.netty.channel.ChannelOption.SO_LINGER;
|
||||||
import static io.netty.channel.ChannelOption.SO_TIMEOUT;
|
import static io.netty.channel.ChannelOption.SO_TIMEOUT;
|
||||||
import static io.netty.util.CharsetUtil.UTF_8;
|
import static io.netty.util.CharsetUtil.UTF_8;
|
||||||
|
import static java.nio.charset.StandardCharsets.US_ASCII;
|
||||||
|
|
||||||
import com.google.common.annotations.VisibleForTesting;
|
import com.google.common.annotations.VisibleForTesting;
|
||||||
import com.google.common.base.Preconditions;
|
import com.google.common.base.Preconditions;
|
||||||
|
|
@ -91,7 +92,9 @@ class Utils {
|
||||||
= new DefaultEventLoopGroupResource(1, "grpc-nio-boss-ELG", EventLoopGroupType.NIO);
|
= new DefaultEventLoopGroupResource(1, "grpc-nio-boss-ELG", EventLoopGroupType.NIO);
|
||||||
public static final Resource<EventLoopGroup> NIO_WORKER_EVENT_LOOP_GROUP
|
public static final Resource<EventLoopGroup> NIO_WORKER_EVENT_LOOP_GROUP
|
||||||
= new DefaultEventLoopGroupResource(0, "grpc-nio-worker-ELG", EventLoopGroupType.NIO);
|
= new DefaultEventLoopGroupResource(0, "grpc-nio-worker-ELG", EventLoopGroupType.NIO);
|
||||||
|
private static final int HEADER_ENTRY_OVERHEAD = 32;
|
||||||
|
private static final byte[] binaryHeaderSuffixBytes =
|
||||||
|
Metadata.BINARY_HEADER_SUFFIX.getBytes(US_ASCII);
|
||||||
public static final Resource<EventLoopGroup> DEFAULT_BOSS_EVENT_LOOP_GROUP;
|
public static final Resource<EventLoopGroup> DEFAULT_BOSS_EVENT_LOOP_GROUP;
|
||||||
public static final Resource<EventLoopGroup> DEFAULT_WORKER_EVENT_LOOP_GROUP;
|
public static final Resource<EventLoopGroup> DEFAULT_WORKER_EVENT_LOOP_GROUP;
|
||||||
|
|
||||||
|
|
@ -195,6 +198,61 @@ class Utils {
|
||||||
return InternalMetadata.newMetadata(convertHeadersToArray(http2Headers));
|
return InternalMetadata.newMetadata(convertHeadersToArray(http2Headers));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static int getH2HeadersSize(Http2Headers http2Headers) {
|
||||||
|
if (http2Headers instanceof GrpcHttp2InboundHeaders) {
|
||||||
|
GrpcHttp2InboundHeaders h = (GrpcHttp2InboundHeaders) http2Headers;
|
||||||
|
int size = 0;
|
||||||
|
for (int i = 0; i < h.numHeaders(); i++) {
|
||||||
|
size += h.namesAndValues()[2 * i].length;
|
||||||
|
size +=
|
||||||
|
maybeAddBinaryHeaderOverhead(h.namesAndValues()[2 * i], h.namesAndValues()[2 * i + 1]);
|
||||||
|
size += HEADER_ENTRY_OVERHEAD;
|
||||||
|
}
|
||||||
|
return size;
|
||||||
|
}
|
||||||
|
|
||||||
|
// the binary header is not decoded yet, no need to add overhead.
|
||||||
|
int size = 0;
|
||||||
|
for (Map.Entry<CharSequence, CharSequence> entry : http2Headers) {
|
||||||
|
size += entry.getKey().length();
|
||||||
|
size += entry.getValue().length();
|
||||||
|
size += HEADER_ENTRY_OVERHEAD;
|
||||||
|
}
|
||||||
|
return size;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static int maybeAddBinaryHeaderOverhead(byte[] name, byte[] value) {
|
||||||
|
if (endsWith(name, binaryHeaderSuffixBytes)) {
|
||||||
|
return value.length * 4 / 3;
|
||||||
|
}
|
||||||
|
return value.length;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static boolean endsWith(byte[] bytes, byte[] suffix) {
|
||||||
|
if (bytes == null || suffix == null || bytes.length < suffix.length) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (int i = 0; i < suffix.length; i++) {
|
||||||
|
if (bytes[bytes.length - suffix.length + i] != suffix[i]) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static boolean shouldRejectOnMetadataSizeSoftLimitExceeded(
|
||||||
|
int h2HeadersSize, int softLimitHeaderListSize, int maxHeaderListSize) {
|
||||||
|
if (h2HeadersSize < softLimitHeaderListSize) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
double failProbability =
|
||||||
|
(double) (h2HeadersSize - softLimitHeaderListSize) / (double) (maxHeaderListSize
|
||||||
|
- softLimitHeaderListSize);
|
||||||
|
return Math.random() < failProbability;
|
||||||
|
}
|
||||||
|
|
||||||
@CheckReturnValue
|
@CheckReturnValue
|
||||||
private static byte[][] convertHeadersToArray(Http2Headers http2Headers) {
|
private static byte[][] convertHeadersToArray(Http2Headers http2Headers) {
|
||||||
// The Netty AsciiString class is really just a wrapper around a byte[] and supports
|
// The Netty AsciiString class is really just a wrapper around a byte[] and supports
|
||||||
|
|
|
||||||
|
|
@ -47,6 +47,7 @@ import static org.mockito.Mockito.verify;
|
||||||
import static org.mockito.Mockito.verifyNoMoreInteractions;
|
import static org.mockito.Mockito.verifyNoMoreInteractions;
|
||||||
|
|
||||||
import com.google.common.base.Stopwatch;
|
import com.google.common.base.Stopwatch;
|
||||||
|
import com.google.common.base.Strings;
|
||||||
import com.google.common.base.Supplier;
|
import com.google.common.base.Supplier;
|
||||||
import com.google.common.base.Ticker;
|
import com.google.common.base.Ticker;
|
||||||
import com.google.common.collect.ImmutableList;
|
import com.google.common.collect.ImmutableList;
|
||||||
|
|
@ -122,6 +123,7 @@ public class NettyClientHandlerTest extends NettyHandlerTestBase<NettyClientHand
|
||||||
private Http2Headers grpcHeaders;
|
private Http2Headers grpcHeaders;
|
||||||
private long nanoTime; // backs a ticker, for testing ping round-trip time measurement
|
private long nanoTime; // backs a ticker, for testing ping round-trip time measurement
|
||||||
private int maxHeaderListSize = Integer.MAX_VALUE;
|
private int maxHeaderListSize = Integer.MAX_VALUE;
|
||||||
|
private int softLimitHeaderListSize = Integer.MAX_VALUE;
|
||||||
private int streamId = STREAM_ID;
|
private int streamId = STREAM_ID;
|
||||||
private ClientTransportLifecycleManager lifecycleManager;
|
private ClientTransportLifecycleManager lifecycleManager;
|
||||||
private KeepAliveManager mockKeepAliveManager = null;
|
private KeepAliveManager mockKeepAliveManager = null;
|
||||||
|
|
@ -217,6 +219,36 @@ public class NettyClientHandlerTest extends NettyHandlerTestBase<NettyClientHand
|
||||||
channelRead(serializedSettings);
|
channelRead(serializedSettings);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
@SuppressWarnings("InlineMeInliner")
|
||||||
|
public void sendLargerThanSoftLimitHeaderMayFail() throws Exception {
|
||||||
|
maxHeaderListSize = 8000;
|
||||||
|
softLimitHeaderListSize = 2000;
|
||||||
|
manualSetUp();
|
||||||
|
|
||||||
|
createStream();
|
||||||
|
// total head size of 7999, soft limit = 2000 and max = 8000.
|
||||||
|
// This header has 5999/6000 chance to be rejected.
|
||||||
|
Http2Headers headers = new DefaultHttp2Headers()
|
||||||
|
.scheme(HTTPS)
|
||||||
|
.authority(as("www.fake.com"))
|
||||||
|
.path(as("/fakemethod"))
|
||||||
|
.method(HTTP_METHOD)
|
||||||
|
.add(as("auth"), as("sometoken"))
|
||||||
|
.add(CONTENT_TYPE_HEADER, CONTENT_TYPE_GRPC)
|
||||||
|
.add(TE_HEADER, TE_TRAILERS)
|
||||||
|
.add("large-field", Strings.repeat("a", 7620)); // String.repeat() requires Java 11
|
||||||
|
|
||||||
|
ByteBuf headersFrame = headersFrame(STREAM_ID, headers);
|
||||||
|
channelRead(headersFrame);
|
||||||
|
ArgumentCaptor<Status> statusArgumentCaptor = ArgumentCaptor.forClass(Status.class);
|
||||||
|
verify(streamListener).closed(statusArgumentCaptor.capture(), eq(PROCESSED),
|
||||||
|
any(Metadata.class));
|
||||||
|
assertThat(statusArgumentCaptor.getValue().getCode()).isEqualTo(Status.Code.RESOURCE_EXHAUSTED);
|
||||||
|
assertThat(statusArgumentCaptor.getValue().getDescription()).contains(
|
||||||
|
"exceeded Metadata size soft limit");
|
||||||
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void cancelBufferedStreamShouldChangeClientStreamStatus() throws Exception {
|
public void cancelBufferedStreamShouldChangeClientStreamStatus() throws Exception {
|
||||||
// Force the stream to be buffered.
|
// Force the stream to be buffered.
|
||||||
|
|
@ -946,6 +978,7 @@ public class NettyClientHandlerTest extends NettyHandlerTestBase<NettyClientHand
|
||||||
false,
|
false,
|
||||||
flowControlWindow,
|
flowControlWindow,
|
||||||
maxHeaderListSize,
|
maxHeaderListSize,
|
||||||
|
softLimitHeaderListSize,
|
||||||
stopwatchSupplier,
|
stopwatchSupplier,
|
||||||
tooManyPingsRunnable,
|
tooManyPingsRunnable,
|
||||||
transportTracer,
|
transportTracer,
|
||||||
|
|
|
||||||
|
|
@ -205,12 +205,30 @@ public class NettyClientTransportTest {
|
||||||
// set SO_LINGER option
|
// set SO_LINGER option
|
||||||
int soLinger = 123;
|
int soLinger = 123;
|
||||||
channelOptions.put(ChannelOption.SO_LINGER, soLinger);
|
channelOptions.put(ChannelOption.SO_LINGER, soLinger);
|
||||||
NettyClientTransport transport = new NettyClientTransport(
|
NettyClientTransport transport =
|
||||||
address, new ReflectiveChannelFactory<>(NioSocketChannel.class), channelOptions, group,
|
new NettyClientTransport(
|
||||||
newNegotiator(), false, DEFAULT_WINDOW_SIZE, DEFAULT_MAX_MESSAGE_SIZE,
|
address,
|
||||||
GrpcUtil.DEFAULT_MAX_HEADER_LIST_SIZE, KEEPALIVE_TIME_NANOS_DISABLED, 1L, false, authority,
|
new ReflectiveChannelFactory<>(NioSocketChannel.class),
|
||||||
null /* user agent */, tooManyPingsRunnable, new TransportTracer(), Attributes.EMPTY,
|
channelOptions,
|
||||||
new SocketPicker(), new FakeChannelLogger(), false, Ticker.systemTicker());
|
group,
|
||||||
|
newNegotiator(),
|
||||||
|
false,
|
||||||
|
DEFAULT_WINDOW_SIZE,
|
||||||
|
DEFAULT_MAX_MESSAGE_SIZE,
|
||||||
|
GrpcUtil.DEFAULT_MAX_HEADER_LIST_SIZE,
|
||||||
|
GrpcUtil.DEFAULT_MAX_HEADER_LIST_SIZE,
|
||||||
|
KEEPALIVE_TIME_NANOS_DISABLED,
|
||||||
|
1L,
|
||||||
|
false,
|
||||||
|
authority,
|
||||||
|
null /* user agent */,
|
||||||
|
tooManyPingsRunnable,
|
||||||
|
new TransportTracer(),
|
||||||
|
Attributes.EMPTY,
|
||||||
|
new SocketPicker(),
|
||||||
|
new FakeChannelLogger(),
|
||||||
|
false,
|
||||||
|
Ticker.systemTicker());
|
||||||
transports.add(transport);
|
transports.add(transport);
|
||||||
callMeMaybe(transport.start(clientTransportListener));
|
callMeMaybe(transport.start(clientTransportListener));
|
||||||
|
|
||||||
|
|
@ -454,13 +472,30 @@ public class NettyClientTransportTest {
|
||||||
public void failingToConstructChannelShouldFailGracefully() throws Exception {
|
public void failingToConstructChannelShouldFailGracefully() throws Exception {
|
||||||
address = TestUtils.testServerAddress(new InetSocketAddress(12345));
|
address = TestUtils.testServerAddress(new InetSocketAddress(12345));
|
||||||
authority = GrpcUtil.authorityFromHostAndPort(address.getHostString(), address.getPort());
|
authority = GrpcUtil.authorityFromHostAndPort(address.getHostString(), address.getPort());
|
||||||
NettyClientTransport transport = new NettyClientTransport(
|
NettyClientTransport transport =
|
||||||
address, new ReflectiveChannelFactory<>(CantConstructChannel.class),
|
new NettyClientTransport(
|
||||||
new HashMap<ChannelOption<?>, Object>(), group,
|
address,
|
||||||
newNegotiator(), false, DEFAULT_WINDOW_SIZE, DEFAULT_MAX_MESSAGE_SIZE,
|
new ReflectiveChannelFactory<>(CantConstructChannel.class),
|
||||||
GrpcUtil.DEFAULT_MAX_HEADER_LIST_SIZE, KEEPALIVE_TIME_NANOS_DISABLED, 1, false, authority,
|
new HashMap<ChannelOption<?>, Object>(),
|
||||||
null, tooManyPingsRunnable, new TransportTracer(), Attributes.EMPTY, new SocketPicker(),
|
group,
|
||||||
new FakeChannelLogger(), false, Ticker.systemTicker());
|
newNegotiator(),
|
||||||
|
false,
|
||||||
|
DEFAULT_WINDOW_SIZE,
|
||||||
|
DEFAULT_MAX_MESSAGE_SIZE,
|
||||||
|
GrpcUtil.DEFAULT_MAX_HEADER_LIST_SIZE,
|
||||||
|
GrpcUtil.DEFAULT_MAX_HEADER_LIST_SIZE,
|
||||||
|
KEEPALIVE_TIME_NANOS_DISABLED,
|
||||||
|
1,
|
||||||
|
false,
|
||||||
|
authority,
|
||||||
|
null,
|
||||||
|
tooManyPingsRunnable,
|
||||||
|
new TransportTracer(),
|
||||||
|
Attributes.EMPTY,
|
||||||
|
new SocketPicker(),
|
||||||
|
new FakeChannelLogger(),
|
||||||
|
false,
|
||||||
|
Ticker.systemTicker());
|
||||||
transports.add(transport);
|
transports.add(transport);
|
||||||
|
|
||||||
// Should not throw
|
// Should not throw
|
||||||
|
|
@ -814,12 +849,29 @@ public class NettyClientTransportTest {
|
||||||
if (!enableKeepAlive) {
|
if (!enableKeepAlive) {
|
||||||
keepAliveTimeNano = KEEPALIVE_TIME_NANOS_DISABLED;
|
keepAliveTimeNano = KEEPALIVE_TIME_NANOS_DISABLED;
|
||||||
}
|
}
|
||||||
NettyClientTransport transport = new NettyClientTransport(
|
NettyClientTransport transport =
|
||||||
address, channelFactory, new HashMap<ChannelOption<?>, Object>(), group,
|
new NettyClientTransport(
|
||||||
negotiator, false, DEFAULT_WINDOW_SIZE, maxMsgSize, maxHeaderListSize,
|
address,
|
||||||
keepAliveTimeNano, keepAliveTimeoutNano,
|
channelFactory,
|
||||||
false, authority, userAgent, tooManyPingsRunnable,
|
new HashMap<ChannelOption<?>, Object>(),
|
||||||
new TransportTracer(), eagAttributes, new SocketPicker(), new FakeChannelLogger(), false,
|
group,
|
||||||
|
negotiator,
|
||||||
|
false,
|
||||||
|
DEFAULT_WINDOW_SIZE,
|
||||||
|
maxMsgSize,
|
||||||
|
maxHeaderListSize,
|
||||||
|
maxHeaderListSize,
|
||||||
|
keepAliveTimeNano,
|
||||||
|
keepAliveTimeoutNano,
|
||||||
|
false,
|
||||||
|
authority,
|
||||||
|
userAgent,
|
||||||
|
tooManyPingsRunnable,
|
||||||
|
new TransportTracer(),
|
||||||
|
eagAttributes,
|
||||||
|
new SocketPicker(),
|
||||||
|
new FakeChannelLogger(),
|
||||||
|
false,
|
||||||
Ticker.systemTicker());
|
Ticker.systemTicker());
|
||||||
transports.add(transport);
|
transports.add(transport);
|
||||||
return transport;
|
return transport;
|
||||||
|
|
@ -830,21 +882,34 @@ public class NettyClientTransportTest {
|
||||||
}
|
}
|
||||||
|
|
||||||
private void startServer(int maxStreamsPerConnection, int maxHeaderListSize) throws IOException {
|
private void startServer(int maxStreamsPerConnection, int maxHeaderListSize) throws IOException {
|
||||||
server = new NettyServer(
|
server =
|
||||||
|
new NettyServer(
|
||||||
TestUtils.testServerAddresses(new InetSocketAddress(0)),
|
TestUtils.testServerAddresses(new InetSocketAddress(0)),
|
||||||
new ReflectiveChannelFactory<>(NioServerSocketChannel.class),
|
new ReflectiveChannelFactory<>(NioServerSocketChannel.class),
|
||||||
new HashMap<ChannelOption<?>, Object>(),
|
new HashMap<ChannelOption<?>, Object>(),
|
||||||
new HashMap<ChannelOption<?>, Object>(),
|
new HashMap<ChannelOption<?>, Object>(),
|
||||||
new FixedObjectPool<>(group), new FixedObjectPool<>(group), false, negotiator,
|
new FixedObjectPool<>(group),
|
||||||
|
new FixedObjectPool<>(group),
|
||||||
|
false,
|
||||||
|
negotiator,
|
||||||
Collections.<ServerStreamTracer.Factory>emptyList(),
|
Collections.<ServerStreamTracer.Factory>emptyList(),
|
||||||
TransportTracer.getDefaultFactory(),
|
TransportTracer.getDefaultFactory(),
|
||||||
maxStreamsPerConnection,
|
maxStreamsPerConnection,
|
||||||
false,
|
false,
|
||||||
DEFAULT_WINDOW_SIZE, DEFAULT_MAX_MESSAGE_SIZE, maxHeaderListSize,
|
DEFAULT_WINDOW_SIZE,
|
||||||
DEFAULT_SERVER_KEEPALIVE_TIME_NANOS, DEFAULT_SERVER_KEEPALIVE_TIMEOUT_NANOS,
|
DEFAULT_MAX_MESSAGE_SIZE,
|
||||||
|
maxHeaderListSize,
|
||||||
|
maxHeaderListSize,
|
||||||
|
DEFAULT_SERVER_KEEPALIVE_TIME_NANOS,
|
||||||
|
DEFAULT_SERVER_KEEPALIVE_TIMEOUT_NANOS,
|
||||||
MAX_CONNECTION_IDLE_NANOS_DISABLED,
|
MAX_CONNECTION_IDLE_NANOS_DISABLED,
|
||||||
MAX_CONNECTION_AGE_NANOS_DISABLED, MAX_CONNECTION_AGE_GRACE_NANOS_INFINITE, true, 0,
|
MAX_CONNECTION_AGE_NANOS_DISABLED,
|
||||||
MAX_RST_COUNT_DISABLED, 0, Attributes.EMPTY,
|
MAX_CONNECTION_AGE_GRACE_NANOS_INFINITE,
|
||||||
|
true,
|
||||||
|
0,
|
||||||
|
MAX_RST_COUNT_DISABLED,
|
||||||
|
0,
|
||||||
|
Attributes.EMPTY,
|
||||||
channelz);
|
channelz);
|
||||||
server.start(serverListener);
|
server.start(serverListener);
|
||||||
address = TestUtils.testServerAddress((InetSocketAddress) server.getListenSocketAddress());
|
address = TestUtils.testServerAddress((InetSocketAddress) server.getListenSocketAddress());
|
||||||
|
|
|
||||||
|
|
@ -100,6 +100,22 @@ public class NettyServerBuilderTest {
|
||||||
builder.maxInboundMetadataSize(0);
|
builder.maxInboundMetadataSize(0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void failIfSoftInboundMetadataSizeNonPositive() {
|
||||||
|
thrown.expect(IllegalArgumentException.class);
|
||||||
|
thrown.expectMessage("softLimitHeaderListSize must be positive");
|
||||||
|
|
||||||
|
builder.maxInboundMetadataSize(0, 100);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void failIfMaxInboundMetadataSizeSmallerThanSoft() {
|
||||||
|
thrown.expect(IllegalArgumentException.class);
|
||||||
|
thrown.expectMessage("must be greater than softLimitHeaderListSize");
|
||||||
|
|
||||||
|
builder.maxInboundMetadataSize(100, 80);
|
||||||
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void failIfMaxConnectionIdleNegative() {
|
public void failIfMaxConnectionIdleNegative() {
|
||||||
thrown.expect(IllegalArgumentException.class);
|
thrown.expect(IllegalArgumentException.class);
|
||||||
|
|
|
||||||
|
|
@ -141,6 +141,7 @@ public class NettyServerHandlerTest extends NettyHandlerTestBase<NettyServerHand
|
||||||
|
|
||||||
private int maxConcurrentStreams = Integer.MAX_VALUE;
|
private int maxConcurrentStreams = Integer.MAX_VALUE;
|
||||||
private int maxHeaderListSize = Integer.MAX_VALUE;
|
private int maxHeaderListSize = Integer.MAX_VALUE;
|
||||||
|
private int softLimitHeaderListSize = Integer.MAX_VALUE;
|
||||||
private boolean permitKeepAliveWithoutCalls = true;
|
private boolean permitKeepAliveWithoutCalls = true;
|
||||||
private long permitKeepAliveTimeInNanos = 0;
|
private long permitKeepAliveTimeInNanos = 0;
|
||||||
private long maxConnectionIdleInNanos = MAX_CONNECTION_IDLE_NANOS_DISABLED;
|
private long maxConnectionIdleInNanos = MAX_CONNECTION_IDLE_NANOS_DISABLED;
|
||||||
|
|
@ -1363,6 +1364,7 @@ public class NettyServerHandlerTest extends NettyHandlerTestBase<NettyServerHand
|
||||||
autoFlowControl,
|
autoFlowControl,
|
||||||
flowControlWindow,
|
flowControlWindow,
|
||||||
maxHeaderListSize,
|
maxHeaderListSize,
|
||||||
|
softLimitHeaderListSize,
|
||||||
DEFAULT_MAX_MESSAGE_SIZE,
|
DEFAULT_MAX_MESSAGE_SIZE,
|
||||||
keepAliveTimeInNanos,
|
keepAliveTimeInNanos,
|
||||||
keepAliveTimeoutInNanos,
|
keepAliveTimeoutInNanos,
|
||||||
|
|
|
||||||
|
|
@ -133,7 +133,8 @@ public class NettyServerTest {
|
||||||
}
|
}
|
||||||
|
|
||||||
NoHandlerProtocolNegotiator protocolNegotiator = new NoHandlerProtocolNegotiator();
|
NoHandlerProtocolNegotiator protocolNegotiator = new NoHandlerProtocolNegotiator();
|
||||||
NettyServer ns = new NettyServer(
|
NettyServer ns =
|
||||||
|
new NettyServer(
|
||||||
Arrays.asList(addr),
|
Arrays.asList(addr),
|
||||||
new ReflectiveChannelFactory<>(NioServerSocketChannel.class),
|
new ReflectiveChannelFactory<>(NioServerSocketChannel.class),
|
||||||
new HashMap<ChannelOption<?>, Object>(),
|
new HashMap<ChannelOption<?>, Object>(),
|
||||||
|
|
@ -150,10 +151,15 @@ public class NettyServerTest {
|
||||||
1, // ignore
|
1, // ignore
|
||||||
1, // ignore
|
1, // ignore
|
||||||
1, // ignore
|
1, // ignore
|
||||||
1, 1, // ignore
|
1, // ignore
|
||||||
1, 1, // ignore
|
1,
|
||||||
true, 0, // ignore
|
1, // ignore
|
||||||
0, 0, // ignore
|
1,
|
||||||
|
1, // ignore
|
||||||
|
true,
|
||||||
|
0, // ignore
|
||||||
|
0,
|
||||||
|
0, // ignore
|
||||||
Attributes.EMPTY,
|
Attributes.EMPTY,
|
||||||
channelz);
|
channelz);
|
||||||
final SettableFuture<Void> serverShutdownCalled = SettableFuture.create();
|
final SettableFuture<Void> serverShutdownCalled = SettableFuture.create();
|
||||||
|
|
@ -184,7 +190,8 @@ public class NettyServerTest {
|
||||||
InetSocketAddress addr1 = new InetSocketAddress(0);
|
InetSocketAddress addr1 = new InetSocketAddress(0);
|
||||||
InetSocketAddress addr2 = new InetSocketAddress(0);
|
InetSocketAddress addr2 = new InetSocketAddress(0);
|
||||||
|
|
||||||
NettyServer ns = new NettyServer(
|
NettyServer ns =
|
||||||
|
new NettyServer(
|
||||||
Arrays.asList(addr1, addr2),
|
Arrays.asList(addr1, addr2),
|
||||||
new ReflectiveChannelFactory<>(NioServerSocketChannel.class),
|
new ReflectiveChannelFactory<>(NioServerSocketChannel.class),
|
||||||
new HashMap<ChannelOption<?>, Object>(),
|
new HashMap<ChannelOption<?>, Object>(),
|
||||||
|
|
@ -201,10 +208,15 @@ public class NettyServerTest {
|
||||||
1, // ignore
|
1, // ignore
|
||||||
1, // ignore
|
1, // ignore
|
||||||
1, // ignore
|
1, // ignore
|
||||||
1, 1, // ignore
|
1, // ignore
|
||||||
1, 1, // ignore
|
1,
|
||||||
true, 0, // ignore
|
1, // ignore
|
||||||
0, 0, // ignore
|
1,
|
||||||
|
1, // ignore
|
||||||
|
true,
|
||||||
|
0, // ignore
|
||||||
|
0,
|
||||||
|
0, // ignore
|
||||||
Attributes.EMPTY,
|
Attributes.EMPTY,
|
||||||
channelz);
|
channelz);
|
||||||
final SettableFuture<Void> shutdownCompleted = SettableFuture.create();
|
final SettableFuture<Void> shutdownCompleted = SettableFuture.create();
|
||||||
|
|
@ -258,7 +270,8 @@ public class NettyServerTest {
|
||||||
InetSocketAddress addr2 = new InetSocketAddress(0);
|
InetSocketAddress addr2 = new InetSocketAddress(0);
|
||||||
final CountDownLatch allPortsConnectedCountDown = new CountDownLatch(2);
|
final CountDownLatch allPortsConnectedCountDown = new CountDownLatch(2);
|
||||||
|
|
||||||
NettyServer ns = new NettyServer(
|
NettyServer ns =
|
||||||
|
new NettyServer(
|
||||||
Arrays.asList(addr1, addr2),
|
Arrays.asList(addr1, addr2),
|
||||||
new ReflectiveChannelFactory<>(NioServerSocketChannel.class),
|
new ReflectiveChannelFactory<>(NioServerSocketChannel.class),
|
||||||
new HashMap<ChannelOption<?>, Object>(),
|
new HashMap<ChannelOption<?>, Object>(),
|
||||||
|
|
@ -275,10 +288,15 @@ public class NettyServerTest {
|
||||||
1, // ignore
|
1, // ignore
|
||||||
1, // ignore
|
1, // ignore
|
||||||
1, // ignore
|
1, // ignore
|
||||||
1, 1, // ignore
|
1, // ignore
|
||||||
1, 1, // ignore
|
1,
|
||||||
true, 0, // ignore
|
1, // ignore
|
||||||
0, 0, // ignore
|
1,
|
||||||
|
1, // ignore
|
||||||
|
true,
|
||||||
|
0, // ignore
|
||||||
|
0,
|
||||||
|
0, // ignore
|
||||||
Attributes.EMPTY,
|
Attributes.EMPTY,
|
||||||
channelz);
|
channelz);
|
||||||
final SettableFuture<Void> shutdownCompleted = SettableFuture.create();
|
final SettableFuture<Void> shutdownCompleted = SettableFuture.create();
|
||||||
|
|
@ -320,7 +338,8 @@ public class NettyServerTest {
|
||||||
public void getPort_notStarted() {
|
public void getPort_notStarted() {
|
||||||
InetSocketAddress addr = new InetSocketAddress(0);
|
InetSocketAddress addr = new InetSocketAddress(0);
|
||||||
List<InetSocketAddress> addresses = Collections.singletonList(addr);
|
List<InetSocketAddress> addresses = Collections.singletonList(addr);
|
||||||
NettyServer ns = new NettyServer(
|
NettyServer ns =
|
||||||
|
new NettyServer(
|
||||||
addresses,
|
addresses,
|
||||||
new ReflectiveChannelFactory<>(NioServerSocketChannel.class),
|
new ReflectiveChannelFactory<>(NioServerSocketChannel.class),
|
||||||
new HashMap<ChannelOption<?>, Object>(),
|
new HashMap<ChannelOption<?>, Object>(),
|
||||||
|
|
@ -337,10 +356,15 @@ public class NettyServerTest {
|
||||||
1, // ignore
|
1, // ignore
|
||||||
1, // ignore
|
1, // ignore
|
||||||
1, // ignore
|
1, // ignore
|
||||||
1, 1, // ignore
|
1, // ignore
|
||||||
1, 1, // ignore
|
1,
|
||||||
true, 0, // ignore
|
1, // ignore
|
||||||
0, 0, // ignore
|
1,
|
||||||
|
1, // ignore
|
||||||
|
true,
|
||||||
|
0, // ignore
|
||||||
|
0,
|
||||||
|
0, // ignore
|
||||||
Attributes.EMPTY,
|
Attributes.EMPTY,
|
||||||
channelz);
|
channelz);
|
||||||
|
|
||||||
|
|
@ -395,7 +419,8 @@ public class NettyServerTest {
|
||||||
.build();
|
.build();
|
||||||
TestProtocolNegotiator protocolNegotiator = new TestProtocolNegotiator();
|
TestProtocolNegotiator protocolNegotiator = new TestProtocolNegotiator();
|
||||||
InetSocketAddress addr = new InetSocketAddress(0);
|
InetSocketAddress addr = new InetSocketAddress(0);
|
||||||
NettyServer ns = new NettyServer(
|
NettyServer ns =
|
||||||
|
new NettyServer(
|
||||||
Arrays.asList(addr),
|
Arrays.asList(addr),
|
||||||
new ReflectiveChannelFactory<>(NioServerSocketChannel.class),
|
new ReflectiveChannelFactory<>(NioServerSocketChannel.class),
|
||||||
new HashMap<ChannelOption<?>, Object>(),
|
new HashMap<ChannelOption<?>, Object>(),
|
||||||
|
|
@ -412,10 +437,15 @@ public class NettyServerTest {
|
||||||
1, // ignore
|
1, // ignore
|
||||||
1, // ignore
|
1, // ignore
|
||||||
1, // ignore
|
1, // ignore
|
||||||
1, 1, // ignore
|
1, // ignore
|
||||||
1, 1, // ignore
|
1,
|
||||||
true, 0, // ignore
|
1, // ignore
|
||||||
0, 0, // ignore
|
1,
|
||||||
|
1, // ignore
|
||||||
|
true,
|
||||||
|
0, // ignore
|
||||||
|
0,
|
||||||
|
0, // ignore
|
||||||
eagAttributes,
|
eagAttributes,
|
||||||
channelz);
|
channelz);
|
||||||
ns.start(new ServerListener() {
|
ns.start(new ServerListener() {
|
||||||
|
|
@ -443,7 +473,8 @@ public class NettyServerTest {
|
||||||
@Test
|
@Test
|
||||||
public void channelzListenSocket() throws Exception {
|
public void channelzListenSocket() throws Exception {
|
||||||
InetSocketAddress addr = new InetSocketAddress(0);
|
InetSocketAddress addr = new InetSocketAddress(0);
|
||||||
NettyServer ns = new NettyServer(
|
NettyServer ns =
|
||||||
|
new NettyServer(
|
||||||
Arrays.asList(addr),
|
Arrays.asList(addr),
|
||||||
new ReflectiveChannelFactory<>(NioServerSocketChannel.class),
|
new ReflectiveChannelFactory<>(NioServerSocketChannel.class),
|
||||||
new HashMap<ChannelOption<?>, Object>(),
|
new HashMap<ChannelOption<?>, Object>(),
|
||||||
|
|
@ -460,10 +491,15 @@ public class NettyServerTest {
|
||||||
1, // ignore
|
1, // ignore
|
||||||
1, // ignore
|
1, // ignore
|
||||||
1, // ignore
|
1, // ignore
|
||||||
1, 1, // ignore
|
1, // ignore
|
||||||
1, 1, // ignore
|
1,
|
||||||
true, 0, // ignore
|
1, // ignore
|
||||||
0, 0, // ignore
|
1,
|
||||||
|
1, // ignore
|
||||||
|
true,
|
||||||
|
0, // ignore
|
||||||
|
0,
|
||||||
|
0, // ignore
|
||||||
Attributes.EMPTY,
|
Attributes.EMPTY,
|
||||||
channelz);
|
channelz);
|
||||||
final SettableFuture<Void> shutdownCompleted = SettableFuture.create();
|
final SettableFuture<Void> shutdownCompleted = SettableFuture.create();
|
||||||
|
|
@ -603,10 +639,15 @@ public class NettyServerTest {
|
||||||
1, // ignore
|
1, // ignore
|
||||||
1, // ignore
|
1, // ignore
|
||||||
1, // ignore
|
1, // ignore
|
||||||
1, 1, // ignore
|
1, // ignore
|
||||||
1, 1, // ignore
|
1,
|
||||||
true, 0, // ignore
|
1, // ignore
|
||||||
0, 0, // ignore
|
1,
|
||||||
|
1, // ignore
|
||||||
|
true,
|
||||||
|
0, // ignore
|
||||||
|
0,
|
||||||
|
0, // ignore
|
||||||
Attributes.EMPTY,
|
Attributes.EMPTY,
|
||||||
channelz);
|
channelz);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue