mirror of https://github.com/grpc/grpc-java.git
Make the header list size limit configurable on both client and server side.
This commit is contained in:
parent
a4f319f0c3
commit
750b1977ca
|
|
@ -145,6 +145,11 @@ public final class GrpcUtil {
|
||||||
*/
|
*/
|
||||||
public static final int DEFAULT_MAX_MESSAGE_SIZE = 100 * 1024 * 1024;
|
public static final int DEFAULT_MAX_MESSAGE_SIZE = 100 * 1024 * 1024;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The default maximum size (in bytes) for inbound header/trailer.
|
||||||
|
*/
|
||||||
|
public static final int DEFAULT_MAX_HEADER_LIST_SIZE = 8192;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The set of valid status codes for client cancellation.
|
* The set of valid status codes for client cancellation.
|
||||||
*/
|
*/
|
||||||
|
|
|
||||||
|
|
@ -71,6 +71,7 @@ public class NettyChannelBuilder extends AbstractManagedChannelImplBuilder<Netty
|
||||||
private SslContext sslContext;
|
private SslContext sslContext;
|
||||||
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;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Creates a new builder with the given server address. This factory method is primarily intended
|
* Creates a new builder with the given server address. This factory method is primarily intended
|
||||||
|
|
@ -160,14 +161,14 @@ public class NettyChannelBuilder extends AbstractManagedChannelImplBuilder<Netty
|
||||||
* is {@link #DEFAULT_FLOW_CONTROL_WINDOW}).
|
* is {@link #DEFAULT_FLOW_CONTROL_WINDOW}).
|
||||||
*/
|
*/
|
||||||
public final NettyChannelBuilder flowControlWindow(int flowControlWindow) {
|
public final NettyChannelBuilder flowControlWindow(int flowControlWindow) {
|
||||||
Preconditions.checkArgument(flowControlWindow > 0, "flowControlWindow must be positive");
|
checkArgument(flowControlWindow > 0, "flowControlWindow must be positive");
|
||||||
this.flowControlWindow = flowControlWindow;
|
this.flowControlWindow = flowControlWindow;
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Sets the maximum message size allowed to be received on the channel. If not called,
|
* Sets the maximum message size allowed to be received on the channel. If not called,
|
||||||
* defaults to {@link io.grpc.internal.GrpcUtil#DEFAULT_MAX_MESSAGE_SIZE}.
|
* defaults to {@link GrpcUtil#DEFAULT_MAX_MESSAGE_SIZE}.
|
||||||
*/
|
*/
|
||||||
public final NettyChannelBuilder maxMessageSize(int maxMessageSize) {
|
public final NettyChannelBuilder maxMessageSize(int maxMessageSize) {
|
||||||
checkArgument(maxMessageSize >= 0, "maxMessageSize must be >= 0");
|
checkArgument(maxMessageSize >= 0, "maxMessageSize must be >= 0");
|
||||||
|
|
@ -175,6 +176,16 @@ public class NettyChannelBuilder extends AbstractManagedChannelImplBuilder<Netty
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets the maximum size of header list allowed to be received on the channel. If not called,
|
||||||
|
* defaults to {@link GrpcUtil#DEFAULT_MAX_HEADER_LIST_SIZE}.
|
||||||
|
*/
|
||||||
|
public final NettyChannelBuilder maxHeaderListSize(int maxHeaderListSize) {
|
||||||
|
checkArgument(maxHeaderListSize > 0, "maxHeaderListSize must be > 0");
|
||||||
|
this.maxHeaderListSize = maxHeaderListSize;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Equivalent to using {@link #negotiationType(NegotiationType)} with {@code PLAINTEXT} or
|
* Equivalent to using {@link #negotiationType(NegotiationType)} with {@code PLAINTEXT} or
|
||||||
* {@code PLAINTEXT_UPGRADE}.
|
* {@code PLAINTEXT_UPGRADE}.
|
||||||
|
|
@ -192,7 +203,7 @@ public class NettyChannelBuilder extends AbstractManagedChannelImplBuilder<Netty
|
||||||
@Override
|
@Override
|
||||||
protected ClientTransportFactory buildTransportFactory() {
|
protected ClientTransportFactory buildTransportFactory() {
|
||||||
return new NettyTransportFactory(channelType, negotiationType, sslContext,
|
return new NettyTransportFactory(channelType, negotiationType, sslContext,
|
||||||
eventLoopGroup, flowControlWindow, maxMessageSize);
|
eventLoopGroup, flowControlWindow, maxMessageSize, maxHeaderListSize);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|
@ -246,18 +257,21 @@ public class NettyChannelBuilder extends AbstractManagedChannelImplBuilder<Netty
|
||||||
private final boolean usingSharedGroup;
|
private final boolean usingSharedGroup;
|
||||||
private final int flowControlWindow;
|
private final int flowControlWindow;
|
||||||
private final int maxMessageSize;
|
private final int maxMessageSize;
|
||||||
|
private final int maxHeaderListSize;
|
||||||
|
|
||||||
private NettyTransportFactory(Class<? extends Channel> channelType,
|
private NettyTransportFactory(Class<? extends Channel> channelType,
|
||||||
NegotiationType negotiationType,
|
NegotiationType negotiationType,
|
||||||
SslContext sslContext,
|
SslContext sslContext,
|
||||||
EventLoopGroup group,
|
EventLoopGroup group,
|
||||||
int flowControlWindow,
|
int flowControlWindow,
|
||||||
int maxMessageSize) {
|
int maxMessageSize,
|
||||||
|
int maxHeaderListSize) {
|
||||||
this.channelType = channelType;
|
this.channelType = channelType;
|
||||||
this.negotiationType = negotiationType;
|
this.negotiationType = negotiationType;
|
||||||
this.sslContext = sslContext;
|
this.sslContext = sslContext;
|
||||||
this.flowControlWindow = flowControlWindow;
|
this.flowControlWindow = flowControlWindow;
|
||||||
this.maxMessageSize = maxMessageSize;
|
this.maxMessageSize = maxMessageSize;
|
||||||
|
this.maxHeaderListSize = maxHeaderListSize;
|
||||||
usingSharedGroup = group == null;
|
usingSharedGroup = group == null;
|
||||||
if (usingSharedGroup) {
|
if (usingSharedGroup) {
|
||||||
// The group was unspecified, using the shared group.
|
// The group was unspecified, using the shared group.
|
||||||
|
|
@ -272,7 +286,7 @@ public class NettyChannelBuilder extends AbstractManagedChannelImplBuilder<Netty
|
||||||
ProtocolNegotiator negotiator =
|
ProtocolNegotiator negotiator =
|
||||||
createProtocolNegotiator(authority, negotiationType, sslContext);
|
createProtocolNegotiator(authority, negotiationType, sslContext);
|
||||||
return new NettyClientTransport(serverAddress, channelType, group, negotiator,
|
return new NettyClientTransport(serverAddress, channelType, group, negotiator,
|
||||||
flowControlWindow, maxMessageSize, authority);
|
flowControlWindow, maxMessageSize, maxHeaderListSize, authority);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|
|
||||||
|
|
@ -54,11 +54,14 @@ import io.netty.handler.codec.http2.DefaultHttp2Connection;
|
||||||
import io.netty.handler.codec.http2.DefaultHttp2ConnectionEncoder;
|
import io.netty.handler.codec.http2.DefaultHttp2ConnectionEncoder;
|
||||||
import io.netty.handler.codec.http2.DefaultHttp2FrameReader;
|
import io.netty.handler.codec.http2.DefaultHttp2FrameReader;
|
||||||
import io.netty.handler.codec.http2.DefaultHttp2FrameWriter;
|
import io.netty.handler.codec.http2.DefaultHttp2FrameWriter;
|
||||||
|
import io.netty.handler.codec.http2.DefaultHttp2HeadersDecoder;
|
||||||
|
import io.netty.handler.codec.http2.Http2CodecUtil;
|
||||||
import io.netty.handler.codec.http2.Http2Connection;
|
import io.netty.handler.codec.http2.Http2Connection;
|
||||||
import io.netty.handler.codec.http2.Http2FrameLogger;
|
import io.netty.handler.codec.http2.Http2FrameLogger;
|
||||||
import io.netty.handler.codec.http2.Http2FrameReader;
|
import io.netty.handler.codec.http2.Http2FrameReader;
|
||||||
import io.netty.handler.codec.http2.Http2FrameWriter;
|
import io.netty.handler.codec.http2.Http2FrameWriter;
|
||||||
import io.netty.handler.codec.http2.Http2Headers;
|
import io.netty.handler.codec.http2.Http2Headers;
|
||||||
|
import io.netty.handler.codec.http2.Http2HeadersDecoder;
|
||||||
import io.netty.handler.codec.http2.Http2InboundFrameLogger;
|
import io.netty.handler.codec.http2.Http2InboundFrameLogger;
|
||||||
import io.netty.handler.codec.http2.Http2OutboundFrameLogger;
|
import io.netty.handler.codec.http2.Http2OutboundFrameLogger;
|
||||||
import io.netty.handler.logging.LogLevel;
|
import io.netty.handler.logging.LogLevel;
|
||||||
|
|
@ -81,6 +84,7 @@ class NettyClientTransport implements ClientTransport {
|
||||||
private final AsciiString authority;
|
private final AsciiString authority;
|
||||||
private final int flowControlWindow;
|
private final int flowControlWindow;
|
||||||
private final int maxMessageSize;
|
private final int maxMessageSize;
|
||||||
|
private final int maxHeaderListSize;
|
||||||
// We should not send on the channel until negotiation completes. This is a hard requirement
|
// We should not send on the channel until negotiation completes. This is a hard requirement
|
||||||
// by SslHandler but is appropriate for HTTP/1.1 Upgrade as well.
|
// by SslHandler but is appropriate for HTTP/1.1 Upgrade as well.
|
||||||
private Channel channel;
|
private Channel channel;
|
||||||
|
|
@ -94,13 +98,15 @@ class NettyClientTransport implements ClientTransport {
|
||||||
|
|
||||||
NettyClientTransport(SocketAddress address, Class<? extends Channel> channelType,
|
NettyClientTransport(SocketAddress address, Class<? extends Channel> channelType,
|
||||||
EventLoopGroup group, ProtocolNegotiator negotiator,
|
EventLoopGroup group, ProtocolNegotiator negotiator,
|
||||||
int flowControlWindow, int maxMessageSize, String authority) {
|
int flowControlWindow, int maxMessageSize, int maxHeaderListSize,
|
||||||
|
String authority) {
|
||||||
Preconditions.checkNotNull(negotiator, "negotiator");
|
Preconditions.checkNotNull(negotiator, "negotiator");
|
||||||
this.address = Preconditions.checkNotNull(address, "address");
|
this.address = Preconditions.checkNotNull(address, "address");
|
||||||
this.group = Preconditions.checkNotNull(group, "group");
|
this.group = Preconditions.checkNotNull(group, "group");
|
||||||
this.channelType = Preconditions.checkNotNull(channelType, "channelType");
|
this.channelType = Preconditions.checkNotNull(channelType, "channelType");
|
||||||
this.flowControlWindow = flowControlWindow;
|
this.flowControlWindow = flowControlWindow;
|
||||||
this.maxMessageSize = maxMessageSize;
|
this.maxMessageSize = maxMessageSize;
|
||||||
|
this.maxHeaderListSize = maxHeaderListSize;
|
||||||
this.authority = new AsciiString(authority);
|
this.authority = new AsciiString(authority);
|
||||||
|
|
||||||
handler = newHandler();
|
handler = newHandler();
|
||||||
|
|
@ -244,7 +250,9 @@ class NettyClientTransport implements ClientTransport {
|
||||||
|
|
||||||
private NettyClientHandler newHandler() {
|
private NettyClientHandler newHandler() {
|
||||||
Http2Connection connection = new DefaultHttp2Connection(false);
|
Http2Connection connection = new DefaultHttp2Connection(false);
|
||||||
Http2FrameReader frameReader = new DefaultHttp2FrameReader();
|
Http2HeadersDecoder headersDecoder =
|
||||||
|
new DefaultHttp2HeadersDecoder(maxHeaderListSize, Http2CodecUtil.DEFAULT_HEADER_TABLE_SIZE);
|
||||||
|
Http2FrameReader frameReader = new DefaultHttp2FrameReader(headersDecoder);
|
||||||
Http2FrameWriter frameWriter = new DefaultHttp2FrameWriter();
|
Http2FrameWriter frameWriter = new DefaultHttp2FrameWriter();
|
||||||
|
|
||||||
Http2FrameLogger frameLogger = new Http2FrameLogger(LogLevel.DEBUG, getClass());
|
Http2FrameLogger frameLogger = new Http2FrameLogger(LogLevel.DEBUG, getClass());
|
||||||
|
|
|
||||||
|
|
@ -76,12 +76,13 @@ public class NettyServer implements Server {
|
||||||
private Channel channel;
|
private Channel channel;
|
||||||
private final int flowControlWindow;
|
private final int flowControlWindow;
|
||||||
private final int maxMessageSize;
|
private final int maxMessageSize;
|
||||||
|
private final int maxHeaderListSize;
|
||||||
private final ReferenceCounted eventLoopReferenceCounter = new EventLoopReferenceCounter();
|
private final ReferenceCounted eventLoopReferenceCounter = new EventLoopReferenceCounter();
|
||||||
|
|
||||||
NettyServer(SocketAddress address, Class<? extends ServerChannel> channelType,
|
NettyServer(SocketAddress address, Class<? extends ServerChannel> channelType,
|
||||||
@Nullable EventLoopGroup bossGroup, @Nullable EventLoopGroup workerGroup,
|
@Nullable EventLoopGroup bossGroup, @Nullable EventLoopGroup workerGroup,
|
||||||
@Nullable SslContext sslContext, int maxStreamsPerConnection, int flowControlWindow,
|
@Nullable SslContext sslContext, int maxStreamsPerConnection, int flowControlWindow,
|
||||||
int maxMessageSize) {
|
int maxMessageSize, int maxHeaderListSize) {
|
||||||
this.address = address;
|
this.address = address;
|
||||||
this.channelType = checkNotNull(channelType, "channelType");
|
this.channelType = checkNotNull(channelType, "channelType");
|
||||||
this.bossGroup = bossGroup;
|
this.bossGroup = bossGroup;
|
||||||
|
|
@ -92,6 +93,7 @@ public class NettyServer implements Server {
|
||||||
this.maxStreamsPerConnection = maxStreamsPerConnection;
|
this.maxStreamsPerConnection = maxStreamsPerConnection;
|
||||||
this.flowControlWindow = flowControlWindow;
|
this.flowControlWindow = flowControlWindow;
|
||||||
this.maxMessageSize = maxMessageSize;
|
this.maxMessageSize = maxMessageSize;
|
||||||
|
this.maxHeaderListSize = maxHeaderListSize;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|
@ -119,7 +121,7 @@ public class NettyServer implements Server {
|
||||||
});
|
});
|
||||||
NettyServerTransport transport
|
NettyServerTransport transport
|
||||||
= new NettyServerTransport(ch, sslContext, maxStreamsPerConnection, flowControlWindow,
|
= new NettyServerTransport(ch, sslContext, maxStreamsPerConnection, flowControlWindow,
|
||||||
maxMessageSize);
|
maxMessageSize, maxHeaderListSize);
|
||||||
transport.start(listener.transportCreated(transport));
|
transport.start(listener.transportCreated(transport));
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
|
||||||
|
|
@ -39,6 +39,7 @@ import com.google.common.base.Preconditions;
|
||||||
import io.grpc.ExperimentalApi;
|
import io.grpc.ExperimentalApi;
|
||||||
import io.grpc.HandlerRegistry;
|
import io.grpc.HandlerRegistry;
|
||||||
import io.grpc.internal.AbstractServerImplBuilder;
|
import io.grpc.internal.AbstractServerImplBuilder;
|
||||||
|
import io.grpc.internal.GrpcUtil;
|
||||||
import io.netty.channel.EventLoopGroup;
|
import io.netty.channel.EventLoopGroup;
|
||||||
import io.netty.channel.ServerChannel;
|
import io.netty.channel.ServerChannel;
|
||||||
import io.netty.channel.socket.nio.NioServerSocketChannel;
|
import io.netty.channel.socket.nio.NioServerSocketChannel;
|
||||||
|
|
@ -68,6 +69,7 @@ public final class NettyServerBuilder extends AbstractServerImplBuilder<NettySer
|
||||||
private int maxConcurrentCallsPerConnection = Integer.MAX_VALUE;
|
private int maxConcurrentCallsPerConnection = Integer.MAX_VALUE;
|
||||||
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;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Creates a server builder that will bind to the given port.
|
* Creates a server builder that will bind to the given port.
|
||||||
|
|
@ -182,7 +184,7 @@ public final class NettyServerBuilder extends AbstractServerImplBuilder<NettySer
|
||||||
* limit.
|
* limit.
|
||||||
*/
|
*/
|
||||||
public NettyServerBuilder maxConcurrentCallsPerConnection(int maxCalls) {
|
public NettyServerBuilder maxConcurrentCallsPerConnection(int maxCalls) {
|
||||||
Preconditions.checkArgument(maxCalls > 0, "max must be positive: %s", maxCalls);
|
checkArgument(maxCalls > 0, "max must be positive: %s", maxCalls);
|
||||||
this.maxConcurrentCallsPerConnection = maxCalls;
|
this.maxConcurrentCallsPerConnection = maxCalls;
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
@ -192,7 +194,7 @@ public final class NettyServerBuilder extends AbstractServerImplBuilder<NettySer
|
||||||
* is {@link #DEFAULT_FLOW_CONTROL_WINDOW}).
|
* is {@link #DEFAULT_FLOW_CONTROL_WINDOW}).
|
||||||
*/
|
*/
|
||||||
public NettyServerBuilder flowControlWindow(int flowControlWindow) {
|
public NettyServerBuilder flowControlWindow(int flowControlWindow) {
|
||||||
Preconditions.checkArgument(flowControlWindow > 0, "flowControlWindow must be positive");
|
checkArgument(flowControlWindow > 0, "flowControlWindow must be positive");
|
||||||
this.flowControlWindow = flowControlWindow;
|
this.flowControlWindow = flowControlWindow;
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
@ -207,11 +209,21 @@ public final class NettyServerBuilder extends AbstractServerImplBuilder<NettySer
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets the maximum size of header list allowed to be received on the server. If not called,
|
||||||
|
* defaults to {@link GrpcUtil#DEFAULT_MAX_HEADER_LIST_SIZE}.
|
||||||
|
*/
|
||||||
|
public NettyServerBuilder maxHeaderListSize(int maxHeaderListSize) {
|
||||||
|
checkArgument(maxHeaderListSize > 0, "maxHeaderListSize must be > 0");
|
||||||
|
this.maxHeaderListSize = maxHeaderListSize;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected NettyServer buildTransportServer() {
|
protected NettyServer buildTransportServer() {
|
||||||
return new NettyServer(address, channelType, bossEventLoopGroup,
|
return new NettyServer(address, channelType, bossEventLoopGroup,
|
||||||
workerEventLoopGroup, sslContext, maxConcurrentCallsPerConnection, flowControlWindow,
|
workerEventLoopGroup, sslContext, maxConcurrentCallsPerConnection, flowControlWindow,
|
||||||
maxMessageSize);
|
maxMessageSize, maxHeaderListSize);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|
|
||||||
|
|
@ -42,10 +42,13 @@ import io.netty.channel.ChannelHandler;
|
||||||
import io.netty.handler.codec.http2.DefaultHttp2Connection;
|
import io.netty.handler.codec.http2.DefaultHttp2Connection;
|
||||||
import io.netty.handler.codec.http2.DefaultHttp2FrameReader;
|
import io.netty.handler.codec.http2.DefaultHttp2FrameReader;
|
||||||
import io.netty.handler.codec.http2.DefaultHttp2FrameWriter;
|
import io.netty.handler.codec.http2.DefaultHttp2FrameWriter;
|
||||||
|
import io.netty.handler.codec.http2.DefaultHttp2HeadersDecoder;
|
||||||
|
import io.netty.handler.codec.http2.Http2CodecUtil;
|
||||||
import io.netty.handler.codec.http2.Http2Connection;
|
import io.netty.handler.codec.http2.Http2Connection;
|
||||||
import io.netty.handler.codec.http2.Http2FrameLogger;
|
import io.netty.handler.codec.http2.Http2FrameLogger;
|
||||||
import io.netty.handler.codec.http2.Http2FrameReader;
|
import io.netty.handler.codec.http2.Http2FrameReader;
|
||||||
import io.netty.handler.codec.http2.Http2FrameWriter;
|
import io.netty.handler.codec.http2.Http2FrameWriter;
|
||||||
|
import io.netty.handler.codec.http2.Http2HeadersDecoder;
|
||||||
import io.netty.handler.codec.http2.Http2InboundFrameLogger;
|
import io.netty.handler.codec.http2.Http2InboundFrameLogger;
|
||||||
import io.netty.handler.codec.http2.Http2OutboundFrameLogger;
|
import io.netty.handler.codec.http2.Http2OutboundFrameLogger;
|
||||||
import io.netty.handler.logging.LogLevel;
|
import io.netty.handler.logging.LogLevel;
|
||||||
|
|
@ -70,14 +73,16 @@ class NettyServerTransport implements ServerTransport {
|
||||||
private boolean terminated;
|
private boolean terminated;
|
||||||
private final int flowControlWindow;
|
private final int flowControlWindow;
|
||||||
private final int maxMessageSize;
|
private final int maxMessageSize;
|
||||||
|
private final int maxHeaderListSize;
|
||||||
|
|
||||||
NettyServerTransport(Channel channel, @Nullable SslContext sslContext, int maxStreams,
|
NettyServerTransport(Channel channel, @Nullable SslContext sslContext, int maxStreams,
|
||||||
int flowControlWindow, int maxMessageSize) {
|
int flowControlWindow, int maxMessageSize, int maxHeaderListSize) {
|
||||||
this.channel = Preconditions.checkNotNull(channel, "channel");
|
this.channel = Preconditions.checkNotNull(channel, "channel");
|
||||||
this.sslContext = sslContext;
|
this.sslContext = sslContext;
|
||||||
this.maxStreams = maxStreams;
|
this.maxStreams = maxStreams;
|
||||||
this.flowControlWindow = flowControlWindow;
|
this.flowControlWindow = flowControlWindow;
|
||||||
this.maxMessageSize = maxMessageSize;
|
this.maxMessageSize = maxMessageSize;
|
||||||
|
this.maxHeaderListSize = maxHeaderListSize;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void start(ServerTransportListener listener) {
|
public void start(ServerTransportListener listener) {
|
||||||
|
|
@ -133,8 +138,10 @@ class NettyServerTransport implements ServerTransport {
|
||||||
private NettyServerHandler createHandler(ServerTransportListener transportListener) {
|
private NettyServerHandler createHandler(ServerTransportListener transportListener) {
|
||||||
Http2Connection connection = new DefaultHttp2Connection(true);
|
Http2Connection connection = new DefaultHttp2Connection(true);
|
||||||
Http2FrameLogger frameLogger = new Http2FrameLogger(LogLevel.DEBUG, getClass());
|
Http2FrameLogger frameLogger = new Http2FrameLogger(LogLevel.DEBUG, getClass());
|
||||||
Http2FrameReader frameReader =
|
Http2HeadersDecoder headersDecoder =
|
||||||
new Http2InboundFrameLogger(new DefaultHttp2FrameReader(), frameLogger);
|
new DefaultHttp2HeadersDecoder(maxHeaderListSize, Http2CodecUtil.DEFAULT_HEADER_TABLE_SIZE);
|
||||||
|
Http2FrameReader frameReader = new Http2InboundFrameLogger(
|
||||||
|
new DefaultHttp2FrameReader(headersDecoder), frameLogger);
|
||||||
Http2FrameWriter frameWriter =
|
Http2FrameWriter frameWriter =
|
||||||
new Http2OutboundFrameLogger(new DefaultHttp2FrameWriter(), frameLogger);
|
new Http2OutboundFrameLogger(new DefaultHttp2FrameWriter(), frameLogger);
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -61,6 +61,7 @@ import io.grpc.testing.TestUtils;
|
||||||
import io.netty.channel.nio.NioEventLoopGroup;
|
import io.netty.channel.nio.NioEventLoopGroup;
|
||||||
import io.netty.channel.socket.nio.NioServerSocketChannel;
|
import io.netty.channel.socket.nio.NioServerSocketChannel;
|
||||||
import io.netty.channel.socket.nio.NioSocketChannel;
|
import io.netty.channel.socket.nio.NioSocketChannel;
|
||||||
|
import io.netty.handler.codec.http2.Http2Exception;
|
||||||
import io.netty.handler.ssl.SslContext;
|
import io.netty.handler.ssl.SslContext;
|
||||||
import io.netty.handler.ssl.SupportedCipherSuiteFilter;
|
import io.netty.handler.ssl.SupportedCipherSuiteFilter;
|
||||||
|
|
||||||
|
|
@ -161,7 +162,8 @@ public class NettyClientTransportTest {
|
||||||
public void maxMessageSizeShouldBeEnforced() throws Throwable {
|
public void maxMessageSizeShouldBeEnforced() throws Throwable {
|
||||||
startServer();
|
startServer();
|
||||||
// Allow the response payloads of up to 1 byte.
|
// Allow the response payloads of up to 1 byte.
|
||||||
NettyClientTransport transport = newTransport(newNegotiator(), 1);
|
NettyClientTransport transport = newTransport(newNegotiator(),
|
||||||
|
1, GrpcUtil.DEFAULT_MAX_HEADER_LIST_SIZE);
|
||||||
transport.start(clientTransportListener);
|
transport.start(clientTransportListener);
|
||||||
|
|
||||||
try {
|
try {
|
||||||
|
|
@ -205,7 +207,7 @@ public class NettyClientTransportTest {
|
||||||
@Test
|
@Test
|
||||||
public void bufferedStreamsShouldBeClosedWhenConnectionTerminates() throws Exception {
|
public void bufferedStreamsShouldBeClosedWhenConnectionTerminates() throws Exception {
|
||||||
// Only allow a single stream active at a time.
|
// Only allow a single stream active at a time.
|
||||||
startServer(1);
|
startServer(1, GrpcUtil.DEFAULT_MAX_HEADER_LIST_SIZE);
|
||||||
|
|
||||||
NettyClientTransport transport = newTransport(newNegotiator());
|
NettyClientTransport transport = newTransport(newNegotiator());
|
||||||
transport.start(clientTransportListener);
|
transport.start(clientTransportListener);
|
||||||
|
|
@ -234,6 +236,51 @@ public class NettyClientTransportTest {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void maxHeaderListSizeShouldBeEnforcedOnClient() throws Exception {
|
||||||
|
startServer();
|
||||||
|
|
||||||
|
NettyClientTransport transport = newTransport(newNegotiator(), DEFAULT_MAX_MESSAGE_SIZE, 1);
|
||||||
|
transport.start(clientTransportListener);
|
||||||
|
|
||||||
|
try {
|
||||||
|
// Send a single RPC and wait for the response.
|
||||||
|
new Rpc(transport, new Metadata()).halfClose().waitForResponse();
|
||||||
|
fail("The stream should have been failed due to client received header exceeds header list"
|
||||||
|
+ " size limit!");
|
||||||
|
} catch (Exception e) {
|
||||||
|
Throwable rootCause = getRootCause(e);
|
||||||
|
assertTrue(rootCause instanceof Http2Exception);
|
||||||
|
assertEquals("Header size exceeded max allowed size (1)", rootCause.getMessage());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void maxHeaderListSizeShouldBeEnforcedOnServer() throws Exception {
|
||||||
|
startServer(100, 1);
|
||||||
|
|
||||||
|
NettyClientTransport transport = newTransport(newNegotiator());
|
||||||
|
transport.start(clientTransportListener);
|
||||||
|
|
||||||
|
try {
|
||||||
|
// Send a single RPC and wait for the response.
|
||||||
|
new Rpc(transport, new Metadata()).halfClose().waitForResponse();
|
||||||
|
fail("The stream should have been failed due to server received header exceeds header list"
|
||||||
|
+ " size limit!");
|
||||||
|
} catch (Exception e) {
|
||||||
|
Throwable rootCause = getRootCause(e);
|
||||||
|
assertTrue(rootCause.getMessage(),
|
||||||
|
rootCause.getMessage().contains("Header size exceeded max allowed size (1)"));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private Throwable getRootCause(Throwable t) {
|
||||||
|
if (t.getCause() == null) {
|
||||||
|
return t;
|
||||||
|
}
|
||||||
|
return getRootCause(t.getCause());
|
||||||
|
}
|
||||||
|
|
||||||
private ProtocolNegotiator newNegotiator() throws IOException {
|
private ProtocolNegotiator newNegotiator() throws IOException {
|
||||||
File clientCert = TestUtils.loadCert("ca.pem");
|
File clientCert = TestUtils.loadCert("ca.pem");
|
||||||
SslContext clientContext = GrpcSslContexts.forClient().trustManager(clientCert)
|
SslContext clientContext = GrpcSslContexts.forClient().trustManager(clientCert)
|
||||||
|
|
@ -242,28 +289,30 @@ public class NettyClientTransportTest {
|
||||||
}
|
}
|
||||||
|
|
||||||
private NettyClientTransport newTransport(ProtocolNegotiator negotiator) {
|
private NettyClientTransport newTransport(ProtocolNegotiator negotiator) {
|
||||||
return newTransport(negotiator, DEFAULT_MAX_MESSAGE_SIZE);
|
return newTransport(negotiator,
|
||||||
|
DEFAULT_MAX_MESSAGE_SIZE, GrpcUtil.DEFAULT_MAX_HEADER_LIST_SIZE);
|
||||||
}
|
}
|
||||||
|
|
||||||
private NettyClientTransport newTransport(ProtocolNegotiator negotiator, int maxMsgSize) {
|
private NettyClientTransport newTransport(ProtocolNegotiator negotiator,
|
||||||
|
int maxMsgSize, int maxHeaderListSize) {
|
||||||
NettyClientTransport transport = new NettyClientTransport(address, NioSocketChannel.class,
|
NettyClientTransport transport = new NettyClientTransport(address, NioSocketChannel.class,
|
||||||
group, negotiator, DEFAULT_WINDOW_SIZE, maxMsgSize, authority);
|
group, negotiator, DEFAULT_WINDOW_SIZE, maxMsgSize, maxHeaderListSize, authority);
|
||||||
transports.add(transport);
|
transports.add(transport);
|
||||||
return transport;
|
return transport;
|
||||||
}
|
}
|
||||||
|
|
||||||
private void startServer() throws IOException {
|
private void startServer() throws IOException {
|
||||||
startServer(100);
|
startServer(100, GrpcUtil.DEFAULT_MAX_HEADER_LIST_SIZE);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void startServer(int maxStreamsPerConnection) throws IOException {
|
private void startServer(int maxStreamsPerConnection, int maxHeaderListSize) throws IOException {
|
||||||
File serverCert = TestUtils.loadCert("server1.pem");
|
File serverCert = TestUtils.loadCert("server1.pem");
|
||||||
File key = TestUtils.loadCert("server1.key");
|
File key = TestUtils.loadCert("server1.key");
|
||||||
SslContext serverContext = GrpcSslContexts.forServer(serverCert, key)
|
SslContext serverContext = GrpcSslContexts.forServer(serverCert, key)
|
||||||
.ciphers(TestUtils.preferredTestCiphers(), SupportedCipherSuiteFilter.INSTANCE).build();
|
.ciphers(TestUtils.preferredTestCiphers(), SupportedCipherSuiteFilter.INSTANCE).build();
|
||||||
server = new NettyServer(address, NioServerSocketChannel.class,
|
server = new NettyServer(address, NioServerSocketChannel.class,
|
||||||
group, group, serverContext, maxStreamsPerConnection,
|
group, group, serverContext, maxStreamsPerConnection,
|
||||||
DEFAULT_WINDOW_SIZE, DEFAULT_MAX_MESSAGE_SIZE);
|
DEFAULT_WINDOW_SIZE, DEFAULT_MAX_MESSAGE_SIZE, maxHeaderListSize);
|
||||||
server.start(serverListener);
|
server.start(serverListener);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue