mirror of https://github.com/grpc/grpc-java.git
Add overrideAuthority to NettyChannelBuilder
Although the functionality is currently available by passing a manually-created InetAddress, that requires that the user do I/O before calling our API and does not work with naming in the future.
This commit is contained in:
parent
a6621daca2
commit
3ae18eaef1
|
|
@ -43,6 +43,8 @@ import io.grpc.Status;
|
||||||
import io.grpc.internal.SharedResourceHolder.Resource;
|
import io.grpc.internal.SharedResourceHolder.Resource;
|
||||||
|
|
||||||
import java.net.HttpURLConnection;
|
import java.net.HttpURLConnection;
|
||||||
|
import java.net.URI;
|
||||||
|
import java.net.URISyntaxException;
|
||||||
import java.util.EnumSet;
|
import java.util.EnumSet;
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
import java.util.concurrent.ExecutorService;
|
import java.util.concurrent.ExecutorService;
|
||||||
|
|
@ -295,6 +297,46 @@ public final class GrpcUtil {
|
||||||
return builder.toString();
|
return builder.toString();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Parse an authority into a URI for retrieving the host and port.
|
||||||
|
*/
|
||||||
|
public static URI authorityToUri(String authority) {
|
||||||
|
Preconditions.checkNotNull(authority, "authority");
|
||||||
|
URI uri;
|
||||||
|
try {
|
||||||
|
uri = new URI(null, authority, null, null, null);
|
||||||
|
} catch (URISyntaxException ex) {
|
||||||
|
throw new IllegalArgumentException("Invalid authority: " + authority, ex);
|
||||||
|
}
|
||||||
|
if (uri.getUserInfo() != null) {
|
||||||
|
throw new IllegalArgumentException(
|
||||||
|
"Userinfo must not be present on authority: " + authority);
|
||||||
|
}
|
||||||
|
return uri;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Verify {@code authority} is valid for use with gRPC. The syntax must be valid and it must not
|
||||||
|
* include userinfo.
|
||||||
|
*
|
||||||
|
* @return the {@code authority} provided
|
||||||
|
*/
|
||||||
|
public static String checkAuthority(String authority) {
|
||||||
|
authorityToUri(authority);
|
||||||
|
return authority;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Combine a host and port into an authority string.
|
||||||
|
*/
|
||||||
|
public static String authorityFromHostAndPort(String host, int port) {
|
||||||
|
try {
|
||||||
|
return new URI(null, null, host, port, null, null, null).getAuthority();
|
||||||
|
} catch (URISyntaxException ex) {
|
||||||
|
throw new IllegalArgumentException("Invalid host or port: " + host + " " + port, ex);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Shared executor for channels.
|
* Shared executor for channels.
|
||||||
*/
|
*/
|
||||||
|
|
|
||||||
|
|
@ -41,6 +41,7 @@ import io.grpc.internal.AbstractManagedChannelImplBuilder;
|
||||||
import io.grpc.internal.AbstractReferenceCounted;
|
import io.grpc.internal.AbstractReferenceCounted;
|
||||||
import io.grpc.internal.ClientTransport;
|
import io.grpc.internal.ClientTransport;
|
||||||
import io.grpc.internal.ClientTransportFactory;
|
import io.grpc.internal.ClientTransportFactory;
|
||||||
|
import io.grpc.internal.GrpcUtil;
|
||||||
import io.grpc.internal.SharedResourceHolder;
|
import io.grpc.internal.SharedResourceHolder;
|
||||||
import io.netty.channel.Channel;
|
import io.netty.channel.Channel;
|
||||||
import io.netty.channel.EventLoopGroup;
|
import io.netty.channel.EventLoopGroup;
|
||||||
|
|
@ -62,6 +63,7 @@ public final class NettyChannelBuilder
|
||||||
public static final int DEFAULT_FLOW_CONTROL_WINDOW = 1048576; // 1MiB
|
public static final int DEFAULT_FLOW_CONTROL_WINDOW = 1048576; // 1MiB
|
||||||
|
|
||||||
private final SocketAddress serverAddress;
|
private final SocketAddress serverAddress;
|
||||||
|
private String authority;
|
||||||
private NegotiationType negotiationType = NegotiationType.TLS;
|
private NegotiationType negotiationType = NegotiationType.TLS;
|
||||||
private Class<? extends Channel> channelType = NioSocketChannel.class;
|
private Class<? extends Channel> channelType = NioSocketChannel.class;
|
||||||
@Nullable
|
@Nullable
|
||||||
|
|
@ -71,21 +73,36 @@ public final class NettyChannelBuilder
|
||||||
private int maxMessageSize = DEFAULT_MAX_MESSAGE_SIZE;
|
private int maxMessageSize = DEFAULT_MAX_MESSAGE_SIZE;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Creates a new builder with the given server address.
|
* Creates a new builder with the given server address. This factory method is primarily intended
|
||||||
|
* for using Netty Channel types other than SocketChannel. {@link #forAddress(String, int)} should
|
||||||
|
* generally be preferred over this method, since that API permits delaying DNS lookups and
|
||||||
|
* noticing changes to DNS.
|
||||||
*/
|
*/
|
||||||
public static NettyChannelBuilder forAddress(SocketAddress serverAddress) {
|
public static NettyChannelBuilder forAddress(SocketAddress serverAddress) {
|
||||||
return new NettyChannelBuilder(serverAddress);
|
String authority;
|
||||||
|
if (serverAddress instanceof InetSocketAddress) {
|
||||||
|
InetSocketAddress address = (InetSocketAddress) serverAddress;
|
||||||
|
authority = GrpcUtil.authorityFromHostAndPort(address.getHostString(), address.getPort());
|
||||||
|
} else {
|
||||||
|
// Specialized address types are allowed to support custom Channel types so just assume their
|
||||||
|
// toString() values are valid :authority values. We defer checking validity of authority
|
||||||
|
// until buildTransportFactory() to provide the user an opportunity to override the value.
|
||||||
|
authority = serverAddress.toString();
|
||||||
|
}
|
||||||
|
return new NettyChannelBuilder(serverAddress, authority);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Creates a new builder with the given host and port.
|
* Creates a new builder with the given host and port.
|
||||||
*/
|
*/
|
||||||
public static NettyChannelBuilder forAddress(String host, int port) {
|
public static NettyChannelBuilder forAddress(String host, int port) {
|
||||||
return forAddress(new InetSocketAddress(host, port));
|
return new NettyChannelBuilder(
|
||||||
|
new InetSocketAddress(host, port), GrpcUtil.authorityFromHostAndPort(host, port));
|
||||||
}
|
}
|
||||||
|
|
||||||
private NettyChannelBuilder(SocketAddress serverAddress) {
|
private NettyChannelBuilder(SocketAddress serverAddress, String authority) {
|
||||||
this.serverAddress = serverAddress;
|
this.serverAddress = serverAddress;
|
||||||
|
this.authority = authority;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
@ -149,10 +166,23 @@ public final class NettyChannelBuilder
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Overrides the authority used with TLS and HTTP virtual hosting. It does not change what host is
|
||||||
|
* actually connected to. Is commonly in the form {@code host:port}.
|
||||||
|
*
|
||||||
|
* <p>Should only used by tests.
|
||||||
|
*/
|
||||||
|
public NettyChannelBuilder overrideAuthority(String authority) {
|
||||||
|
this.authority = GrpcUtil.checkAuthority(authority);
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected ClientTransportFactory buildTransportFactory() {
|
protected ClientTransportFactory buildTransportFactory() {
|
||||||
return new NettyTransportFactory(serverAddress, channelType, eventLoopGroup, flowControlWindow,
|
// Check authority, since non-inet ServerAddresses delay the authority check.
|
||||||
createProtocolNegotiator(), maxMessageSize);
|
GrpcUtil.checkAuthority(authority);
|
||||||
|
return new NettyTransportFactory(serverAddress, authority, channelType, eventLoopGroup,
|
||||||
|
flowControlWindow, createProtocolNegotiator(), maxMessageSize);
|
||||||
}
|
}
|
||||||
|
|
||||||
private ProtocolNegotiator createProtocolNegotiator() {
|
private ProtocolNegotiator createProtocolNegotiator() {
|
||||||
|
|
@ -163,9 +193,6 @@ public final class NettyChannelBuilder
|
||||||
case PLAINTEXT_UPGRADE:
|
case PLAINTEXT_UPGRADE:
|
||||||
return ProtocolNegotiators.plaintextUpgrade();
|
return ProtocolNegotiators.plaintextUpgrade();
|
||||||
case TLS:
|
case TLS:
|
||||||
if (!(serverAddress instanceof InetSocketAddress)) {
|
|
||||||
throw new IllegalStateException("TLS not supported for non-internet socket types");
|
|
||||||
}
|
|
||||||
if (sslContext == null) {
|
if (sslContext == null) {
|
||||||
try {
|
try {
|
||||||
sslContext = GrpcSslContexts.forClient().build();
|
sslContext = GrpcSslContexts.forClient().build();
|
||||||
|
|
@ -173,7 +200,7 @@ public final class NettyChannelBuilder
|
||||||
throw new RuntimeException(ex);
|
throw new RuntimeException(ex);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return ProtocolNegotiators.tls(sslContext, (InetSocketAddress) serverAddress);
|
return ProtocolNegotiators.tls(sslContext, authority);
|
||||||
default:
|
default:
|
||||||
throw new IllegalArgumentException("Unsupported negotiationType: " + negotiationType);
|
throw new IllegalArgumentException("Unsupported negotiationType: " + negotiationType);
|
||||||
}
|
}
|
||||||
|
|
@ -191,6 +218,7 @@ public final class NettyChannelBuilder
|
||||||
private final String authority;
|
private final String authority;
|
||||||
|
|
||||||
private NettyTransportFactory(SocketAddress serverAddress,
|
private NettyTransportFactory(SocketAddress serverAddress,
|
||||||
|
String authority,
|
||||||
Class<? extends Channel> channelType,
|
Class<? extends Channel> channelType,
|
||||||
EventLoopGroup group,
|
EventLoopGroup group,
|
||||||
int flowControlWindow,
|
int flowControlWindow,
|
||||||
|
|
@ -201,14 +229,7 @@ public final class NettyChannelBuilder
|
||||||
this.flowControlWindow = flowControlWindow;
|
this.flowControlWindow = flowControlWindow;
|
||||||
this.negotiator = negotiator;
|
this.negotiator = negotiator;
|
||||||
this.maxMessageSize = maxMessageSize;
|
this.maxMessageSize = maxMessageSize;
|
||||||
if (serverAddress instanceof InetSocketAddress) {
|
this.authority = authority;
|
||||||
InetSocketAddress address = (InetSocketAddress) serverAddress;
|
|
||||||
this.authority = address.getHostString() + ":" + address.getPort();
|
|
||||||
} else {
|
|
||||||
// Specialized address types are allowed to support custom Channel types so just assume
|
|
||||||
// their toString() values are valid :authority values
|
|
||||||
this.authority = serverAddress.toString();
|
|
||||||
}
|
|
||||||
|
|
||||||
usingSharedGroup = group == null;
|
usingSharedGroup = group == null;
|
||||||
if (usingSharedGroup) {
|
if (usingSharedGroup) {
|
||||||
|
|
|
||||||
|
|
@ -34,6 +34,7 @@ package io.grpc.netty;
|
||||||
import com.google.common.base.Preconditions;
|
import com.google.common.base.Preconditions;
|
||||||
|
|
||||||
import io.grpc.Status;
|
import io.grpc.Status;
|
||||||
|
import io.grpc.internal.GrpcUtil;
|
||||||
import io.netty.channel.ChannelDuplexHandler;
|
import io.netty.channel.ChannelDuplexHandler;
|
||||||
import io.netty.channel.ChannelHandler;
|
import io.netty.channel.ChannelHandler;
|
||||||
import io.netty.channel.ChannelHandlerAdapter;
|
import io.netty.channel.ChannelHandlerAdapter;
|
||||||
|
|
@ -54,7 +55,7 @@ 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.ByteString;
|
||||||
|
|
||||||
import java.net.InetSocketAddress;
|
import java.net.URI;
|
||||||
import java.util.ArrayDeque;
|
import java.util.ArrayDeque;
|
||||||
import java.util.Arrays;
|
import java.util.Arrays;
|
||||||
import java.util.Queue;
|
import java.util.Queue;
|
||||||
|
|
@ -130,9 +131,9 @@ public final class ProtocolNegotiators {
|
||||||
* may happen immediately, even before the TLS Handshake is complete.
|
* may happen immediately, even before the TLS Handshake is complete.
|
||||||
*/
|
*/
|
||||||
public static ProtocolNegotiator tls(final SslContext sslContext,
|
public static ProtocolNegotiator tls(final SslContext sslContext,
|
||||||
final InetSocketAddress inetAddress) {
|
String authority) {
|
||||||
Preconditions.checkNotNull(sslContext, "sslContext");
|
Preconditions.checkNotNull(sslContext, "sslContext");
|
||||||
Preconditions.checkNotNull(inetAddress, "inetAddress");
|
final URI uri = GrpcUtil.authorityToUri(Preconditions.checkNotNull(authority, "authority"));
|
||||||
|
|
||||||
return new ProtocolNegotiator() {
|
return new ProtocolNegotiator() {
|
||||||
@Override
|
@Override
|
||||||
|
|
@ -140,8 +141,7 @@ public final class ProtocolNegotiators {
|
||||||
ChannelHandler sslBootstrap = new ChannelHandlerAdapter() {
|
ChannelHandler sslBootstrap = new ChannelHandlerAdapter() {
|
||||||
@Override
|
@Override
|
||||||
public void handlerAdded(ChannelHandlerContext ctx) throws Exception {
|
public void handlerAdded(ChannelHandlerContext ctx) throws Exception {
|
||||||
SSLEngine sslEngine = sslContext.newEngine(ctx.alloc(),
|
SSLEngine sslEngine = sslContext.newEngine(ctx.alloc(), uri.getHost(), uri.getPort());
|
||||||
inetAddress.getHostName(), inetAddress.getPort());
|
|
||||||
SSLParameters sslParams = new SSLParameters();
|
SSLParameters sslParams = new SSLParameters();
|
||||||
sslParams.setEndpointIdentificationAlgorithm("HTTPS");
|
sslParams.setEndpointIdentificationAlgorithm("HTTPS");
|
||||||
sslEngine.setSSLParameters(sslParams);
|
sslEngine.setSSLParameters(sslParams);
|
||||||
|
|
|
||||||
|
|
@ -96,6 +96,7 @@ public class NettyClientTransportTest {
|
||||||
private final List<NettyClientTransport> transports = new ArrayList<NettyClientTransport>();
|
private final List<NettyClientTransport> transports = new ArrayList<NettyClientTransport>();
|
||||||
private NioEventLoopGroup group;
|
private NioEventLoopGroup group;
|
||||||
private InetSocketAddress address;
|
private InetSocketAddress address;
|
||||||
|
private String authority;
|
||||||
private NettyServer server;
|
private NettyServer server;
|
||||||
private EchoServerListener serverListener = new EchoServerListener();
|
private EchoServerListener serverListener = new EchoServerListener();
|
||||||
|
|
||||||
|
|
@ -105,6 +106,7 @@ public class NettyClientTransportTest {
|
||||||
|
|
||||||
group = new NioEventLoopGroup(1);
|
group = new NioEventLoopGroup(1);
|
||||||
address = TestUtils.testServerAddress(TestUtils.pickUnusedPort());
|
address = TestUtils.testServerAddress(TestUtils.pickUnusedPort());
|
||||||
|
authority = GrpcUtil.authorityFromHostAndPort(address.getHostString(), address.getPort());
|
||||||
}
|
}
|
||||||
|
|
||||||
@After
|
@After
|
||||||
|
|
@ -236,7 +238,7 @@ public class NettyClientTransportTest {
|
||||||
File clientCert = TestUtils.loadCert("ca.pem");
|
File clientCert = TestUtils.loadCert("ca.pem");
|
||||||
SslContext clientContext = GrpcSslContexts.forClient().trustManager(clientCert)
|
SslContext clientContext = GrpcSslContexts.forClient().trustManager(clientCert)
|
||||||
.ciphers(TestUtils.preferredTestCiphers(), SupportedCipherSuiteFilter.INSTANCE).build();
|
.ciphers(TestUtils.preferredTestCiphers(), SupportedCipherSuiteFilter.INSTANCE).build();
|
||||||
return ProtocolNegotiators.tls(clientContext, address);
|
return ProtocolNegotiators.tls(clientContext, authority);
|
||||||
}
|
}
|
||||||
|
|
||||||
private NettyClientTransport newTransport(ProtocolNegotiator negotiator) {
|
private NettyClientTransport newTransport(ProtocolNegotiator negotiator) {
|
||||||
|
|
@ -245,8 +247,7 @@ public class NettyClientTransportTest {
|
||||||
|
|
||||||
private NettyClientTransport newTransport(ProtocolNegotiator negotiator, int maxMsgSize) {
|
private NettyClientTransport newTransport(ProtocolNegotiator negotiator, int maxMsgSize) {
|
||||||
NettyClientTransport transport = new NettyClientTransport(address, NioSocketChannel.class,
|
NettyClientTransport transport = new NettyClientTransport(address, NioSocketChannel.class,
|
||||||
group, negotiator, DEFAULT_WINDOW_SIZE, maxMsgSize,
|
group, negotiator, DEFAULT_WINDOW_SIZE, maxMsgSize, authority);
|
||||||
address.getHostString() + ":" + address.getPort());
|
|
||||||
transports.add(transport);
|
transports.add(transport);
|
||||||
return transport;
|
return transport;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue