From 735b3f3fe6c6b9d8fc6019e8c89f81c065d9b0d6 Mon Sep 17 00:00:00 2001 From: Ran Date: Mon, 28 Oct 2024 10:25:17 -0700 Subject: [PATCH] netty: add soft Metadata size limit enforcement. (#11603) --- .../io/grpc/netty/AbstractNettyHandler.java | 9 +- .../io/grpc/netty/NettyChannelBuilder.java | 130 +++++-- .../io/grpc/netty/NettyClientHandler.java | 48 ++- .../io/grpc/netty/NettyClientTransport.java | 58 ++-- .../main/java/io/grpc/netty/NettyServer.java | 58 ++-- .../io/grpc/netty/NettyServerBuilder.java | 69 +++- .../io/grpc/netty/NettyServerHandler.java | 37 +- .../io/grpc/netty/NettyServerTransport.java | 4 + netty/src/main/java/io/grpc/netty/Utils.java | 60 +++- .../io/grpc/netty/NettyClientHandlerTest.java | 33 ++ .../grpc/netty/NettyClientTransportTest.java | 137 ++++++-- .../io/grpc/netty/NettyServerBuilderTest.java | 16 + .../io/grpc/netty/NettyServerHandlerTest.java | 2 + .../java/io/grpc/netty/NettyServerTest.java | 325 ++++++++++-------- 14 files changed, 722 insertions(+), 264 deletions(-) diff --git a/netty/src/main/java/io/grpc/netty/AbstractNettyHandler.java b/netty/src/main/java/io/grpc/netty/AbstractNettyHandler.java index 7f088509c04..6743b4fd5f7 100644 --- a/netty/src/main/java/io/grpc/netty/AbstractNettyHandler.java +++ b/netty/src/main/java/io/grpc/netty/AbstractNettyHandler.java @@ -42,7 +42,8 @@ abstract class AbstractNettyHandler extends GrpcHttp2ConnectionHandler { private final int initialConnectionWindow; private final FlowControlPinger flowControlPing; - + protected final int maxHeaderListSize; + protected final int softLimitHeaderListSize; private boolean autoTuneFlowControlOn; private ChannelHandlerContext ctx; private boolean initialWindowSent = false; @@ -58,7 +59,9 @@ abstract class AbstractNettyHandler extends GrpcHttp2ConnectionHandler { ChannelLogger negotiationLogger, boolean autoFlowControl, PingLimiter pingLimiter, - Ticker ticker) { + Ticker ticker, + int maxHeaderListSize, + int softLimitHeaderListSize) { super(channelUnused, decoder, encoder, initialSettings, negotiationLogger); // 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.ticker = checkNotNull(ticker, "ticker"); + this.maxHeaderListSize = maxHeaderListSize; + this.softLimitHeaderListSize = softLimitHeaderListSize; } @Override diff --git a/netty/src/main/java/io/grpc/netty/NettyChannelBuilder.java b/netty/src/main/java/io/grpc/netty/NettyChannelBuilder.java index d1d9810b485..fe226ec2ba9 100644 --- a/netty/src/main/java/io/grpc/netty/NettyChannelBuilder.java +++ b/netty/src/main/java/io/grpc/netty/NettyChannelBuilder.java @@ -104,6 +104,7 @@ public final class NettyChannelBuilder extends ForwardingChannelBuilder2 0, "maxInboundMetadataSize must be > 0"); 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. + * + *

This is cumulative size of the metadata. The precise calculation is + * implementation-dependent, but implementations are encouraged to follow the calculation used + * for + * HTTP/2's + * SETTINGS_MAX_HEADER_LIST_SIZE. 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; } @@ -573,10 +608,22 @@ ClientTransportFactory buildTransportFactory() { ProtocolNegotiator negotiator = protocolNegotiatorFactory.newNegotiator(); return new NettyTransportFactory( - negotiator, channelFactory, channelOptions, - eventLoopGroupPool, autoFlowControl, flowControlWindow, maxInboundMessageSize, - maxHeaderListSize, keepAliveTimeNanos, keepAliveTimeoutNanos, keepAliveWithoutCalls, - transportTracerFactory, localSocketPicker, useGetForSafeMethods, transportSocketType); + negotiator, + channelFactory, + channelOptions, + eventLoopGroupPool, + autoFlowControl, + flowControlWindow, + maxInboundMessageSize, + maxHeaderListSize, + softLimitHeaderListSize, + keepAliveTimeNanos, + keepAliveTimeoutNanos, + keepAliveWithoutCalls, + transportTracerFactory, + localSocketPicker, + useGetForSafeMethods, + transportSocketType); } @VisibleForTesting @@ -710,6 +757,7 @@ private static final class NettyTransportFactory implements ClientTransportFacto private final int flowControlWindow; private final int maxMessageSize; private final int maxHeaderListSize; + private final int softLimitHeaderListSize; private final long keepAliveTimeNanos; private final AtomicBackoff keepAliveBackoff; private final long keepAliveTimeoutNanos; @@ -724,11 +772,20 @@ private static final class NettyTransportFactory implements ClientTransportFacto NettyTransportFactory( ProtocolNegotiator protocolNegotiator, ChannelFactory channelFactory, - Map, ?> channelOptions, ObjectPool groupPool, - boolean autoFlowControl, int flowControlWindow, int maxMessageSize, int maxHeaderListSize, - long keepAliveTimeNanos, long keepAliveTimeoutNanos, boolean keepAliveWithoutCalls, - TransportTracer.Factory transportTracerFactory, LocalSocketPicker localSocketPicker, - boolean useGetForSafeMethods, Class transportSocketType) { + Map, ?> channelOptions, + ObjectPool groupPool, + boolean autoFlowControl, + int flowControlWindow, + int maxMessageSize, + int maxHeaderListSize, + int softLimitHeaderListSize, + long keepAliveTimeNanos, + long keepAliveTimeoutNanos, + boolean keepAliveWithoutCalls, + TransportTracer.Factory transportTracerFactory, + LocalSocketPicker localSocketPicker, + boolean useGetForSafeMethods, + Class transportSocketType) { this.protocolNegotiator = checkNotNull(protocolNegotiator, "protocolNegotiator"); this.channelFactory = channelFactory; this.channelOptions = new HashMap, Object>(channelOptions); @@ -738,6 +795,7 @@ private static final class NettyTransportFactory implements ClientTransportFacto this.flowControlWindow = flowControlWindow; this.maxMessageSize = maxMessageSize; this.maxHeaderListSize = maxHeaderListSize; + this.softLimitHeaderListSize = softLimitHeaderListSize; this.keepAliveTimeNanos = keepAliveTimeNanos; this.keepAliveBackoff = new AtomicBackoff("keepalive time nanos", keepAliveTimeNanos); this.keepAliveTimeoutNanos = keepAliveTimeoutNanos; @@ -774,13 +832,30 @@ public void run() { }; // TODO(carl-mastrangelo): Pass channelLogger in. - NettyClientTransport transport = new NettyClientTransport( - serverAddress, channelFactory, channelOptions, group, - localNegotiator, autoFlowControl, flowControlWindow, - maxMessageSize, maxHeaderListSize, keepAliveTimeNanosState.get(), keepAliveTimeoutNanos, - keepAliveWithoutCalls, options.getAuthority(), options.getUserAgent(), - tooManyPingsRunnable, transportTracerFactory.create(), options.getEagAttributes(), - localSocketPicker, channelLogger, useGetForSafeMethods, Ticker.systemTicker()); + NettyClientTransport transport = + new NettyClientTransport( + serverAddress, + channelFactory, + channelOptions, + group, + 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; } @@ -796,11 +871,24 @@ public SwapChannelCredentialsResult swapChannelCredentials(ChannelCredentials ch if (result.error != null) { return null; } - ClientTransportFactory factory = new NettyTransportFactory( - result.negotiator.newNegotiator(), channelFactory, channelOptions, groupPool, - autoFlowControl, flowControlWindow, maxMessageSize, maxHeaderListSize, keepAliveTimeNanos, - keepAliveTimeoutNanos, keepAliveWithoutCalls, transportTracerFactory, localSocketPicker, - useGetForSafeMethods, transportSocketType); + ClientTransportFactory factory = + new NettyTransportFactory( + result.negotiator.newNegotiator(), + channelFactory, + channelOptions, + groupPool, + autoFlowControl, + flowControlWindow, + maxMessageSize, + maxHeaderListSize, + softLimitHeaderListSize, + keepAliveTimeNanos, + keepAliveTimeoutNanos, + keepAliveWithoutCalls, + transportTracerFactory, + localSocketPicker, + useGetForSafeMethods, + transportSocketType); return new SwapChannelCredentialsResult(factory, result.callCredentials); } diff --git a/netty/src/main/java/io/grpc/netty/NettyClientHandler.java b/netty/src/main/java/io/grpc/netty/NettyClientHandler.java index eb4dbf8cc66..194decb1120 100644 --- a/netty/src/main/java/io/grpc/netty/NettyClientHandler.java +++ b/netty/src/main/java/io/grpc/netty/NettyClientHandler.java @@ -142,6 +142,7 @@ static NettyClientHandler newHandler( boolean autoFlowControl, int flowControlWindow, int maxHeaderListSize, + int softLimitHeaderListSize, Supplier stopwatchFactory, Runnable tooManyPingsRunnable, TransportTracer transportTracer, @@ -171,6 +172,7 @@ static NettyClientHandler newHandler( autoFlowControl, flowControlWindow, maxHeaderListSize, + softLimitHeaderListSize, stopwatchFactory, tooManyPingsRunnable, transportTracer, @@ -190,6 +192,7 @@ static NettyClientHandler newHandler( boolean autoFlowControl, int flowControlWindow, int maxHeaderListSize, + int softLimitHeaderListSize, Supplier stopwatchFactory, Runnable tooManyPingsRunnable, TransportTracer transportTracer, @@ -202,6 +205,8 @@ static NettyClientHandler newHandler( Preconditions.checkNotNull(lifecycleManager, "lifecycleManager"); Preconditions.checkArgument(flowControlWindow > 0, "flowControlWindow 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(tooManyPingsRunnable, "tooManyPingsRunnable"); Preconditions.checkNotNull(eagAttributes, "eagAttributes"); @@ -247,7 +252,9 @@ static NettyClientHandler newHandler( authority, autoFlowControl, pingCounter, - ticker); + ticker, + maxHeaderListSize, + softLimitHeaderListSize); } private NettyClientHandler( @@ -264,9 +271,20 @@ private NettyClientHandler( String authority, boolean autoFlowControl, PingLimiter pingLimiter, - Ticker ticker) { - super(/* channelUnused= */ null, decoder, encoder, settings, - negotiationLogger, autoFlowControl, pingLimiter, ticker); + Ticker ticker, + int maxHeaderListSize, + int softLimitHeaderListSize) { + super( + /* channelUnused= */ null, + decoder, + encoder, + settings, + negotiationLogger, + autoFlowControl, + pingLimiter, + ticker, + maxHeaderListSize, + softLimitHeaderListSize); this.lifecycleManager = lifecycleManager; this.keepAliveManager = keepAliveManager; this.stopwatchFactory = stopwatchFactory; @@ -380,6 +398,28 @@ private void onHeadersRead(int streamId, Http2Headers headers, boolean endStream if (streamId != Http2CodecUtil.HTTP_UPGRADE_STREAM_ID) { NettyClientStream.TransportState stream = clientStream(requireHttp2Stream(streamId)); 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); } diff --git a/netty/src/main/java/io/grpc/netty/NettyClientTransport.java b/netty/src/main/java/io/grpc/netty/NettyClientTransport.java index 426f3c0d583..54d1641a7ed 100644 --- a/netty/src/main/java/io/grpc/netty/NettyClientTransport.java +++ b/netty/src/main/java/io/grpc/netty/NettyClientTransport.java @@ -83,6 +83,7 @@ class NettyClientTransport implements ConnectionClientTransport { private final int flowControlWindow; private final int maxMessageSize; private final int maxHeaderListSize; + private final int softLimitHeaderListSize; private KeepAliveManager keepAliveManager; private final long keepAliveTimeNanos; private final long keepAliveTimeoutNanos; @@ -106,15 +107,28 @@ class NettyClientTransport implements ConnectionClientTransport { private final Ticker ticker; NettyClientTransport( - SocketAddress address, ChannelFactory channelFactory, - Map, ?> channelOptions, EventLoopGroup group, - ProtocolNegotiator negotiator, boolean autoFlowControl, int flowControlWindow, - int maxMessageSize, int maxHeaderListSize, - 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) { + SocketAddress address, + ChannelFactory channelFactory, + Map, ?> channelOptions, + EventLoopGroup group, + ProtocolNegotiator negotiator, + boolean autoFlowControl, + int flowControlWindow, + int maxMessageSize, + 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.negotiationScheme = this.negotiator.scheme(); @@ -126,6 +140,7 @@ class NettyClientTransport implements ConnectionClientTransport { this.flowControlWindow = flowControlWindow; this.maxMessageSize = maxMessageSize; this.maxHeaderListSize = maxHeaderListSize; + this.softLimitHeaderListSize = softLimitHeaderListSize; this.keepAliveTimeNanos = keepAliveTimeNanos; this.keepAliveTimeoutNanos = keepAliveTimeoutNanos; this.keepAliveWithoutCalls = keepAliveWithoutCalls; @@ -220,18 +235,19 @@ public Runnable start(Listener transportListener) { } handler = NettyClientHandler.newHandler( - lifecycleManager, - keepAliveManager, - autoFlowControl, - flowControlWindow, - maxHeaderListSize, - GrpcUtil.STOPWATCH_SUPPLIER, - tooManyPingsRunnable, - transportTracer, - eagAttributes, - authorityString, - channelLogger, - ticker); + lifecycleManager, + keepAliveManager, + autoFlowControl, + flowControlWindow, + maxHeaderListSize, + softLimitHeaderListSize, + GrpcUtil.STOPWATCH_SUPPLIER, + tooManyPingsRunnable, + transportTracer, + eagAttributes, + authorityString, + channelLogger, + ticker); ChannelHandler negotiationHandler = negotiator.newHandler(handler); diff --git a/netty/src/main/java/io/grpc/netty/NettyServer.java b/netty/src/main/java/io/grpc/netty/NettyServer.java index 2960604e5b5..1cf67ea25ca 100644 --- a/netty/src/main/java/io/grpc/netty/NettyServer.java +++ b/netty/src/main/java/io/grpc/netty/NettyServer.java @@ -92,6 +92,7 @@ class NettyServer implements InternalServer, InternalWithLogId { private final int flowControlWindow; private final int maxMessageSize; private final int maxHeaderListSize; + private final int softLimitHeaderListSize; private final long keepAliveTimeInNanos; private final long keepAliveTimeoutInNanos; private final long maxConnectionIdleInNanos; @@ -123,9 +124,14 @@ class NettyServer implements InternalServer, InternalWithLogId { ProtocolNegotiator protocolNegotiator, List streamTracerFactories, TransportTracer.Factory transportTracerFactory, - int maxStreamsPerConnection, boolean autoFlowControl, int flowControlWindow, - int maxMessageSize, int maxHeaderListSize, - long keepAliveTimeInNanos, long keepAliveTimeoutInNanos, + int maxStreamsPerConnection, + boolean autoFlowControl, + int flowControlWindow, + int maxMessageSize, + int maxHeaderListSize, + int softLimitHeaderListSize, + long keepAliveTimeInNanos, + long keepAliveTimeoutInNanos, long maxConnectionIdleInNanos, long maxConnectionAgeInNanos, long maxConnectionAgeGraceInNanos, boolean permitKeepAliveWithoutCalls, long permitKeepAliveTimeInNanos, @@ -152,6 +158,7 @@ class NettyServer implements InternalServer, InternalWithLogId { this.flowControlWindow = flowControlWindow; this.maxMessageSize = maxMessageSize; this.maxHeaderListSize = maxHeaderListSize; + this.softLimitHeaderListSize = softLimitHeaderListSize; this.keepAliveTimeInNanos = keepAliveTimeInNanos; this.keepAliveTimeoutInNanos = keepAliveTimeoutInNanos; this.maxConnectionIdleInNanos = maxConnectionIdleInNanos; @@ -243,28 +250,29 @@ public void initChannel(Channel ch) { (long) ((.9D + Math.random() * .2D) * maxConnectionAgeInNanos); } - NettyServerTransport transport = - new NettyServerTransport( - ch, - channelDone, - protocolNegotiator, - streamTracerFactories, - transportTracerFactory.create(), - maxStreamsPerConnection, - autoFlowControl, - flowControlWindow, - maxMessageSize, - maxHeaderListSize, - keepAliveTimeInNanos, - keepAliveTimeoutInNanos, - maxConnectionIdleInNanos, - maxConnectionAgeInNanos, - maxConnectionAgeGraceInNanos, - permitKeepAliveWithoutCalls, - permitKeepAliveTimeInNanos, - maxRstCount, - maxRstPeriodNanos, - eagAttributes); + NettyServerTransport transport = + new NettyServerTransport( + ch, + channelDone, + protocolNegotiator, + streamTracerFactories, + transportTracerFactory.create(), + maxStreamsPerConnection, + autoFlowControl, + flowControlWindow, + maxMessageSize, + maxHeaderListSize, + softLimitHeaderListSize, + keepAliveTimeInNanos, + keepAliveTimeoutInNanos, + maxConnectionIdleInNanos, + maxConnectionAgeInNanos, + maxConnectionAgeGraceInNanos, + permitKeepAliveWithoutCalls, + permitKeepAliveTimeInNanos, + maxRstCount, + maxRstPeriodNanos, + eagAttributes); ServerTransportListener transportListener; // This is to order callbacks on the listener, not to guard access to channel. synchronized (NettyServer.this) { diff --git a/netty/src/main/java/io/grpc/netty/NettyServerBuilder.java b/netty/src/main/java/io/grpc/netty/NettyServerBuilder.java index 3b82b193f61..eb3a6d9b538 100644 --- a/netty/src/main/java/io/grpc/netty/NettyServerBuilder.java +++ b/netty/src/main/java/io/grpc/netty/NettyServerBuilder.java @@ -105,6 +105,7 @@ public final class NettyServerBuilder extends ForwardingServerBuilder 0, "maxInboundMetadataSize must be positive: %s", 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. + * + *

This is cumulative size of the metadata. The precise calculation is + * implementation-dependent, but implementations are encouraged to follow the calculation used + * for + * HTTP/2's + * SETTINGS_MAX_HEADER_LIST_SIZE. 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; } @@ -677,14 +711,33 @@ NettyServer buildTransportServers( this.serverImplBuilder.getExecutorPool()); return new NettyServer( - listenAddresses, channelFactory, channelOptions, childChannelOptions, - bossEventLoopGroupPool, workerEventLoopGroupPool, forceHeapBuffer, negotiator, - streamTracerFactories, transportTracerFactory, maxConcurrentCallsPerConnection, - autoFlowControl, flowControlWindow, maxMessageSize, maxHeaderListSize, - keepAliveTimeInNanos, keepAliveTimeoutInNanos, - maxConnectionIdleInNanos, maxConnectionAgeInNanos, - maxConnectionAgeGraceInNanos, permitKeepAliveWithoutCalls, permitKeepAliveTimeInNanos, - maxRstCount, maxRstPeriodNanos, eagAttributes, this.serverImplBuilder.getChannelz()); + listenAddresses, + channelFactory, + channelOptions, + childChannelOptions, + bossEventLoopGroupPool, + workerEventLoopGroupPool, + forceHeapBuffer, + negotiator, + streamTracerFactories, + transportTracerFactory, + maxConcurrentCallsPerConnection, + autoFlowControl, + flowControlWindow, + maxMessageSize, + maxHeaderListSize, + softLimitHeaderListSize, + keepAliveTimeInNanos, + keepAliveTimeoutInNanos, + maxConnectionIdleInNanos, + maxConnectionAgeInNanos, + maxConnectionAgeGraceInNanos, + permitKeepAliveWithoutCalls, + permitKeepAliveTimeInNanos, + maxRstCount, + maxRstPeriodNanos, + eagAttributes, + this.serverImplBuilder.getChannelz()); } @VisibleForTesting diff --git a/netty/src/main/java/io/grpc/netty/NettyServerHandler.java b/netty/src/main/java/io/grpc/netty/NettyServerHandler.java index a6e855a199d..85a4886b766 100644 --- a/netty/src/main/java/io/grpc/netty/NettyServerHandler.java +++ b/netty/src/main/java/io/grpc/netty/NettyServerHandler.java @@ -152,7 +152,6 @@ class NettyServerHandler extends AbstractNettyHandler { private int rstCount; private long lastRstNanoTime; - static NettyServerHandler newHandler( ServerTransportListener transportListener, ChannelPromise channelUnused, @@ -162,6 +161,7 @@ static NettyServerHandler newHandler( boolean autoFlowControl, int flowControlWindow, int maxHeaderListSize, + int softLimitHeaderListSize, int maxMessageSize, long keepAliveTimeInNanos, long keepAliveTimeoutInNanos, @@ -192,6 +192,7 @@ static NettyServerHandler newHandler( autoFlowControl, flowControlWindow, maxHeaderListSize, + softLimitHeaderListSize, maxMessageSize, keepAliveTimeInNanos, keepAliveTimeoutInNanos, @@ -217,6 +218,7 @@ static NettyServerHandler newHandler( boolean autoFlowControl, int flowControlWindow, int maxHeaderListSize, + int softLimitHeaderListSize, int maxMessageSize, long keepAliveTimeInNanos, long keepAliveTimeoutInNanos, @@ -234,6 +236,9 @@ static NettyServerHandler newHandler( flowControlWindow); Preconditions.checkArgument(maxHeaderListSize > 0, "maxHeaderListSize must be positive: %s", maxHeaderListSize); + Preconditions.checkArgument( + softLimitHeaderListSize > 0, "softLimitHeaderListSize must be positive: %s", + softLimitHeaderListSize); Preconditions.checkArgument(maxMessageSize > 0, "maxMessageSize must be positive: %s", maxMessageSize); @@ -273,7 +278,10 @@ static NettyServerHandler newHandler( transportTracer, decoder, encoder, settings, maxMessageSize, - keepAliveTimeInNanos, keepAliveTimeoutInNanos, + maxHeaderListSize, + softLimitHeaderListSize, + keepAliveTimeInNanos, + keepAliveTimeoutInNanos, maxConnectionIdleInNanos, maxConnectionAgeInNanos, maxConnectionAgeGraceInNanos, keepAliveEnforcer, @@ -293,6 +301,8 @@ private NettyServerHandler( Http2ConnectionEncoder encoder, Http2Settings settings, int maxMessageSize, + int maxHeaderListSize, + int softLimitHeaderListSize, long keepAliveTimeInNanos, long keepAliveTimeoutInNanos, long maxConnectionIdleInNanos, @@ -304,8 +314,17 @@ private NettyServerHandler( long maxRstPeriodNanos, Attributes eagAttributes, Ticker ticker) { - super(channelUnused, decoder, encoder, settings, new ServerChannelLogger(), - autoFlowControl, null, ticker); + super( + channelUnused, + decoder, + encoder, + settings, + new ServerChannelLogger(), + autoFlowControl, + null, + ticker, + maxHeaderListSize, + softLimitHeaderListSize); final MaxConnectionIdleManager maxConnectionIdleManager; if (maxConnectionIdleInNanos == MAX_CONNECTION_IDLE_NANOS_DISABLED) { @@ -470,6 +489,16 @@ private void onHeadersRead(ChannelHandlerContext ctx, int streamId, Http2Headers 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))) { logger.warning(String.format("Expected header TE: %s, but %s is received. This means " + "some intermediate proxy may not support trailers", diff --git a/netty/src/main/java/io/grpc/netty/NettyServerTransport.java b/netty/src/main/java/io/grpc/netty/NettyServerTransport.java index 9511927a09f..758ffeee5b1 100644 --- a/netty/src/main/java/io/grpc/netty/NettyServerTransport.java +++ b/netty/src/main/java/io/grpc/netty/NettyServerTransport.java @@ -70,6 +70,7 @@ class NettyServerTransport implements ServerTransport { private final int flowControlWindow; private final int maxMessageSize; private final int maxHeaderListSize; + private final int softLimitHeaderListSize; private final long keepAliveTimeInNanos; private final long keepAliveTimeoutInNanos; private final long maxConnectionIdleInNanos; @@ -94,6 +95,7 @@ class NettyServerTransport implements ServerTransport { int flowControlWindow, int maxMessageSize, int maxHeaderListSize, + int softLimitHeaderListSize, long keepAliveTimeInNanos, long keepAliveTimeoutInNanos, long maxConnectionIdleInNanos, @@ -115,6 +117,7 @@ class NettyServerTransport implements ServerTransport { this.flowControlWindow = flowControlWindow; this.maxMessageSize = maxMessageSize; this.maxHeaderListSize = maxHeaderListSize; + this.softLimitHeaderListSize = softLimitHeaderListSize; this.keepAliveTimeInNanos = keepAliveTimeInNanos; this.keepAliveTimeoutInNanos = keepAliveTimeoutInNanos; this.maxConnectionIdleInNanos = maxConnectionIdleInNanos; @@ -275,6 +278,7 @@ private NettyServerHandler createHandler( autoFlowControl, flowControlWindow, maxHeaderListSize, + softLimitHeaderListSize, maxMessageSize, keepAliveTimeInNanos, keepAliveTimeoutInNanos, diff --git a/netty/src/main/java/io/grpc/netty/Utils.java b/netty/src/main/java/io/grpc/netty/Utils.java index 96f19aab5e3..ba405637af5 100644 --- a/netty/src/main/java/io/grpc/netty/Utils.java +++ b/netty/src/main/java/io/grpc/netty/Utils.java @@ -23,6 +23,7 @@ import static io.netty.channel.ChannelOption.SO_LINGER; import static io.netty.channel.ChannelOption.SO_TIMEOUT; 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.base.Preconditions; @@ -91,7 +92,9 @@ class Utils { = new DefaultEventLoopGroupResource(1, "grpc-nio-boss-ELG", EventLoopGroupType.NIO); public static final Resource NIO_WORKER_EVENT_LOOP_GROUP = 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 DEFAULT_BOSS_EVENT_LOOP_GROUP; public static final Resource DEFAULT_WORKER_EVENT_LOOP_GROUP; @@ -195,6 +198,61 @@ public static Metadata convertHeaders(Http2Headers 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 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 private static byte[][] convertHeadersToArray(Http2Headers http2Headers) { // The Netty AsciiString class is really just a wrapper around a byte[] and supports diff --git a/netty/src/test/java/io/grpc/netty/NettyClientHandlerTest.java b/netty/src/test/java/io/grpc/netty/NettyClientHandlerTest.java index 73988f773cb..6c5dd6b18bc 100644 --- a/netty/src/test/java/io/grpc/netty/NettyClientHandlerTest.java +++ b/netty/src/test/java/io/grpc/netty/NettyClientHandlerTest.java @@ -47,6 +47,7 @@ import static org.mockito.Mockito.verifyNoMoreInteractions; import com.google.common.base.Stopwatch; +import com.google.common.base.Strings; import com.google.common.base.Supplier; import com.google.common.base.Ticker; import com.google.common.collect.ImmutableList; @@ -122,6 +123,7 @@ public class NettyClientHandlerTest extends NettyHandlerTestBase 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 public void cancelBufferedStreamShouldChangeClientStreamStatus() throws Exception { // Force the stream to be buffered. @@ -946,6 +978,7 @@ public Stopwatch get() { false, flowControlWindow, maxHeaderListSize, + softLimitHeaderListSize, stopwatchSupplier, tooManyPingsRunnable, transportTracer, diff --git a/netty/src/test/java/io/grpc/netty/NettyClientTransportTest.java b/netty/src/test/java/io/grpc/netty/NettyClientTransportTest.java index 7cb269b7d62..b7a3ff13a59 100644 --- a/netty/src/test/java/io/grpc/netty/NettyClientTransportTest.java +++ b/netty/src/test/java/io/grpc/netty/NettyClientTransportTest.java @@ -205,12 +205,30 @@ public void setSoLingerChannelOption() throws IOException { // set SO_LINGER option int soLinger = 123; channelOptions.put(ChannelOption.SO_LINGER, soLinger); - NettyClientTransport transport = new NettyClientTransport( - address, new ReflectiveChannelFactory<>(NioSocketChannel.class), channelOptions, group, - newNegotiator(), false, DEFAULT_WINDOW_SIZE, DEFAULT_MAX_MESSAGE_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()); + NettyClientTransport transport = + new NettyClientTransport( + address, + new ReflectiveChannelFactory<>(NioSocketChannel.class), + channelOptions, + 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); callMeMaybe(transport.start(clientTransportListener)); @@ -454,13 +472,30 @@ private static class CantConstructChannelError extends Error {} public void failingToConstructChannelShouldFailGracefully() throws Exception { address = TestUtils.testServerAddress(new InetSocketAddress(12345)); authority = GrpcUtil.authorityFromHostAndPort(address.getHostString(), address.getPort()); - NettyClientTransport transport = new NettyClientTransport( - address, new ReflectiveChannelFactory<>(CantConstructChannel.class), - new HashMap, Object>(), group, - newNegotiator(), false, DEFAULT_WINDOW_SIZE, DEFAULT_MAX_MESSAGE_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()); + NettyClientTransport transport = + new NettyClientTransport( + address, + new ReflectiveChannelFactory<>(CantConstructChannel.class), + new HashMap, Object>(), + 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, + 1, + false, + authority, + null, + tooManyPingsRunnable, + new TransportTracer(), + Attributes.EMPTY, + new SocketPicker(), + new FakeChannelLogger(), + false, + Ticker.systemTicker()); transports.add(transport); // Should not throw @@ -814,13 +849,30 @@ private NettyClientTransport newTransport(ProtocolNegotiator negotiator, int max if (!enableKeepAlive) { keepAliveTimeNano = KEEPALIVE_TIME_NANOS_DISABLED; } - NettyClientTransport transport = new NettyClientTransport( - address, channelFactory, new HashMap, Object>(), group, - negotiator, false, DEFAULT_WINDOW_SIZE, maxMsgSize, maxHeaderListSize, - keepAliveTimeNano, keepAliveTimeoutNano, - false, authority, userAgent, tooManyPingsRunnable, - new TransportTracer(), eagAttributes, new SocketPicker(), new FakeChannelLogger(), false, - Ticker.systemTicker()); + NettyClientTransport transport = + new NettyClientTransport( + address, + channelFactory, + new HashMap, Object>(), + 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()); transports.add(transport); return transport; } @@ -830,22 +882,35 @@ private void startServer() throws IOException { } private void startServer(int maxStreamsPerConnection, int maxHeaderListSize) throws IOException { - server = new NettyServer( - TestUtils.testServerAddresses(new InetSocketAddress(0)), - new ReflectiveChannelFactory<>(NioServerSocketChannel.class), - new HashMap, Object>(), - new HashMap, Object>(), - new FixedObjectPool<>(group), new FixedObjectPool<>(group), false, negotiator, - Collections.emptyList(), - TransportTracer.getDefaultFactory(), - maxStreamsPerConnection, - false, - DEFAULT_WINDOW_SIZE, DEFAULT_MAX_MESSAGE_SIZE, maxHeaderListSize, - DEFAULT_SERVER_KEEPALIVE_TIME_NANOS, DEFAULT_SERVER_KEEPALIVE_TIMEOUT_NANOS, - MAX_CONNECTION_IDLE_NANOS_DISABLED, - MAX_CONNECTION_AGE_NANOS_DISABLED, MAX_CONNECTION_AGE_GRACE_NANOS_INFINITE, true, 0, - MAX_RST_COUNT_DISABLED, 0, Attributes.EMPTY, - channelz); + server = + new NettyServer( + TestUtils.testServerAddresses(new InetSocketAddress(0)), + new ReflectiveChannelFactory<>(NioServerSocketChannel.class), + new HashMap, Object>(), + new HashMap, Object>(), + new FixedObjectPool<>(group), + new FixedObjectPool<>(group), + false, + negotiator, + Collections.emptyList(), + TransportTracer.getDefaultFactory(), + maxStreamsPerConnection, + false, + DEFAULT_WINDOW_SIZE, + DEFAULT_MAX_MESSAGE_SIZE, + maxHeaderListSize, + maxHeaderListSize, + DEFAULT_SERVER_KEEPALIVE_TIME_NANOS, + DEFAULT_SERVER_KEEPALIVE_TIMEOUT_NANOS, + MAX_CONNECTION_IDLE_NANOS_DISABLED, + MAX_CONNECTION_AGE_NANOS_DISABLED, + MAX_CONNECTION_AGE_GRACE_NANOS_INFINITE, + true, + 0, + MAX_RST_COUNT_DISABLED, + 0, + Attributes.EMPTY, + channelz); server.start(serverListener); address = TestUtils.testServerAddress((InetSocketAddress) server.getListenSocketAddress()); authority = GrpcUtil.authorityFromHostAndPort(address.getHostString(), address.getPort()); diff --git a/netty/src/test/java/io/grpc/netty/NettyServerBuilderTest.java b/netty/src/test/java/io/grpc/netty/NettyServerBuilderTest.java index 6d8192322aa..48af23b78a8 100644 --- a/netty/src/test/java/io/grpc/netty/NettyServerBuilderTest.java +++ b/netty/src/test/java/io/grpc/netty/NettyServerBuilderTest.java @@ -100,6 +100,22 @@ public void failIfMaxInboundMetadataSizeNonPositive() { 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 public void failIfMaxConnectionIdleNegative() { thrown.expect(IllegalArgumentException.class); diff --git a/netty/src/test/java/io/grpc/netty/NettyServerHandlerTest.java b/netty/src/test/java/io/grpc/netty/NettyServerHandlerTest.java index 541490847c0..308079ff62f 100644 --- a/netty/src/test/java/io/grpc/netty/NettyServerHandlerTest.java +++ b/netty/src/test/java/io/grpc/netty/NettyServerHandlerTest.java @@ -141,6 +141,7 @@ public class NettyServerHandlerTest extends NettyHandlerTestBase(NioServerSocketChannel.class), - new HashMap, Object>(), - new HashMap, Object>(), - new FixedObjectPool<>(eventLoop), - new FixedObjectPool<>(eventLoop), - false, - protocolNegotiator, - Collections.emptyList(), - TransportTracer.getDefaultFactory(), - 1, // ignore - false, // ignore - 1, // ignore - 1, // ignore - 1, // ignore - 1, // ignore - 1, 1, // ignore - 1, 1, // ignore - true, 0, // ignore - 0, 0, // ignore - Attributes.EMPTY, - channelz); + NettyServer ns = + new NettyServer( + Arrays.asList(addr), + new ReflectiveChannelFactory<>(NioServerSocketChannel.class), + new HashMap, Object>(), + new HashMap, Object>(), + new FixedObjectPool<>(eventLoop), + new FixedObjectPool<>(eventLoop), + false, + protocolNegotiator, + Collections.emptyList(), + TransportTracer.getDefaultFactory(), + 1, // ignore + false, // ignore + 1, // ignore + 1, // ignore + 1, // ignore + 1, // ignore + 1, // ignore + 1, + 1, // ignore + 1, + 1, // ignore + true, + 0, // ignore + 0, + 0, // ignore + Attributes.EMPTY, + channelz); final SettableFuture serverShutdownCalled = SettableFuture.create(); ns.start(new ServerListener() { @Override @@ -184,29 +190,35 @@ public void multiPortStartStopGet() throws Exception { InetSocketAddress addr1 = new InetSocketAddress(0); InetSocketAddress addr2 = new InetSocketAddress(0); - NettyServer ns = new NettyServer( - Arrays.asList(addr1, addr2), - new ReflectiveChannelFactory<>(NioServerSocketChannel.class), - new HashMap, Object>(), - new HashMap, Object>(), - new FixedObjectPool<>(eventLoop), - new FixedObjectPool<>(eventLoop), - false, - ProtocolNegotiators.plaintext(), - Collections.emptyList(), - TransportTracer.getDefaultFactory(), - 1, // ignore - false, // ignore - 1, // ignore - 1, // ignore - 1, // ignore - 1, // ignore - 1, 1, // ignore - 1, 1, // ignore - true, 0, // ignore - 0, 0, // ignore - Attributes.EMPTY, - channelz); + NettyServer ns = + new NettyServer( + Arrays.asList(addr1, addr2), + new ReflectiveChannelFactory<>(NioServerSocketChannel.class), + new HashMap, Object>(), + new HashMap, Object>(), + new FixedObjectPool<>(eventLoop), + new FixedObjectPool<>(eventLoop), + false, + ProtocolNegotiators.plaintext(), + Collections.emptyList(), + TransportTracer.getDefaultFactory(), + 1, // ignore + false, // ignore + 1, // ignore + 1, // ignore + 1, // ignore + 1, // ignore + 1, // ignore + 1, + 1, // ignore + 1, + 1, // ignore + true, + 0, // ignore + 0, + 0, // ignore + Attributes.EMPTY, + channelz); final SettableFuture shutdownCompleted = SettableFuture.create(); ns.start(new ServerListener() { @Override @@ -258,29 +270,35 @@ public void multiPortConnections() throws Exception { InetSocketAddress addr2 = new InetSocketAddress(0); final CountDownLatch allPortsConnectedCountDown = new CountDownLatch(2); - NettyServer ns = new NettyServer( - Arrays.asList(addr1, addr2), - new ReflectiveChannelFactory<>(NioServerSocketChannel.class), - new HashMap, Object>(), - new HashMap, Object>(), - new FixedObjectPool<>(eventLoop), - new FixedObjectPool<>(eventLoop), - false, - ProtocolNegotiators.plaintext(), - Collections.emptyList(), - TransportTracer.getDefaultFactory(), - 1, // ignore - false, // ignore - 1, // ignore - 1, // ignore - 1, // ignore - 1, // ignore - 1, 1, // ignore - 1, 1, // ignore - true, 0, // ignore - 0, 0, // ignore - Attributes.EMPTY, - channelz); + NettyServer ns = + new NettyServer( + Arrays.asList(addr1, addr2), + new ReflectiveChannelFactory<>(NioServerSocketChannel.class), + new HashMap, Object>(), + new HashMap, Object>(), + new FixedObjectPool<>(eventLoop), + new FixedObjectPool<>(eventLoop), + false, + ProtocolNegotiators.plaintext(), + Collections.emptyList(), + TransportTracer.getDefaultFactory(), + 1, // ignore + false, // ignore + 1, // ignore + 1, // ignore + 1, // ignore + 1, // ignore + 1, // ignore + 1, + 1, // ignore + 1, + 1, // ignore + true, + 0, // ignore + 0, + 0, // ignore + Attributes.EMPTY, + channelz); final SettableFuture shutdownCompleted = SettableFuture.create(); ns.start(new ServerListener() { @Override @@ -320,29 +338,35 @@ public void run() {} public void getPort_notStarted() { InetSocketAddress addr = new InetSocketAddress(0); List addresses = Collections.singletonList(addr); - NettyServer ns = new NettyServer( - addresses, - new ReflectiveChannelFactory<>(NioServerSocketChannel.class), - new HashMap, Object>(), - new HashMap, Object>(), - new FixedObjectPool<>(eventLoop), - new FixedObjectPool<>(eventLoop), - false, - ProtocolNegotiators.plaintext(), - Collections.emptyList(), - TransportTracer.getDefaultFactory(), - 1, // ignore - false, // ignore - 1, // ignore - 1, // ignore - 1, // ignore - 1, // ignore - 1, 1, // ignore - 1, 1, // ignore - true, 0, // ignore - 0, 0, // ignore - Attributes.EMPTY, - channelz); + NettyServer ns = + new NettyServer( + addresses, + new ReflectiveChannelFactory<>(NioServerSocketChannel.class), + new HashMap, Object>(), + new HashMap, Object>(), + new FixedObjectPool<>(eventLoop), + new FixedObjectPool<>(eventLoop), + false, + ProtocolNegotiators.plaintext(), + Collections.emptyList(), + TransportTracer.getDefaultFactory(), + 1, // ignore + false, // ignore + 1, // ignore + 1, // ignore + 1, // ignore + 1, // ignore + 1, // ignore + 1, + 1, // ignore + 1, + 1, // ignore + true, + 0, // ignore + 0, + 0, // ignore + Attributes.EMPTY, + channelz); assertThat(ns.getListenSocketAddress()).isEqualTo(addr); assertThat(ns.getListenSocketAddresses()).isEqualTo(addresses); @@ -395,29 +419,35 @@ class TestProtocolNegotiator implements ProtocolNegotiator { .build(); TestProtocolNegotiator protocolNegotiator = new TestProtocolNegotiator(); InetSocketAddress addr = new InetSocketAddress(0); - NettyServer ns = new NettyServer( - Arrays.asList(addr), - new ReflectiveChannelFactory<>(NioServerSocketChannel.class), - new HashMap, Object>(), - childChannelOptions, - new FixedObjectPool<>(eventLoop), - new FixedObjectPool<>(eventLoop), - false, - protocolNegotiator, - Collections.emptyList(), - TransportTracer.getDefaultFactory(), - 1, // ignore - false, // ignore - 1, // ignore - 1, // ignore - 1, // ignore - 1, // ignore - 1, 1, // ignore - 1, 1, // ignore - true, 0, // ignore - 0, 0, // ignore - eagAttributes, - channelz); + NettyServer ns = + new NettyServer( + Arrays.asList(addr), + new ReflectiveChannelFactory<>(NioServerSocketChannel.class), + new HashMap, Object>(), + childChannelOptions, + new FixedObjectPool<>(eventLoop), + new FixedObjectPool<>(eventLoop), + false, + protocolNegotiator, + Collections.emptyList(), + TransportTracer.getDefaultFactory(), + 1, // ignore + false, // ignore + 1, // ignore + 1, // ignore + 1, // ignore + 1, // ignore + 1, // ignore + 1, + 1, // ignore + 1, + 1, // ignore + true, + 0, // ignore + 0, + 0, // ignore + eagAttributes, + channelz); ns.start(new ServerListener() { @Override public ServerTransportListener transportCreated(ServerTransport transport) { @@ -443,29 +473,35 @@ public void serverShutdown() {} @Test public void channelzListenSocket() throws Exception { InetSocketAddress addr = new InetSocketAddress(0); - NettyServer ns = new NettyServer( - Arrays.asList(addr), - new ReflectiveChannelFactory<>(NioServerSocketChannel.class), - new HashMap, Object>(), - new HashMap, Object>(), - new FixedObjectPool<>(eventLoop), - new FixedObjectPool<>(eventLoop), - false, - ProtocolNegotiators.plaintext(), - Collections.emptyList(), - TransportTracer.getDefaultFactory(), - 1, // ignore - false, // ignore - 1, // ignore - 1, // ignore - 1, // ignore - 1, // ignore - 1, 1, // ignore - 1, 1, // ignore - true, 0, // ignore - 0, 0, // ignore - Attributes.EMPTY, - channelz); + NettyServer ns = + new NettyServer( + Arrays.asList(addr), + new ReflectiveChannelFactory<>(NioServerSocketChannel.class), + new HashMap, Object>(), + new HashMap, Object>(), + new FixedObjectPool<>(eventLoop), + new FixedObjectPool<>(eventLoop), + false, + ProtocolNegotiators.plaintext(), + Collections.emptyList(), + TransportTracer.getDefaultFactory(), + 1, // ignore + false, // ignore + 1, // ignore + 1, // ignore + 1, // ignore + 1, // ignore + 1, // ignore + 1, + 1, // ignore + 1, + 1, // ignore + true, + 0, // ignore + 0, + 0, // ignore + Attributes.EMPTY, + channelz); final SettableFuture shutdownCompleted = SettableFuture.create(); ns.start(new ServerListener() { @Override @@ -603,10 +639,15 @@ private NettyServer getServer(List addr, EventLoopGroup ev) { 1, // ignore 1, // ignore 1, // ignore - 1, 1, // ignore - 1, 1, // ignore - true, 0, // ignore - 0, 0, // ignore + 1, // ignore + 1, + 1, // ignore + 1, + 1, // ignore + true, + 0, // ignore + 0, + 0, // ignore Attributes.EMPTY, channelz); }