mirror of https://github.com/grpc/grpc-java.git
Upgrading to Netty 4.1.0.Beta8
A few things to note: - ByteString has gone away in favor of AsciiString. - Http2Headers now uses CharSequence for all methods, so there are a few places that we have to explicitly check for AsciiString to get the optimizations. - We now have to specify a graceful shutdown timeout for our Netty handlers. Using 5 seconds.
This commit is contained in:
parent
088def1985
commit
ebed5a624a
|
|
@ -57,7 +57,7 @@ In Maven, you can use the [os-maven-plugin](https://github.com/trustin/os-maven-
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>io.netty</groupId>
|
<groupId>io.netty</groupId>
|
||||||
<artifactId>netty-tcnative</artifactId>
|
<artifactId>netty-tcnative</artifactId>
|
||||||
<version>1.1.33.Fork7</version>
|
<version>1.1.33.Fork9</version>
|
||||||
<classifier>${tcnative.classifier}</classifier>
|
<classifier>${tcnative.classifier}</classifier>
|
||||||
</dependency>
|
</dependency>
|
||||||
</dependencies>
|
</dependencies>
|
||||||
|
|
@ -125,7 +125,7 @@ if (osdetector.os == "linux" && osdetector.release.isLike("fedora")) {
|
||||||
}
|
}
|
||||||
|
|
||||||
dependencies {
|
dependencies {
|
||||||
compile 'io.netty:netty-tcnative:1.1.33.Fork7:' + tcnative_classifier
|
compile 'io.netty:netty-tcnative:1.1.33.Fork9:' + tcnative_classifier
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -38,7 +38,7 @@ dependencies {
|
||||||
libraries.mockito,
|
libraries.mockito,
|
||||||
libraries.hdrhistogram,
|
libraries.hdrhistogram,
|
||||||
libraries.netty_tcnative,
|
libraries.netty_tcnative,
|
||||||
libraries.netty_transport_native_epoll
|
libraries.netty_epoll
|
||||||
}
|
}
|
||||||
|
|
||||||
configureProtoCompilation()
|
configureProtoCompilation()
|
||||||
|
|
|
||||||
|
|
@ -144,9 +144,9 @@ subprojects {
|
||||||
protobuf_nano: "com.google.protobuf.nano:protobuf-javanano:${protobufNanoVersion}",
|
protobuf_nano: "com.google.protobuf.nano:protobuf-javanano:${protobufNanoVersion}",
|
||||||
protobuf_plugin: 'com.google.protobuf:protobuf-gradle-plugin:0.7.0',
|
protobuf_plugin: 'com.google.protobuf:protobuf-gradle-plugin:0.7.0',
|
||||||
|
|
||||||
netty: 'io.netty:netty-codec-http2:4.1.0.Beta6',
|
netty: 'io.netty:netty-codec-http2:4.1.0.Beta8',
|
||||||
netty_tcnative: 'io.netty:netty-tcnative:1.1.33.Fork7:' + tcnative_suffix,
|
netty_epoll: 'io.netty:netty-transport-native-epoll:4.1.0.Beta8' + epoll_suffix,
|
||||||
netty_transport_native_epoll: 'io.netty:netty-transport-native-epoll:4.1.0.Beta6' + epoll_suffix,
|
netty_tcnative: 'io.netty:netty-tcnative:1.1.33.Fork9:' + tcnative_suffix,
|
||||||
|
|
||||||
// Test dependencies.
|
// Test dependencies.
|
||||||
junit: 'junit:junit:4.11',
|
junit: 'junit:junit:4.11',
|
||||||
|
|
|
||||||
|
|
@ -32,6 +32,8 @@
|
||||||
package io.grpc.netty;
|
package io.grpc.netty;
|
||||||
|
|
||||||
import static io.netty.handler.codec.http2.Http2CodecUtil.getEmbeddedHttp2Exception;
|
import static io.netty.handler.codec.http2.Http2CodecUtil.getEmbeddedHttp2Exception;
|
||||||
|
import static java.util.concurrent.TimeUnit.MILLISECONDS;
|
||||||
|
import static java.util.concurrent.TimeUnit.SECONDS;
|
||||||
|
|
||||||
import io.netty.channel.ChannelHandlerContext;
|
import io.netty.channel.ChannelHandlerContext;
|
||||||
import io.netty.handler.codec.http2.Http2ConnectionDecoder;
|
import io.netty.handler.codec.http2.Http2ConnectionDecoder;
|
||||||
|
|
@ -47,7 +49,7 @@ import io.netty.handler.codec.http2.Http2Stream;
|
||||||
* shutdown the connection) as well as sending the initial connection window at startup.
|
* shutdown the connection) as well as sending the initial connection window at startup.
|
||||||
*/
|
*/
|
||||||
abstract class AbstractNettyHandler extends Http2ConnectionHandler {
|
abstract class AbstractNettyHandler extends Http2ConnectionHandler {
|
||||||
|
private static long GRACEFUL_SHUTDOWN_TIMEOUT = MILLISECONDS.convert(5, SECONDS);
|
||||||
private int initialConnectionWindow;
|
private int initialConnectionWindow;
|
||||||
private ChannelHandlerContext ctx;
|
private ChannelHandlerContext ctx;
|
||||||
|
|
||||||
|
|
@ -56,6 +58,9 @@ abstract class AbstractNettyHandler extends Http2ConnectionHandler {
|
||||||
Http2Settings initialSettings) {
|
Http2Settings initialSettings) {
|
||||||
super(decoder, encoder, initialSettings);
|
super(decoder, encoder, initialSettings);
|
||||||
|
|
||||||
|
// Set the timeout for graceful shutdown.
|
||||||
|
gracefulShutdownTimeoutMillis(GRACEFUL_SHUTDOWN_TIMEOUT);
|
||||||
|
|
||||||
// TODO(nmittler): Use auto-refill once https://github.com/grpc/grpc-java/issues/1175 is fixed.
|
// TODO(nmittler): Use auto-refill once https://github.com/grpc/grpc-java/issues/1175 is fixed.
|
||||||
this.initialConnectionWindow = Integer.MAX_VALUE;
|
this.initialConnectionWindow = Integer.MAX_VALUE;
|
||||||
}
|
}
|
||||||
|
|
@ -81,7 +86,8 @@ abstract class AbstractNettyHandler extends Http2ConnectionHandler {
|
||||||
if (embedded == null) {
|
if (embedded == null) {
|
||||||
// Kill the connection instead of propagating the exceptionCaught(). Http2ConnectionHandler
|
// Kill the connection instead of propagating the exceptionCaught(). Http2ConnectionHandler
|
||||||
// only handles Http2Exceptions and propagates everything else.
|
// only handles Http2Exceptions and propagates everything else.
|
||||||
cause = Http2Exception.connectionError(Http2Error.INTERNAL_ERROR, cause, cause.getMessage());
|
String message = cause.getMessage() == null ? "Unknown error occurred" : cause.getMessage();
|
||||||
|
cause = Http2Exception.connectionError(Http2Error.INTERNAL_ERROR, cause, message);
|
||||||
}
|
}
|
||||||
super.exceptionCaught(ctx, cause);
|
super.exceptionCaught(ctx, cause);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -105,12 +105,13 @@ class NettyClientHandler extends AbstractNettyHandler {
|
||||||
|
|
||||||
@VisibleForTesting
|
@VisibleForTesting
|
||||||
NettyClientHandler(BufferingHttp2ConnectionEncoder encoder, Http2Connection connection,
|
NettyClientHandler(BufferingHttp2ConnectionEncoder encoder, Http2Connection connection,
|
||||||
Http2FrameReader frameReader, int flowControlWindow, Ticker ticker) {
|
Http2FrameReader frameReader, int flowControlWindow, Ticker ticker) {
|
||||||
super(new DefaultHttp2ConnectionDecoder(connection, encoder, frameReader,
|
super(new DefaultHttp2ConnectionDecoder(connection, encoder, frameReader), encoder,
|
||||||
new LazyFrameListener()), encoder, createInitialSettings(flowControlWindow));
|
createInitialSettings(flowControlWindow));
|
||||||
this.ticker = ticker;
|
this.ticker = ticker;
|
||||||
|
|
||||||
initListener();
|
// Set the frame listener on the decoder.
|
||||||
|
decoder().frameListener(new FrameListener());
|
||||||
|
|
||||||
streamKey = connection.newKey();
|
streamKey = connection.newKey();
|
||||||
|
|
||||||
|
|
@ -180,10 +181,6 @@ class NettyClientHandler extends AbstractNettyHandler {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void initListener() {
|
|
||||||
((LazyFrameListener) decoder().listener()).setHandler(this);
|
|
||||||
}
|
|
||||||
|
|
||||||
private void onHeadersRead(int streamId, Http2Headers headers, boolean endStream)
|
private void onHeadersRead(int streamId, Http2Headers headers, boolean endStream)
|
||||||
throws Http2Exception {
|
throws Http2Exception {
|
||||||
NettyClientStream stream = clientStream(requireHttp2Stream(streamId));
|
NettyClientStream stream = clientStream(requireHttp2Stream(streamId));
|
||||||
|
|
@ -476,17 +473,11 @@ class NettyClientHandler extends AbstractNettyHandler {
|
||||||
return stream;
|
return stream;
|
||||||
}
|
}
|
||||||
|
|
||||||
private static class LazyFrameListener extends Http2FrameAdapter {
|
private class FrameListener extends Http2FrameAdapter {
|
||||||
private NettyClientHandler handler;
|
|
||||||
|
|
||||||
void setHandler(NettyClientHandler handler) {
|
|
||||||
this.handler = handler;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public int onDataRead(ChannelHandlerContext ctx, int streamId, ByteBuf data, int padding,
|
public int onDataRead(ChannelHandlerContext ctx, int streamId, ByteBuf data, int padding,
|
||||||
boolean endOfStream) throws Http2Exception {
|
boolean endOfStream) throws Http2Exception {
|
||||||
handler.onDataRead(streamId, data, endOfStream);
|
NettyClientHandler.this.onDataRead(streamId, data, endOfStream);
|
||||||
return padding;
|
return padding;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -499,23 +490,23 @@ class NettyClientHandler extends AbstractNettyHandler {
|
||||||
boolean exclusive,
|
boolean exclusive,
|
||||||
int padding,
|
int padding,
|
||||||
boolean endStream) throws Http2Exception {
|
boolean endStream) throws Http2Exception {
|
||||||
handler.onHeadersRead(streamId, headers, endStream);
|
NettyClientHandler.this.onHeadersRead(streamId, headers, endStream);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onRstStreamRead(ChannelHandlerContext ctx, int streamId, long errorCode)
|
public void onRstStreamRead(ChannelHandlerContext ctx, int streamId, long errorCode)
|
||||||
throws Http2Exception {
|
throws Http2Exception {
|
||||||
handler.onRstStreamRead(streamId, errorCode);
|
NettyClientHandler.this.onRstStreamRead(streamId, errorCode);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override public void onPingAckRead(ChannelHandlerContext ctx, ByteBuf data)
|
@Override public void onPingAckRead(ChannelHandlerContext ctx, ByteBuf data)
|
||||||
throws Http2Exception {
|
throws Http2Exception {
|
||||||
Http2Ping p = handler.ping;
|
Http2Ping p = ping;
|
||||||
if (p != null) {
|
if (p != null) {
|
||||||
long ackPayload = data.readLong();
|
long ackPayload = data.readLong();
|
||||||
if (p.payload() == ackPayload) {
|
if (p.payload() == ackPayload) {
|
||||||
p.complete();
|
p.complete();
|
||||||
handler.ping = null;
|
ping = null;
|
||||||
} else {
|
} else {
|
||||||
logger.log(Level.WARNING, String.format("Received unexpected ping ack. "
|
logger.log(Level.WARNING, String.format("Received unexpected ping ack. "
|
||||||
+ "Expecting %d, got %d", p.payload(), ackPayload));
|
+ "Expecting %d, got %d", p.payload(), ackPayload));
|
||||||
|
|
|
||||||
|
|
@ -31,7 +31,6 @@
|
||||||
|
|
||||||
package io.grpc.netty;
|
package io.grpc.netty;
|
||||||
|
|
||||||
import static com.google.common.base.Charsets.US_ASCII;
|
|
||||||
import static com.google.common.base.Preconditions.checkArgument;
|
import static com.google.common.base.Preconditions.checkArgument;
|
||||||
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;
|
||||||
|
|
@ -65,7 +64,6 @@ import io.netty.handler.codec.http2.Http2Headers;
|
||||||
import io.netty.handler.codec.http2.Http2Settings;
|
import io.netty.handler.codec.http2.Http2Settings;
|
||||||
import io.netty.handler.codec.http2.Http2Stream;
|
import io.netty.handler.codec.http2.Http2Stream;
|
||||||
import io.netty.handler.codec.http2.Http2StreamVisitor;
|
import io.netty.handler.codec.http2.Http2StreamVisitor;
|
||||||
import io.netty.util.ByteString;
|
|
||||||
import io.netty.util.ReferenceCountUtil;
|
import io.netty.util.ReferenceCountUtil;
|
||||||
|
|
||||||
import java.util.logging.Level;
|
import java.util.logging.Level;
|
||||||
|
|
@ -78,7 +76,6 @@ import javax.annotation.Nullable;
|
||||||
* the context of the Netty Channel thread.
|
* the context of the Netty Channel thread.
|
||||||
*/
|
*/
|
||||||
class NettyServerHandler extends AbstractNettyHandler {
|
class NettyServerHandler extends AbstractNettyHandler {
|
||||||
|
|
||||||
private static Logger logger = Logger.getLogger(NettyServerHandler.class.getName());
|
private static Logger logger = Logger.getLogger(NettyServerHandler.class.getName());
|
||||||
|
|
||||||
private static final Status GOAWAY_STATUS = Status.UNAVAILABLE;
|
private static final Status GOAWAY_STATUS = Status.UNAVAILABLE;
|
||||||
|
|
@ -98,21 +95,21 @@ class NettyServerHandler extends AbstractNettyHandler {
|
||||||
int flowControlWindow,
|
int flowControlWindow,
|
||||||
int maxMessageSize) {
|
int maxMessageSize) {
|
||||||
this(transportListener, new DefaultHttp2ConnectionEncoder(connection, frameWriter), frameReader,
|
this(transportListener, new DefaultHttp2ConnectionEncoder(connection, frameWriter), frameReader,
|
||||||
createInitialSettings(flowControlWindow, maxStreams), maxMessageSize);
|
createInitialSettings(flowControlWindow, maxStreams), maxMessageSize);
|
||||||
}
|
}
|
||||||
|
|
||||||
private NettyServerHandler(ServerTransportListener transportListener,
|
private NettyServerHandler(ServerTransportListener transportListener,
|
||||||
Http2ConnectionEncoder encoder,
|
Http2ConnectionEncoder encoder,
|
||||||
Http2FrameReader frameReader, Http2Settings settings,
|
Http2FrameReader frameReader, Http2Settings settings,
|
||||||
int maxMessageSize) {
|
int maxMessageSize) {
|
||||||
super(new DefaultHttp2ConnectionDecoder(encoder.connection(), encoder, frameReader,
|
super(new DefaultHttp2ConnectionDecoder(encoder.connection(), encoder, frameReader), encoder,
|
||||||
new LazyFrameListener()), encoder, settings);
|
settings);
|
||||||
checkArgument(maxMessageSize >= 0, "maxMessageSize must be >= 0");
|
checkArgument(maxMessageSize >= 0, "maxMessageSize must be >= 0");
|
||||||
this.maxMessageSize = maxMessageSize;
|
this.maxMessageSize = maxMessageSize;
|
||||||
|
|
||||||
streamKey = encoder.connection().newKey();
|
streamKey = encoder.connection().newKey();
|
||||||
this.transportListener = Preconditions.checkNotNull(transportListener, "transportListener");
|
this.transportListener = Preconditions.checkNotNull(transportListener, "transportListener");
|
||||||
initListener();
|
decoder().frameListener(new FrameListener());
|
||||||
}
|
}
|
||||||
|
|
||||||
private static Http2Settings createInitialSettings(int flowControlWindow, int maxStreams) {
|
private static Http2Settings createInitialSettings(int flowControlWindow, int maxStreams) {
|
||||||
|
|
@ -128,10 +125,6 @@ class NettyServerHandler extends AbstractNettyHandler {
|
||||||
return connectionError;
|
return connectionError;
|
||||||
}
|
}
|
||||||
|
|
||||||
private void initListener() {
|
|
||||||
((LazyFrameListener) decoder().listener()).setHandler(this);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void handlerAdded(ChannelHandlerContext ctx) throws Exception {
|
public void handlerAdded(ChannelHandlerContext ctx) throws Exception {
|
||||||
serverWriteQueue = new WriteQueue(ctx.channel());
|
serverWriteQueue = new WriteQueue(ctx.channel());
|
||||||
|
|
@ -333,12 +326,12 @@ class NettyServerHandler extends AbstractNettyHandler {
|
||||||
}
|
}
|
||||||
|
|
||||||
private void verifyContentType(int streamId, Http2Headers headers) throws Http2Exception {
|
private void verifyContentType(int streamId, Http2Headers headers) throws Http2Exception {
|
||||||
ByteString contentType = headers.get(CONTENT_TYPE_HEADER);
|
CharSequence contentType = headers.get(CONTENT_TYPE_HEADER);
|
||||||
if (contentType == null) {
|
if (contentType == null) {
|
||||||
throw Http2Exception.streamError(streamId, Http2Error.REFUSED_STREAM,
|
throw Http2Exception.streamError(streamId, Http2Error.REFUSED_STREAM,
|
||||||
"Content-Type is missing from the request");
|
"Content-Type is missing from the request");
|
||||||
}
|
}
|
||||||
String contentTypeString = contentType.toString(US_ASCII);
|
String contentTypeString = contentType.toString();
|
||||||
if (!GrpcUtil.isGrpcContentType(contentTypeString)) {
|
if (!GrpcUtil.isGrpcContentType(contentTypeString)) {
|
||||||
throw Http2Exception.streamError(streamId, Http2Error.REFUSED_STREAM,
|
throw Http2Exception.streamError(streamId, Http2Error.REFUSED_STREAM,
|
||||||
"Content-Type '%s' is not supported", contentTypeString);
|
"Content-Type '%s' is not supported", contentTypeString);
|
||||||
|
|
@ -361,16 +354,18 @@ class NettyServerHandler extends AbstractNettyHandler {
|
||||||
}
|
}
|
||||||
checkHeader(streamId, headers, CONTENT_TYPE_HEADER, CONTENT_TYPE_GRPC);
|
checkHeader(streamId, headers, CONTENT_TYPE_HEADER, CONTENT_TYPE_GRPC);
|
||||||
// Remove the leading slash of the path and get the fully qualified method name
|
// Remove the leading slash of the path and get the fully qualified method name
|
||||||
ByteString path = headers.path();
|
CharSequence path = headers.path();
|
||||||
if (path.byteAt(0) != '/') {
|
if (path.charAt(0) != '/') {
|
||||||
throw Http2Exception.streamError(streamId, Http2Error.REFUSED_STREAM,
|
throw Http2Exception.streamError(streamId, Http2Error.REFUSED_STREAM,
|
||||||
"Malformatted path: %s", path);
|
"Malformatted path: %s", path);
|
||||||
}
|
}
|
||||||
return path.toString(1, path.length());
|
return path.subSequence(1, path.length()).toString();
|
||||||
}
|
}
|
||||||
|
|
||||||
private static void checkHeader(int streamId, Http2Headers headers,
|
private static void checkHeader(int streamId,
|
||||||
ByteString header, ByteString expectedValue) throws Http2Exception {
|
Http2Headers headers,
|
||||||
|
CharSequence header,
|
||||||
|
CharSequence expectedValue) throws Http2Exception {
|
||||||
if (!expectedValue.equals(headers.get(header))) {
|
if (!expectedValue.equals(headers.get(header))) {
|
||||||
throw Http2Exception.streamError(streamId, Http2Error.REFUSED_STREAM,
|
throw Http2Exception.streamError(streamId, Http2Error.REFUSED_STREAM,
|
||||||
"Header '%s'='%s', while '%s' is expected", header, headers.get(header), expectedValue);
|
"Header '%s'='%s', while '%s' is expected", header, headers.get(header), expectedValue);
|
||||||
|
|
@ -389,17 +384,12 @@ class NettyServerHandler extends AbstractNettyHandler {
|
||||||
streamId, Http2Error.INTERNAL_ERROR, cause, cause.getMessage());
|
streamId, Http2Error.INTERNAL_ERROR, cause, cause.getMessage());
|
||||||
}
|
}
|
||||||
|
|
||||||
private static class LazyFrameListener extends Http2FrameAdapter {
|
private class FrameListener extends Http2FrameAdapter {
|
||||||
private NettyServerHandler handler;
|
|
||||||
|
|
||||||
void setHandler(NettyServerHandler handler) {
|
|
||||||
this.handler = handler;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public int onDataRead(ChannelHandlerContext ctx, int streamId, ByteBuf data, int padding,
|
public int onDataRead(ChannelHandlerContext ctx, int streamId, ByteBuf data, int padding,
|
||||||
boolean endOfStream) throws Http2Exception {
|
boolean endOfStream) throws Http2Exception {
|
||||||
handler.onDataRead(streamId, data, endOfStream);
|
NettyServerHandler.this.onDataRead(streamId, data, endOfStream);
|
||||||
return padding;
|
return padding;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -412,13 +402,13 @@ class NettyServerHandler extends AbstractNettyHandler {
|
||||||
boolean exclusive,
|
boolean exclusive,
|
||||||
int padding,
|
int padding,
|
||||||
boolean endStream) throws Http2Exception {
|
boolean endStream) throws Http2Exception {
|
||||||
handler.onHeadersRead(ctx, streamId, headers);
|
NettyServerHandler.this.onHeadersRead(ctx, streamId, headers);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onRstStreamRead(ChannelHandlerContext ctx, int streamId, long errorCode)
|
public void onRstStreamRead(ChannelHandlerContext ctx, int streamId, long errorCode)
|
||||||
throws Http2Exception {
|
throws Http2Exception {
|
||||||
handler.onRstStreamRead(streamId);
|
NettyServerHandler.this.onRstStreamRead(streamId);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -34,7 +34,7 @@ package io.grpc.netty;
|
||||||
import io.grpc.Internal;
|
import io.grpc.Internal;
|
||||||
import io.netty.channel.ChannelHandler;
|
import io.netty.channel.ChannelHandler;
|
||||||
import io.netty.handler.codec.http2.Http2ConnectionHandler;
|
import io.netty.handler.codec.http2.Http2ConnectionHandler;
|
||||||
import io.netty.util.ByteString;
|
import io.netty.util.AsciiString;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A class that provides a Netty handler to control protocol negotiation.
|
* A class that provides a Netty handler to control protocol negotiation.
|
||||||
|
|
@ -49,7 +49,7 @@ public interface ProtocolNegotiator {
|
||||||
/**
|
/**
|
||||||
* The HTTP/2 scheme to be used when sending {@code HEADERS}.
|
* The HTTP/2 scheme to be used when sending {@code HEADERS}.
|
||||||
*/
|
*/
|
||||||
ByteString scheme();
|
AsciiString scheme();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
||||||
|
|
@ -59,7 +59,7 @@ import io.netty.handler.ssl.OpenSslEngine;
|
||||||
import io.netty.handler.ssl.SslContext;
|
import io.netty.handler.ssl.SslContext;
|
||||||
import io.netty.handler.ssl.SslHandler;
|
import io.netty.handler.ssl.SslHandler;
|
||||||
import io.netty.handler.ssl.SslHandshakeCompletionEvent;
|
import io.netty.handler.ssl.SslHandshakeCompletionEvent;
|
||||||
import io.netty.util.ByteString;
|
import io.netty.util.AsciiString;
|
||||||
|
|
||||||
import java.net.URI;
|
import java.net.URI;
|
||||||
import java.util.ArrayDeque;
|
import java.util.ArrayDeque;
|
||||||
|
|
@ -108,7 +108,7 @@ public final class ProtocolNegotiators {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public ByteString scheme() {
|
public AsciiString scheme() {
|
||||||
return Utils.HTTP;
|
return Utils.HTTP;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
@ -183,7 +183,7 @@ public final class ProtocolNegotiators {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public ByteString scheme() {
|
public AsciiString scheme() {
|
||||||
return Utils.HTTPS;
|
return Utils.HTTPS;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -488,7 +488,7 @@ public final class ProtocolNegotiators {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public ByteString scheme() {
|
public AsciiString scheme() {
|
||||||
return Utils.HTTPS;
|
return Utils.HTTPS;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -527,7 +527,7 @@ public final class ProtocolNegotiators {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public ByteString scheme() {
|
public AsciiString scheme() {
|
||||||
return Utils.HTTP;
|
return Utils.HTTP;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -554,7 +554,7 @@ public final class ProtocolNegotiators {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public ByteString scheme() {
|
public AsciiString scheme() {
|
||||||
return Utils.HTTP;
|
return Utils.HTTP;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -34,6 +34,7 @@ package io.grpc.netty;
|
||||||
import static io.grpc.internal.GrpcUtil.AUTHORITY_KEY;
|
import static io.grpc.internal.GrpcUtil.AUTHORITY_KEY;
|
||||||
import static io.grpc.internal.GrpcUtil.CONTENT_TYPE_KEY;
|
import static io.grpc.internal.GrpcUtil.CONTENT_TYPE_KEY;
|
||||||
import static io.grpc.internal.GrpcUtil.USER_AGENT_KEY;
|
import static io.grpc.internal.GrpcUtil.USER_AGENT_KEY;
|
||||||
|
import static io.netty.util.CharsetUtil.US_ASCII;
|
||||||
import static io.netty.util.CharsetUtil.UTF_8;
|
import static io.netty.util.CharsetUtil.UTF_8;
|
||||||
|
|
||||||
import com.google.common.base.Preconditions;
|
import com.google.common.base.Preconditions;
|
||||||
|
|
@ -47,7 +48,7 @@ import io.netty.channel.EventLoopGroup;
|
||||||
import io.netty.channel.nio.NioEventLoopGroup;
|
import io.netty.channel.nio.NioEventLoopGroup;
|
||||||
import io.netty.handler.codec.http2.DefaultHttp2Headers;
|
import io.netty.handler.codec.http2.DefaultHttp2Headers;
|
||||||
import io.netty.handler.codec.http2.Http2Headers;
|
import io.netty.handler.codec.http2.Http2Headers;
|
||||||
import io.netty.util.ByteString;
|
import io.netty.util.AsciiString;
|
||||||
import io.netty.util.concurrent.Future;
|
import io.netty.util.concurrent.Future;
|
||||||
import io.netty.util.concurrent.GenericFutureListener;
|
import io.netty.util.concurrent.GenericFutureListener;
|
||||||
|
|
||||||
|
|
@ -62,18 +63,15 @@ import java.util.concurrent.TimeUnit;
|
||||||
*/
|
*/
|
||||||
class Utils {
|
class Utils {
|
||||||
|
|
||||||
public static final ByteString STATUS_OK = new ByteString("200".getBytes(UTF_8));
|
public static final AsciiString STATUS_OK = AsciiString.of("200");
|
||||||
public static final ByteString HTTP_METHOD = new ByteString(GrpcUtil.HTTP_METHOD.getBytes(UTF_8));
|
public static final AsciiString HTTP_METHOD = AsciiString.of(GrpcUtil.HTTP_METHOD);
|
||||||
public static final ByteString HTTPS = new ByteString("https".getBytes(UTF_8));
|
public static final AsciiString HTTPS = AsciiString.of("https");
|
||||||
public static final ByteString HTTP = new ByteString("http".getBytes(UTF_8));
|
public static final AsciiString HTTP = AsciiString.of("http");
|
||||||
public static final ByteString CONTENT_TYPE_HEADER =
|
public static final AsciiString CONTENT_TYPE_HEADER = AsciiString.of(CONTENT_TYPE_KEY.name());
|
||||||
new ByteString(CONTENT_TYPE_KEY.name().getBytes(UTF_8));
|
public static final AsciiString CONTENT_TYPE_GRPC = AsciiString.of(GrpcUtil.CONTENT_TYPE_GRPC);
|
||||||
public static final ByteString CONTENT_TYPE_GRPC =
|
public static final AsciiString TE_HEADER = AsciiString.of("te");
|
||||||
new ByteString(GrpcUtil.CONTENT_TYPE_GRPC.getBytes(UTF_8));
|
public static final AsciiString TE_TRAILERS = AsciiString.of(GrpcUtil.TE_TRAILERS);
|
||||||
public static final ByteString TE_HEADER = new ByteString("te".getBytes(UTF_8));
|
public static final AsciiString USER_AGENT = AsciiString.of(USER_AGENT_KEY.name());
|
||||||
public static final ByteString TE_TRAILERS = new ByteString(GrpcUtil.TE_TRAILERS.getBytes(UTF_8));
|
|
||||||
public static final ByteString USER_AGENT =
|
|
||||||
new ByteString(USER_AGENT_KEY.name().getBytes(UTF_8));
|
|
||||||
|
|
||||||
public static final Resource<EventLoopGroup> DEFAULT_BOSS_EVENT_LOOP_GROUP =
|
public static final Resource<EventLoopGroup> DEFAULT_BOSS_EVENT_LOOP_GROUP =
|
||||||
new DefaultEventLoopGroupResource(1, "grpc-default-boss-ELG");
|
new DefaultEventLoopGroupResource(1, "grpc-default-boss-ELG");
|
||||||
|
|
@ -90,17 +88,26 @@ class Utils {
|
||||||
// arbitrary binary data, not just ASCII.
|
// arbitrary binary data, not just ASCII.
|
||||||
byte[][] headerValues = new byte[http2Headers.size() * 2][];
|
byte[][] headerValues = new byte[http2Headers.size() * 2][];
|
||||||
int i = 0;
|
int i = 0;
|
||||||
for (Map.Entry<ByteString, ByteString> entry : http2Headers) {
|
for (Map.Entry<CharSequence, CharSequence> entry : http2Headers) {
|
||||||
headerValues[i++] = entry.getKey().array();
|
headerValues[i++] = bytes(entry.getKey());
|
||||||
headerValues[i++] = entry.getValue().array();
|
headerValues[i++] = bytes(entry.getValue());
|
||||||
}
|
}
|
||||||
return TransportFrameUtil.toRawSerializedHeaders(headerValues);
|
return TransportFrameUtil.toRawSerializedHeaders(headerValues);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private static byte[] bytes(CharSequence seq) {
|
||||||
|
if (seq instanceof AsciiString) {
|
||||||
|
// Fast path - no copy.
|
||||||
|
return ((AsciiString) seq).array();
|
||||||
|
}
|
||||||
|
// Slow path - copy.
|
||||||
|
return seq.toString().getBytes(UTF_8);
|
||||||
|
}
|
||||||
|
|
||||||
public static Http2Headers convertClientHeaders(Metadata headers,
|
public static Http2Headers convertClientHeaders(Metadata headers,
|
||||||
ByteString scheme,
|
AsciiString scheme,
|
||||||
ByteString defaultPath,
|
AsciiString defaultPath,
|
||||||
ByteString defaultAuthority) {
|
AsciiString defaultAuthority) {
|
||||||
Preconditions.checkNotNull(defaultPath, "defaultPath");
|
Preconditions.checkNotNull(defaultPath, "defaultPath");
|
||||||
Preconditions.checkNotNull(defaultAuthority, "defaultAuthority");
|
Preconditions.checkNotNull(defaultAuthority, "defaultAuthority");
|
||||||
// Add any application-provided headers first.
|
// Add any application-provided headers first.
|
||||||
|
|
@ -116,12 +123,12 @@ class Utils {
|
||||||
|
|
||||||
// Override the default authority and path if provided by the headers.
|
// Override the default authority and path if provided by the headers.
|
||||||
if (headers.containsKey(AUTHORITY_KEY)) {
|
if (headers.containsKey(AUTHORITY_KEY)) {
|
||||||
http2Headers.authority(new ByteString(headers.get(AUTHORITY_KEY).getBytes(UTF_8)));
|
http2Headers.authority(new AsciiString(headers.get(AUTHORITY_KEY).getBytes(UTF_8)));
|
||||||
}
|
}
|
||||||
|
|
||||||
// Set the User-Agent header.
|
// Set the User-Agent header.
|
||||||
String userAgent = GrpcUtil.getGrpcUserAgent("netty", headers.get(USER_AGENT_KEY));
|
String userAgent = GrpcUtil.getGrpcUserAgent("netty", headers.get(USER_AGENT_KEY));
|
||||||
http2Headers.set(USER_AGENT, new ByteString(userAgent.getBytes(UTF_8)));
|
http2Headers.set(USER_AGENT, new AsciiString(userAgent.getBytes(UTF_8)));
|
||||||
|
|
||||||
return http2Headers;
|
return http2Headers;
|
||||||
}
|
}
|
||||||
|
|
@ -151,8 +158,8 @@ class Utils {
|
||||||
Http2Headers http2Headers = new DefaultHttp2Headers();
|
Http2Headers http2Headers = new DefaultHttp2Headers();
|
||||||
byte[][] serializedHeaders = TransportFrameUtil.toHttp2Headers(headers);
|
byte[][] serializedHeaders = TransportFrameUtil.toHttp2Headers(headers);
|
||||||
for (int i = 0; i < serializedHeaders.length; i += 2) {
|
for (int i = 0; i < serializedHeaders.length; i += 2) {
|
||||||
ByteString name = new ByteString(serializedHeaders[i], false);
|
AsciiString name = new AsciiString(serializedHeaders[i], false);
|
||||||
ByteString value = new ByteString(serializedHeaders[i + 1], false);
|
AsciiString value = new AsciiString(serializedHeaders[i + 1], false);
|
||||||
http2Headers.add(name, value);
|
http2Headers.add(name, value);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -111,9 +111,10 @@ public class BufferingHttp2ConnectionEncoderTest {
|
||||||
new DefaultHttp2ConnectionEncoder(connection, writer);
|
new DefaultHttp2ConnectionEncoder(connection, writer);
|
||||||
encoder = new BufferingHttp2ConnectionEncoder(defaultEncoder);
|
encoder = new BufferingHttp2ConnectionEncoder(defaultEncoder);
|
||||||
DefaultHttp2ConnectionDecoder decoder = new DefaultHttp2ConnectionDecoder(connection, encoder,
|
DefaultHttp2ConnectionDecoder decoder = new DefaultHttp2ConnectionDecoder(connection, encoder,
|
||||||
new DefaultHttp2FrameReader(), frameListener);
|
new DefaultHttp2FrameReader());
|
||||||
|
decoder.frameListener(frameListener);
|
||||||
|
|
||||||
Http2ConnectionHandler handler = new Http2ConnectionHandler(decoder, encoder);
|
Http2ConnectionHandler handler = new Http2ConnectionHandler.Builder().build(decoder, encoder);
|
||||||
channel = new EmbeddedChannel(handler);
|
channel = new EmbeddedChannel(handler);
|
||||||
ctx = channel.pipeline().context(handler);
|
ctx = channel.pipeline().context(handler);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -55,14 +55,12 @@ import static org.mockito.Mockito.when;
|
||||||
import io.grpc.Metadata;
|
import io.grpc.Metadata;
|
||||||
import io.grpc.Status;
|
import io.grpc.Status;
|
||||||
import io.grpc.internal.ClientStreamListener;
|
import io.grpc.internal.ClientStreamListener;
|
||||||
|
|
||||||
import io.netty.buffer.ByteBuf;
|
import io.netty.buffer.ByteBuf;
|
||||||
import io.netty.buffer.Unpooled;
|
import io.netty.buffer.Unpooled;
|
||||||
import io.netty.channel.ChannelPromise;
|
import io.netty.channel.ChannelPromise;
|
||||||
import io.netty.handler.codec.http2.DefaultHttp2Headers;
|
import io.netty.handler.codec.http2.DefaultHttp2Headers;
|
||||||
import io.netty.handler.codec.http2.Http2Headers;
|
import io.netty.handler.codec.http2.Http2Headers;
|
||||||
import io.netty.util.AsciiString;
|
import io.netty.util.AsciiString;
|
||||||
import io.netty.util.ByteString;
|
|
||||||
|
|
||||||
import org.junit.Test;
|
import org.junit.Test;
|
||||||
import org.junit.runner.RunWith;
|
import org.junit.runner.RunWith;
|
||||||
|
|
@ -265,10 +263,10 @@ public class NettyClientStreamTest extends NettyStreamTestBase<NettyClientStream
|
||||||
// Set stream id to indicate it has been created
|
// Set stream id to indicate it has been created
|
||||||
stream().id(STREAM_ID);
|
stream().id(STREAM_ID);
|
||||||
Http2Headers headers = new DefaultHttp2Headers().status(STATUS_OK).set(CONTENT_TYPE_HEADER,
|
Http2Headers headers = new DefaultHttp2Headers().status(STATUS_OK).set(CONTENT_TYPE_HEADER,
|
||||||
new ByteString("application/bad", UTF_8));
|
new AsciiString("application/bad", UTF_8));
|
||||||
stream().transportHeadersReceived(headers, false);
|
stream().transportHeadersReceived(headers, false);
|
||||||
Http2Headers trailers = new DefaultHttp2Headers()
|
Http2Headers trailers = new DefaultHttp2Headers()
|
||||||
.set(new ByteString("grpc-status", UTF_8), new ByteString("0", UTF_8));
|
.set(new AsciiString("grpc-status", UTF_8), new AsciiString("0", UTF_8));
|
||||||
stream().transportHeadersReceived(trailers, true);
|
stream().transportHeadersReceived(trailers, true);
|
||||||
ArgumentCaptor<Status> captor = ArgumentCaptor.forClass(Status.class);
|
ArgumentCaptor<Status> captor = ArgumentCaptor.forClass(Status.class);
|
||||||
verify(listener).closed(captor.capture(), any(Metadata.class));
|
verify(listener).closed(captor.capture(), any(Metadata.class));
|
||||||
|
|
|
||||||
|
|
@ -80,7 +80,6 @@ import io.netty.handler.codec.http2.Http2Headers;
|
||||||
import io.netty.handler.codec.http2.Http2Settings;
|
import io.netty.handler.codec.http2.Http2Settings;
|
||||||
import io.netty.handler.codec.http2.Http2Stream;
|
import io.netty.handler.codec.http2.Http2Stream;
|
||||||
import io.netty.util.AsciiString;
|
import io.netty.util.AsciiString;
|
||||||
import io.netty.util.ByteString;
|
|
||||||
|
|
||||||
import org.junit.Before;
|
import org.junit.Before;
|
||||||
import org.junit.Ignore;
|
import org.junit.Ignore;
|
||||||
|
|
@ -278,7 +277,7 @@ public class NettyServerHandlerTest extends NettyHandlerTestBase<NettyServerHand
|
||||||
public void headersWithInvalidContentTypeShouldFail() throws Exception {
|
public void headersWithInvalidContentTypeShouldFail() throws Exception {
|
||||||
Http2Headers headers = new DefaultHttp2Headers()
|
Http2Headers headers = new DefaultHttp2Headers()
|
||||||
.method(HTTP_METHOD)
|
.method(HTTP_METHOD)
|
||||||
.set(CONTENT_TYPE_HEADER, new ByteString("application/bad", UTF_8))
|
.set(CONTENT_TYPE_HEADER, new AsciiString("application/bad", UTF_8))
|
||||||
.set(TE_HEADER, TE_TRAILERS)
|
.set(TE_HEADER, TE_TRAILERS)
|
||||||
.path(new AsciiString("/foo/bar"));
|
.path(new AsciiString("/foo/bar"));
|
||||||
ByteBuf headersFrame = headersFrame(STREAM_ID, headers);
|
ByteBuf headersFrame = headersFrame(STREAM_ID, headers);
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue