Expose compression on ClientCall and Server Call

This commit is contained in:
Carl Mastrangelo 2015-12-07 14:40:11 -08:00
parent 3fef40368d
commit 82a79d8f93
17 changed files with 192 additions and 28 deletions

View File

@ -183,4 +183,13 @@ public abstract class ClientCall<ReqT, RespT> {
public boolean isReady() { public boolean isReady() {
return true; return true;
} }
/**
* Enables per-message compression, if an encoding type has been negotiated. If no message
* encoding has been negotiated, this is a no-op.
*/
@ExperimentalApi
public void setMessageCompression(boolean enabled) {
// noop
}
} }

View File

@ -54,7 +54,7 @@ import javax.annotation.concurrent.ThreadSafe;
public final class DecompressorRegistry { public final class DecompressorRegistry {
private static final DecompressorRegistry DEFAULT_INSTANCE = new DecompressorRegistry( private static final DecompressorRegistry DEFAULT_INSTANCE = new DecompressorRegistry(
new DecompressorInfo(new Codec.Gzip(), false), new DecompressorInfo(new Codec.Gzip(), true),
new DecompressorInfo(Codec.Identity.NONE, false)); new DecompressorInfo(Codec.Identity.NONE, false));
public static DecompressorRegistry getDefaultInstance() { public static DecompressorRegistry getDefaultInstance() {

View File

@ -65,6 +65,11 @@ public abstract class ForwardingClientCall<ReqT, RespT> extends ClientCall<ReqT,
delegate().sendMessage(message); delegate().sendMessage(message);
} }
@Override
public void setMessageCompression(boolean enabled) {
delegate().setMessageCompression(enabled);
}
@Override @Override
public boolean isReady() { public boolean isReady() {
return delegate().isReady(); return delegate().isReady();

View File

@ -163,6 +163,22 @@ public abstract class ManagedChannelBuilder<T extends ManagedChannelBuilder<T>>
@ExperimentalApi @ExperimentalApi
public abstract T loadBalancerFactory(LoadBalancer.Factory loadBalancerFactory); public abstract T loadBalancerFactory(LoadBalancer.Factory loadBalancerFactory);
/**
* Set the decompression registry for use in the channel. This is an advanced API call and
* shouldn't be used unless you are using custom message encoding. The default supported
* decompressors are in {@code DecompressorRegistry.getDefaultInstance}.
*/
@ExperimentalApi
public abstract T decompressorRegistry(DecompressorRegistry registry);
/**
* Set the compression registry for use in the channel. This is an advanced API call and
* shouldn't be used unless you are using custom message encoding. The default supported
* compressors are in {@code CompressorRegistry.getDefaultInstance}.
*/
@ExperimentalApi
public abstract T compressorRegistry(CompressorRegistry registry);
/** /**
* Builds a channel using the given parameters. * Builds a channel using the given parameters.
*/ */

View File

@ -87,6 +87,22 @@ public abstract class ServerBuilder<T extends ServerBuilder<T>> {
*/ */
public abstract T useTransportSecurity(File certChain, File privateKey); public abstract T useTransportSecurity(File certChain, File privateKey);
/**
* Set the decompression registry for use in the channel. This is an advanced API call and
* shouldn't be used unless you are using custom message encoding. The default supported
* decompressors are in {@code DecompressorRegistry.getDefaultInstance}.
*/
@ExperimentalApi
public abstract T decompressorRegistry(DecompressorRegistry registry);
/**
* Set the compression registry for use in the channel. This is an advanced API call and
* shouldn't be used unless you are using custom message encoding. The default supported
* compressors are in {@code CompressorRegistry.getDefaultInstance}.
*/
@ExperimentalApi
public abstract T compressorRegistry(CompressorRegistry registry);
/** /**
* Builds a server using the given parameters. * Builds a server using the given parameters.
* *

View File

@ -31,11 +31,16 @@
package io.grpc.internal; package io.grpc.internal;
import static com.google.common.base.MoreObjects.firstNonNull;
import com.google.common.base.Preconditions; import com.google.common.base.Preconditions;
import com.google.common.util.concurrent.MoreExecutors; import com.google.common.util.concurrent.MoreExecutors;
import io.grpc.Attributes; import io.grpc.Attributes;
import io.grpc.ClientInterceptor; import io.grpc.ClientInterceptor;
import io.grpc.CompressorRegistry;
import io.grpc.DecompressorRegistry;
import io.grpc.ExperimentalApi;
import io.grpc.LoadBalancer; import io.grpc.LoadBalancer;
import io.grpc.ManagedChannelBuilder; import io.grpc.ManagedChannelBuilder;
import io.grpc.NameResolver; import io.grpc.NameResolver;
@ -82,6 +87,12 @@ public abstract class AbstractManagedChannelImplBuilder
@Nullable @Nullable
private LoadBalancer.Factory loadBalancerFactory; private LoadBalancer.Factory loadBalancerFactory;
@Nullable
private DecompressorRegistry decompressorRegistry;
@Nullable
private CompressorRegistry compressorRegistry;
protected AbstractManagedChannelImplBuilder(String target) { protected AbstractManagedChannelImplBuilder(String target) {
this.target = Preconditions.checkNotNull(target); this.target = Preconditions.checkNotNull(target);
this.directServerAddress = null; this.directServerAddress = null;
@ -133,6 +144,20 @@ public abstract class AbstractManagedChannelImplBuilder
return thisT(); return thisT();
} }
@Override
@ExperimentalApi
public final T decompressorRegistry(DecompressorRegistry registry) {
this.decompressorRegistry = registry;
return thisT();
}
@Override
@ExperimentalApi
public final T compressorRegistry(CompressorRegistry registry) {
this.compressorRegistry = registry;
return thisT();
}
private T thisT() { private T thisT() {
@SuppressWarnings("unchecked") @SuppressWarnings("unchecked")
T thisT = (T) this; T thisT = (T) this;
@ -168,12 +193,13 @@ public abstract class AbstractManagedChannelImplBuilder
target, target,
// TODO(carl-mastrangelo): Allow clients to pass this in // TODO(carl-mastrangelo): Allow clients to pass this in
new ExponentialBackoffPolicy.Provider(), new ExponentialBackoffPolicy.Provider(),
nameResolverFactory == null ? NameResolverRegistry.getDefaultRegistry() firstNonNull(nameResolverFactory, NameResolverRegistry.getDefaultRegistry()),
: nameResolverFactory,
getNameResolverParams(), getNameResolverParams(),
loadBalancerFactory == null ? SimpleLoadBalancerFactory.getInstance() firstNonNull(loadBalancerFactory, SimpleLoadBalancerFactory.getInstance()),
: loadBalancerFactory, transportFactory,
transportFactory, executor, userAgent, interceptors); firstNonNull(decompressorRegistry, DecompressorRegistry.getDefaultInstance()),
firstNonNull(compressorRegistry, CompressorRegistry.getDefaultInstance()),
executor, userAgent, interceptors);
} }
/** /**
@ -186,7 +212,7 @@ public abstract class AbstractManagedChannelImplBuilder
/** /**
* Subclasses can override this method to provide additional parameters to {@link * Subclasses can override this method to provide additional parameters to {@link
* NameResolver.Factory#newNameResolver}. The default implementation returns {@link * NameResolver.Factory#newNameResolver}. The default implementation returns {@link
* Attributes.EMPTY}. * Attributes#EMPTY}.
*/ */
protected Attributes getNameResolverParams() { protected Attributes getNameResolverParams() {
return Attributes.EMPTY; return Attributes.EMPTY;

View File

@ -34,7 +34,9 @@ package io.grpc.internal;
import com.google.common.base.Preconditions; import com.google.common.base.Preconditions;
import com.google.common.util.concurrent.MoreExecutors; import com.google.common.util.concurrent.MoreExecutors;
import io.grpc.CompressorRegistry;
import io.grpc.Context; import io.grpc.Context;
import io.grpc.DecompressorRegistry;
import io.grpc.HandlerRegistry; import io.grpc.HandlerRegistry;
import io.grpc.Internal; import io.grpc.Internal;
import io.grpc.MutableHandlerRegistry; import io.grpc.MutableHandlerRegistry;
@ -58,6 +60,12 @@ public abstract class AbstractServerImplBuilder<T extends AbstractServerImplBuil
@Nullable @Nullable
private Executor executor; private Executor executor;
@Nullable
private DecompressorRegistry decompressorRegistry;
@Nullable
private CompressorRegistry compressorRegistry;
/** /**
* Constructs using a given handler registry. * Constructs using a given handler registry.
*/ */
@ -98,6 +106,26 @@ public abstract class AbstractServerImplBuilder<T extends AbstractServerImplBuil
throw new UnsupportedOperationException("Underlying HandlerRegistry is not mutable"); throw new UnsupportedOperationException("Underlying HandlerRegistry is not mutable");
} }
@Override
public final T decompressorRegistry(DecompressorRegistry registry) {
decompressorRegistry = registry;
return thisT();
}
protected final DecompressorRegistry decompressorRegistry() {
return decompressorRegistry;
}
@Override
public final T compressorRegistry(CompressorRegistry registry) {
compressorRegistry = registry;
return thisT();
}
protected final CompressorRegistry compressorRegistry() {
return compressorRegistry;
}
@Override @Override
public ServerImpl build() { public ServerImpl build() {
io.grpc.internal.Server transportServer = buildTransportServer(); io.grpc.internal.Server transportServer = buildTransportServer();

View File

@ -31,6 +31,7 @@
package io.grpc.internal; package io.grpc.internal;
import static com.google.common.base.Preconditions.checkState;
import static com.google.common.collect.Iterables.addAll; import static com.google.common.collect.Iterables.addAll;
import static com.google.common.util.concurrent.MoreExecutors.directExecutor; import static com.google.common.util.concurrent.MoreExecutors.directExecutor;
import static io.grpc.internal.GrpcUtil.ACCEPT_ENCODING_SPLITER; import static io.grpc.internal.GrpcUtil.ACCEPT_ENCODING_SPLITER;
@ -337,6 +338,12 @@ final class ClientCallImpl<ReqT, RespT> extends ClientCall<ReqT, RespT>
} }
} }
@Override
public void setMessageCompression(boolean enabled) {
checkState(stream != null, "Not started");
stream.setMessageCompression(enabled);
}
@Override @Override
public boolean isReady() { public boolean isReady() {
return stream.isReady(); return stream.isReady();

View File

@ -108,9 +108,8 @@ public final class ManagedChannelImpl extends ManagedChannel {
*/ */
private final Set<String> knownAcceptEncodingRegistry = private final Set<String> knownAcceptEncodingRegistry =
Collections.newSetFromMap(new ConcurrentHashMap<String, Boolean>()); Collections.newSetFromMap(new ConcurrentHashMap<String, Boolean>());
private final DecompressorRegistry decompressorRegistry = private final DecompressorRegistry decompressorRegistry;
DecompressorRegistry.getDefaultInstance(); private final CompressorRegistry compressorRegistry;
private final CompressorRegistry compressorRegistry = CompressorRegistry.getDefaultInstance();
/** /**
* Executor that runs deadline timers for requests. * Executor that runs deadline timers for requests.
@ -154,9 +153,10 @@ public final class ManagedChannelImpl extends ManagedChannel {
ManagedChannelImpl(String target, BackoffPolicy.Provider backoffPolicyProvider, ManagedChannelImpl(String target, BackoffPolicy.Provider backoffPolicyProvider,
NameResolver.Factory nameResolverFactory, Attributes nameResolverParams, NameResolver.Factory nameResolverFactory, Attributes nameResolverParams,
LoadBalancer.Factory loadBalancerFactory, LoadBalancer.Factory loadBalancerFactory, ClientTransportFactory transportFactory,
ClientTransportFactory transportFactory, @Nullable Executor executor, DecompressorRegistry decompressorRegistry, CompressorRegistry compressorRegistry,
@Nullable String userAgent, List<ClientInterceptor> interceptors) { @Nullable Executor executor, @Nullable String userAgent,
List<ClientInterceptor> interceptors) {
if (executor == null) { if (executor == null) {
usingSharedExecutor = true; usingSharedExecutor = true;
this.executor = SharedResourceHolder.get(GrpcUtil.SHARED_CHANNEL_EXECUTOR); this.executor = SharedResourceHolder.get(GrpcUtil.SHARED_CHANNEL_EXECUTOR);
@ -171,6 +171,8 @@ public final class ManagedChannelImpl extends ManagedChannel {
this.userAgent = userAgent; this.userAgent = userAgent;
this.interceptorChannel = ClientInterceptors.intercept(new RealChannel(), interceptors); this.interceptorChannel = ClientInterceptors.intercept(new RealChannel(), interceptors);
scheduledExecutor = SharedResourceHolder.get(TIMER_SERVICE); scheduledExecutor = SharedResourceHolder.get(TIMER_SERVICE);
this.decompressorRegistry = decompressorRegistry;
this.compressorRegistry = compressorRegistry;
this.nameResolver.start(new NameResolver.Listener() { this.nameResolver.start(new NameResolver.Listener() {
@Override @Override

View File

@ -134,7 +134,8 @@ public class ManagedChannelImplTest {
NameResolver.Factory nameResolverFactory, List<ClientInterceptor> interceptors) { NameResolver.Factory nameResolverFactory, List<ClientInterceptor> interceptors) {
return new ManagedChannelImpl(target, new FakeBackoffPolicyProvider(), return new ManagedChannelImpl(target, new FakeBackoffPolicyProvider(),
nameResolverFactory, NAME_RESOLVER_PARAMS, loadBalancerFactory, nameResolverFactory, NAME_RESOLVER_PARAMS, loadBalancerFactory,
mockTransportFactory, executor, null, interceptors); mockTransportFactory, DecompressorRegistry.getDefaultInstance(),
CompressorRegistry.getDefaultInstance(), executor, null, interceptors);
} }
@Before @Before

View File

@ -48,6 +48,8 @@ import com.google.common.util.concurrent.ListenableFuture;
import io.grpc.Attributes; import io.grpc.Attributes;
import io.grpc.ClientInterceptor; import io.grpc.ClientInterceptor;
import io.grpc.CompressorRegistry;
import io.grpc.DecompressorRegistry;
import io.grpc.EquivalentAddressGroup; import io.grpc.EquivalentAddressGroup;
import io.grpc.LoadBalancer; import io.grpc.LoadBalancer;
import io.grpc.NameResolver; import io.grpc.NameResolver;
@ -119,7 +121,9 @@ public class ManagedChannelImplTransportManagerTest {
channel = new ManagedChannelImpl("fake://target", mockBackoffPolicyProvider, channel = new ManagedChannelImpl("fake://target", mockBackoffPolicyProvider,
nameResolverFactory, Attributes.EMPTY, mockLoadBalancerFactory, nameResolverFactory, Attributes.EMPTY, mockLoadBalancerFactory,
mockTransportFactory, executor, null, Collections.<ClientInterceptor>emptyList()); mockTransportFactory, DecompressorRegistry.getDefaultInstance(),
CompressorRegistry.getDefaultInstance(), executor, null,
Collections.<ClientInterceptor>emptyList());
ArgumentCaptor<TransportManager> tmCaptor = ArgumentCaptor.forClass(TransportManager.class); ArgumentCaptor<TransportManager> tmCaptor = ArgumentCaptor.forClass(TransportManager.class);
verify(mockLoadBalancerFactory).newLoadBalancer(anyString(), tmCaptor.capture()); verify(mockLoadBalancerFactory).newLoadBalancer(anyString(), tmCaptor.capture());

View File

@ -35,6 +35,8 @@ import static com.google.common.base.Preconditions.checkNotNull;
import static io.netty.channel.ChannelOption.SO_BACKLOG; import static io.netty.channel.ChannelOption.SO_BACKLOG;
import static io.netty.channel.ChannelOption.SO_KEEPALIVE; import static io.netty.channel.ChannelOption.SO_KEEPALIVE;
import io.grpc.CompressorRegistry;
import io.grpc.DecompressorRegistry;
import io.grpc.internal.Server; import io.grpc.internal.Server;
import io.grpc.internal.ServerListener; import io.grpc.internal.ServerListener;
import io.grpc.internal.SharedResourceHolder; import io.grpc.internal.SharedResourceHolder;
@ -72,6 +74,8 @@ class NettyServer implements Server {
private EventLoopGroup workerGroup; private EventLoopGroup workerGroup;
private ServerListener listener; private ServerListener listener;
private Channel channel; private Channel channel;
private final DecompressorRegistry decompressorRegistry;
private final CompressorRegistry compressorRegistry;
private final int flowControlWindow; private final int flowControlWindow;
private final int maxMessageSize; private final int maxMessageSize;
private final int maxHeaderListSize; private final int maxHeaderListSize;
@ -79,7 +83,8 @@ class NettyServer implements Server {
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,
ProtocolNegotiator protocolNegotiator, int maxStreamsPerConnection, ProtocolNegotiator protocolNegotiator, DecompressorRegistry decompressorRegistry,
CompressorRegistry compressorRegistry, int maxStreamsPerConnection,
int flowControlWindow, int maxMessageSize, int maxHeaderListSize) { int flowControlWindow, int maxMessageSize, int maxHeaderListSize) {
this.address = address; this.address = address;
this.channelType = checkNotNull(channelType, "channelType"); this.channelType = checkNotNull(channelType, "channelType");
@ -92,6 +97,8 @@ class NettyServer implements Server {
this.flowControlWindow = flowControlWindow; this.flowControlWindow = flowControlWindow;
this.maxMessageSize = maxMessageSize; this.maxMessageSize = maxMessageSize;
this.maxHeaderListSize = maxHeaderListSize; this.maxHeaderListSize = maxHeaderListSize;
this.decompressorRegistry = checkNotNull(decompressorRegistry, "decompressorRegistry");
this.compressorRegistry = checkNotNull(compressorRegistry, "compressorRegistry");
} }
@Override @Override
@ -113,13 +120,15 @@ class NettyServer implements Server {
public void initChannel(Channel ch) throws Exception { public void initChannel(Channel ch) throws Exception {
eventLoopReferenceCounter.retain(); eventLoopReferenceCounter.retain();
ch.closeFuture().addListener(new ChannelFutureListener() { ch.closeFuture().addListener(new ChannelFutureListener() {
@Override
public void operationComplete(ChannelFuture future) { public void operationComplete(ChannelFuture future) {
eventLoopReferenceCounter.release(); eventLoopReferenceCounter.release();
} }
}); });
NettyServerTransport transport NettyServerTransport transport
= new NettyServerTransport(ch, protocolNegotiator, maxStreamsPerConnection, = new NettyServerTransport(ch, protocolNegotiator, decompressorRegistry,
flowControlWindow, maxMessageSize, maxHeaderListSize); compressorRegistry, maxStreamsPerConnection, flowControlWindow, maxMessageSize,
maxHeaderListSize);
transport.start(listener.transportCreated(transport)); transport.start(listener.transportCreated(transport));
} }
}); });

View File

@ -31,11 +31,14 @@
package io.grpc.netty; package io.grpc.netty;
import static com.google.common.base.MoreObjects.firstNonNull;
import static com.google.common.base.Preconditions.checkArgument; import static com.google.common.base.Preconditions.checkArgument;
import static io.grpc.internal.GrpcUtil.DEFAULT_MAX_MESSAGE_SIZE; import static io.grpc.internal.GrpcUtil.DEFAULT_MAX_MESSAGE_SIZE;
import com.google.common.base.Preconditions; import com.google.common.base.Preconditions;
import io.grpc.CompressorRegistry;
import io.grpc.DecompressorRegistry;
import io.grpc.ExperimentalApi; import io.grpc.ExperimentalApi;
import io.grpc.HandlerRegistry; import io.grpc.HandlerRegistry;
import io.grpc.Internal; import io.grpc.Internal;
@ -242,7 +245,10 @@ public final class NettyServerBuilder extends AbstractServerImplBuilder<NettySer
ProtocolNegotiators.serverPlaintext(); ProtocolNegotiators.serverPlaintext();
} }
return new NettyServer(address, channelType, bossEventLoopGroup, return new NettyServer(address, channelType, bossEventLoopGroup,
workerEventLoopGroup, negotiator, maxConcurrentCallsPerConnection, flowControlWindow, workerEventLoopGroup, negotiator,
firstNonNull(decompressorRegistry(), DecompressorRegistry.getDefaultInstance()),
firstNonNull(compressorRegistry(), CompressorRegistry.getDefaultInstance()),
maxConcurrentCallsPerConnection, flowControlWindow,
maxMessageSize, maxHeaderListSize); maxMessageSize, maxHeaderListSize);
} }

View File

@ -32,6 +32,7 @@
package io.grpc.netty; package io.grpc.netty;
import static com.google.common.base.Preconditions.checkArgument; import static com.google.common.base.Preconditions.checkArgument;
import static com.google.common.base.Preconditions.checkNotNull;
import static io.grpc.netty.Utils.CONTENT_TYPE_GRPC; import static io.grpc.netty.Utils.CONTENT_TYPE_GRPC;
import static io.grpc.netty.Utils.CONTENT_TYPE_HEADER; import static io.grpc.netty.Utils.CONTENT_TYPE_HEADER;
import static io.grpc.netty.Utils.HTTP_METHOD; import static io.grpc.netty.Utils.HTTP_METHOD;
@ -42,6 +43,8 @@ import static io.netty.handler.codec.http2.DefaultHttp2LocalFlowController.DEFAU
import com.google.common.annotations.VisibleForTesting; import com.google.common.annotations.VisibleForTesting;
import com.google.common.base.Preconditions; import com.google.common.base.Preconditions;
import io.grpc.CompressorRegistry;
import io.grpc.DecompressorRegistry;
import io.grpc.Metadata; import io.grpc.Metadata;
import io.grpc.Status; import io.grpc.Status;
import io.grpc.internal.GrpcUtil; import io.grpc.internal.GrpcUtil;
@ -94,6 +97,8 @@ class NettyServerHandler extends AbstractNettyHandler {
private static final Status GOAWAY_STATUS = Status.UNAVAILABLE; private static final Status GOAWAY_STATUS = Status.UNAVAILABLE;
private final DecompressorRegistry decompressorRegistry;
private final CompressorRegistry compressorRegistry;
private final Http2Connection.PropertyKey streamKey; private final Http2Connection.PropertyKey streamKey;
private final ServerTransportListener transportListener; private final ServerTransportListener transportListener;
private final int maxMessageSize; private final int maxMessageSize;
@ -102,6 +107,8 @@ class NettyServerHandler extends AbstractNettyHandler {
private WriteQueue serverWriteQueue; private WriteQueue serverWriteQueue;
static NettyServerHandler newHandler(ServerTransportListener transportListener, static NettyServerHandler newHandler(ServerTransportListener transportListener,
DecompressorRegistry decompressorRegistry,
CompressorRegistry compressorRegistry,
int maxStreams, int maxStreams,
int flowControlWindow, int flowControlWindow,
int maxHeaderListSize, int maxHeaderListSize,
@ -114,13 +121,15 @@ class NettyServerHandler extends AbstractNettyHandler {
new DefaultHttp2FrameReader(headersDecoder), frameLogger); new DefaultHttp2FrameReader(headersDecoder), frameLogger);
Http2FrameWriter frameWriter = Http2FrameWriter frameWriter =
new Http2OutboundFrameLogger(new DefaultHttp2FrameWriter(), frameLogger); new Http2OutboundFrameLogger(new DefaultHttp2FrameWriter(), frameLogger);
return newHandler(frameReader, frameWriter, transportListener, maxStreams, flowControlWindow, return newHandler(frameReader, frameWriter, transportListener, decompressorRegistry,
maxMessageSize); compressorRegistry, maxStreams, flowControlWindow, maxMessageSize);
} }
@VisibleForTesting @VisibleForTesting
static NettyServerHandler newHandler(Http2FrameReader frameReader, Http2FrameWriter frameWriter, static NettyServerHandler newHandler(Http2FrameReader frameReader, Http2FrameWriter frameWriter,
ServerTransportListener transportListener, ServerTransportListener transportListener,
DecompressorRegistry decompressorRegistry,
CompressorRegistry compressorRegistry,
int maxStreams, int maxStreams,
int flowControlWindow, int flowControlWindow,
int maxMessageSize) { int maxMessageSize) {
@ -142,19 +151,24 @@ class NettyServerHandler extends AbstractNettyHandler {
settings.initialWindowSize(flowControlWindow); settings.initialWindowSize(flowControlWindow);
settings.maxConcurrentStreams(maxStreams); settings.maxConcurrentStreams(maxStreams);
return new NettyServerHandler(transportListener, decoder, encoder, settings, maxMessageSize); return new NettyServerHandler(transportListener, decoder, encoder, settings,
decompressorRegistry, compressorRegistry, maxMessageSize);
} }
private NettyServerHandler(ServerTransportListener transportListener, private NettyServerHandler(ServerTransportListener transportListener,
Http2ConnectionDecoder decoder, Http2ConnectionDecoder decoder,
Http2ConnectionEncoder encoder, Http2Settings settings, Http2ConnectionEncoder encoder, Http2Settings settings,
DecompressorRegistry decompressorRegistry,
CompressorRegistry compressorRegistry,
int maxMessageSize) { int maxMessageSize) {
super(decoder, encoder, settings); super(decoder, encoder, settings);
checkArgument(maxMessageSize >= 0, "maxMessageSize must be >= 0"); checkArgument(maxMessageSize >= 0, "maxMessageSize must be >= 0");
this.maxMessageSize = maxMessageSize; this.maxMessageSize = maxMessageSize;
this.decompressorRegistry = checkNotNull(decompressorRegistry, "decompressorRegistry");
this.compressorRegistry = checkNotNull(compressorRegistry, "compressorRegistry");
streamKey = encoder.connection().newKey(); streamKey = encoder.connection().newKey();
this.transportListener = Preconditions.checkNotNull(transportListener, "transportListener"); this.transportListener = checkNotNull(transportListener, "transportListener");
// Set the frame listener on the decoder. // Set the frame listener on the decoder.
decoder().frameListener(new FrameListener()); decoder().frameListener(new FrameListener());
@ -192,6 +206,11 @@ class NettyServerHandler extends AbstractNettyHandler {
NettyServerStream stream = new NettyServerStream(ctx.channel(), http2Stream, this, NettyServerStream stream = new NettyServerStream(ctx.channel(), http2Stream, this,
maxMessageSize); maxMessageSize);
// These must be called before inboundHeadersReceived, because the framers depend on knowing
// the compression algorithms available before negotiation.
stream.setDecompressionRegistry(decompressorRegistry);
stream.setCompressionRegistry(compressorRegistry);
Metadata metadata = Utils.convertHeaders(headers); Metadata metadata = Utils.convertHeaders(headers);
stream.inboundHeadersReceived(metadata); stream.inboundHeadersReceived(metadata);

View File

@ -31,8 +31,12 @@
package io.grpc.netty; package io.grpc.netty;
import static com.google.common.base.Preconditions.checkNotNull;
import com.google.common.base.Preconditions; import com.google.common.base.Preconditions;
import io.grpc.CompressorRegistry;
import io.grpc.DecompressorRegistry;
import io.grpc.internal.ServerTransport; import io.grpc.internal.ServerTransport;
import io.grpc.internal.ServerTransportListener; import io.grpc.internal.ServerTransportListener;
import io.netty.channel.Channel; import io.netty.channel.Channel;
@ -51,6 +55,8 @@ class NettyServerTransport implements ServerTransport {
private final Channel channel; private final Channel channel;
private final ProtocolNegotiator protocolNegotiator; private final ProtocolNegotiator protocolNegotiator;
private final DecompressorRegistry decompressorRegistry;
private final CompressorRegistry compressorRegistry;
private final int maxStreams; private final int maxStreams;
private ServerTransportListener listener; private ServerTransportListener listener;
private boolean terminated; private boolean terminated;
@ -58,14 +64,18 @@ class NettyServerTransport implements ServerTransport {
private final int maxMessageSize; private final int maxMessageSize;
private final int maxHeaderListSize; private final int maxHeaderListSize;
NettyServerTransport(Channel channel, ProtocolNegotiator protocolNegotiator, int maxStreams, NettyServerTransport(Channel channel, ProtocolNegotiator protocolNegotiator,
int flowControlWindow, int maxMessageSize, int maxHeaderListSize) { DecompressorRegistry decompressorRegistry,
CompressorRegistry compressorRegistry, int maxStreams, int flowControlWindow,
int maxMessageSize, int maxHeaderListSize) {
this.channel = Preconditions.checkNotNull(channel, "channel"); this.channel = Preconditions.checkNotNull(channel, "channel");
this.protocolNegotiator = Preconditions.checkNotNull(protocolNegotiator, "protocolNegotiator"); this.protocolNegotiator = Preconditions.checkNotNull(protocolNegotiator, "protocolNegotiator");
this.maxStreams = maxStreams; this.maxStreams = maxStreams;
this.flowControlWindow = flowControlWindow; this.flowControlWindow = flowControlWindow;
this.maxMessageSize = maxMessageSize; this.maxMessageSize = maxMessageSize;
this.maxHeaderListSize = maxHeaderListSize; this.maxHeaderListSize = maxHeaderListSize;
this.decompressorRegistry = checkNotNull(decompressorRegistry, "decompressorRegistry");
this.compressorRegistry = checkNotNull(compressorRegistry, "compressorRegistry");
} }
public void start(ServerTransportListener listener) { public void start(ServerTransportListener listener) {
@ -115,7 +125,7 @@ class NettyServerTransport implements ServerTransport {
* Creates the Netty handler to be used in the channel pipeline. * Creates the Netty handler to be used in the channel pipeline.
*/ */
private NettyServerHandler createHandler(ServerTransportListener transportListener) { private NettyServerHandler createHandler(ServerTransportListener transportListener) {
return NettyServerHandler.newHandler(transportListener, maxStreams, flowControlWindow, return NettyServerHandler.newHandler(transportListener, decompressorRegistry,
maxHeaderListSize, maxMessageSize); compressorRegistry, maxStreams, flowControlWindow, maxHeaderListSize, maxMessageSize);
} }
} }

View File

@ -43,6 +43,8 @@ import static org.junit.Assert.fail;
import com.google.common.io.ByteStreams; import com.google.common.io.ByteStreams;
import com.google.common.util.concurrent.SettableFuture; import com.google.common.util.concurrent.SettableFuture;
import io.grpc.CompressorRegistry;
import io.grpc.DecompressorRegistry;
import io.grpc.Metadata; import io.grpc.Metadata;
import io.grpc.MethodDescriptor; import io.grpc.MethodDescriptor;
import io.grpc.MethodDescriptor.Marshaller; import io.grpc.MethodDescriptor.Marshaller;
@ -312,7 +314,8 @@ public class NettyClientTransportTest {
.ciphers(TestUtils.preferredTestCiphers(), SupportedCipherSuiteFilter.INSTANCE).build(); .ciphers(TestUtils.preferredTestCiphers(), SupportedCipherSuiteFilter.INSTANCE).build();
ProtocolNegotiator negotiator = ProtocolNegotiators.serverTls(serverContext); ProtocolNegotiator negotiator = ProtocolNegotiators.serverTls(serverContext);
server = new NettyServer(address, NioServerSocketChannel.class, server = new NettyServer(address, NioServerSocketChannel.class,
group, group, negotiator, maxStreamsPerConnection, group, group, negotiator, DecompressorRegistry.getDefaultInstance(),
CompressorRegistry.getDefaultInstance(), maxStreamsPerConnection,
DEFAULT_WINDOW_SIZE, DEFAULT_MAX_MESSAGE_SIZE, maxHeaderListSize); DEFAULT_WINDOW_SIZE, DEFAULT_MAX_MESSAGE_SIZE, maxHeaderListSize);
server.start(serverListener); server.start(serverListener);
} }

View File

@ -54,6 +54,8 @@ import static org.mockito.Mockito.when;
import com.google.common.io.ByteStreams; import com.google.common.io.ByteStreams;
import io.grpc.CompressorRegistry;
import io.grpc.DecompressorRegistry;
import io.grpc.Metadata; import io.grpc.Metadata;
import io.grpc.Status; import io.grpc.Status;
import io.grpc.Status.Code; import io.grpc.Status.Code;
@ -345,6 +347,7 @@ public class NettyServerHandlerTest extends NettyHandlerTestBase<NettyServerHand
@Override @Override
protected NettyServerHandler newHandler() { protected NettyServerHandler newHandler() {
return NettyServerHandler.newHandler(frameReader(), frameWriter(), transportListener, return NettyServerHandler.newHandler(frameReader(), frameWriter(), transportListener,
DecompressorRegistry.getDefaultInstance(), CompressorRegistry.getDefaultInstance(),
maxConcurrentStreams, flowControlWindow, DEFAULT_MAX_MESSAGE_SIZE); maxConcurrentStreams, flowControlWindow, DEFAULT_MAX_MESSAGE_SIZE);
} }