netty: Client-side support for h2c via Upgrade

Fixes #4518
This commit is contained in:
Arnout Engelen 2018-12-01 01:10:27 +01:00 committed by Eric Anderson
parent b5acbedd55
commit 3dab7aed2f
3 changed files with 27 additions and 7 deletions

View File

@ -80,6 +80,7 @@ public class TestServiceClient {
private String testCase = "empty_unary";
private boolean useTls = true;
private boolean useAlts = false;
private boolean useH2cUpgrade = false;
private String customCredentialsType;
private boolean useTestCa;
private boolean useOkHttp;
@ -121,6 +122,8 @@ public class TestServiceClient {
testCase = value;
} else if ("use_tls".equals(key)) {
useTls = Boolean.parseBoolean(value);
} else if ("use_upgrade".equals(key)) {
useH2cUpgrade = Boolean.parseBoolean(value);
} else if ("use_alts".equals(key)) {
useAlts = Boolean.parseBoolean(value);
} else if ("custom_credentials_type".equals(key)) {
@ -149,7 +152,7 @@ public class TestServiceClient {
break;
}
}
if (useAlts) {
if (useAlts || useH2cUpgrade) {
useTls = false;
}
if (usage) {
@ -167,6 +170,9 @@ public class TestServiceClient {
+ "\n --use_tls=true|false Whether to use TLS. Default " + c.useTls
+ "\n --use_alts=true|false Whether to use ALTS. Enable ALTS will disable TLS."
+ "\n Default " + c.useAlts
+ "\n --use_upgrade=true|false Whether to use the h2c Upgrade mechanism."
+ "\n Enabling h2c Upgrade will disable TLS."
+ "\n Default " + c.useH2cUpgrade
+ "\n --custom_credentials_type Custom credentials type to use. Default "
+ c.customCredentialsType
+ "\n --use_test_ca=true|false Whether to trust our fake CA. Requires --use_tls=true "
@ -371,7 +377,8 @@ public class TestServiceClient {
NettyChannelBuilder nettyBuilder =
NettyChannelBuilder.forAddress(serverHost, serverPort)
.flowControlWindow(65 * 1024)
.negotiationType(useTls ? NegotiationType.TLS : NegotiationType.PLAINTEXT)
.negotiationType(useTls ? NegotiationType.TLS :
(useH2cUpgrade ? NegotiationType.PLAINTEXT_UPGRADE : NegotiationType.PLAINTEXT))
.sslContext(sslContext);
if (serverHostOverride != null) {
nettyBuilder.overrideAuthority(serverHostOverride);

View File

@ -51,6 +51,7 @@ import io.netty.handler.codec.http2.DefaultHttp2FrameReader;
import io.netty.handler.codec.http2.DefaultHttp2FrameWriter;
import io.netty.handler.codec.http2.DefaultHttp2LocalFlowController;
import io.netty.handler.codec.http2.DefaultHttp2RemoteFlowController;
import io.netty.handler.codec.http2.Http2CodecUtil;
import io.netty.handler.codec.http2.Http2Connection;
import io.netty.handler.codec.http2.Http2ConnectionAdapter;
import io.netty.handler.codec.http2.Http2ConnectionDecoder;
@ -347,8 +348,12 @@ class NettyClientHandler extends AbstractNettyHandler {
}
private void onHeadersRead(int streamId, Http2Headers headers, boolean endStream) {
NettyClientStream.TransportState stream = clientStream(requireHttp2Stream(streamId));
stream.transportHeadersReceived(headers, endStream);
// Stream 1 is reserved for the Upgrade response, so we should ignore its headers here:
if (streamId != Http2CodecUtil.HTTP_UPGRADE_STREAM_ID) {
NettyClientStream.TransportState stream = clientStream(requireHttp2Stream(streamId));
stream.transportHeadersReceived(headers, endStream);
}
if (keepAliveManager != null) {
keepAliveManager.onDataReceived();
}

View File

@ -42,6 +42,7 @@ import io.netty.channel.ChannelPromise;
import io.netty.handler.codec.http.DefaultHttpRequest;
import io.netty.handler.codec.http.HttpClientCodec;
import io.netty.handler.codec.http.HttpClientUpgradeHandler;
import io.netty.handler.codec.http.HttpHeaderNames;
import io.netty.handler.codec.http.HttpMethod;
import io.netty.handler.codec.http.HttpVersion;
import io.netty.handler.codec.http2.Http2ClientUpgradeCodec;
@ -351,6 +352,7 @@ public final class ProtocolNegotiators {
}
static final class PlaintextUpgradeNegotiator implements ProtocolNegotiator {
@Override
public Handler newHandler(GrpcHttp2ConnectionHandler handler) {
// Register the plaintext upgrader
@ -358,7 +360,8 @@ public final class ProtocolNegotiators {
HttpClientCodec httpClientCodec = new HttpClientCodec();
final HttpClientUpgradeHandler upgrader =
new HttpClientUpgradeHandler(httpClientCodec, upgradeCodec, 1000);
return new BufferingHttp2UpgradeHandler(upgrader, handler);
return new BufferingHttp2UpgradeHandler(httpClientCodec, upgrader, handler,
handler.getAuthority());
}
@Override
@ -742,9 +745,13 @@ public final class ProtocolNegotiators {
private final GrpcHttp2ConnectionHandler grpcHandler;
BufferingHttp2UpgradeHandler(ChannelHandler handler, GrpcHttp2ConnectionHandler grpcHandler) {
super(handler);
private final String authority;
BufferingHttp2UpgradeHandler(ChannelHandler handler, ChannelHandler upgradeHandler,
GrpcHttp2ConnectionHandler grpcHandler, String authority) {
super(handler, upgradeHandler);
this.grpcHandler = grpcHandler;
this.authority = authority;
}
@Override
@ -759,6 +766,7 @@ public final class ProtocolNegotiators {
// which causes the upgrade headers to be added
DefaultHttpRequest upgradeTrigger =
new DefaultHttpRequest(HttpVersion.HTTP_1_1, HttpMethod.GET, "/");
upgradeTrigger.headers().add(HttpHeaderNames.HOST, authority);
ctx.writeAndFlush(upgradeTrigger);
super.channelActive(ctx);
}