diff --git a/netty/src/main/java/io/grpc/netty/GrpcSslContexts.java b/netty/src/main/java/io/grpc/netty/GrpcSslContexts.java index 96a1bf6f451..94f8d274a4d 100644 --- a/netty/src/main/java/io/grpc/netty/GrpcSslContexts.java +++ b/netty/src/main/java/io/grpc/netty/GrpcSslContexts.java @@ -156,6 +156,9 @@ private static ApplicationProtocolConfig selectApplicationProtocolConfig(SslProv if (JettyTlsUtil.isJettyNpnConfigured()) { return NPN; } + if (JettyTlsUtil.isJava9AlpnAvailable()) { + return ALPN; + } // Use the ALPN cause since it is prefered. throw new IllegalArgumentException( "Jetty ALPN/NPN has not been properly configured.", diff --git a/netty/src/main/java/io/grpc/netty/JettyTlsUtil.java b/netty/src/main/java/io/grpc/netty/JettyTlsUtil.java index 53bdc6e9f38..c83c55c38c5 100644 --- a/netty/src/main/java/io/grpc/netty/JettyTlsUtil.java +++ b/netty/src/main/java/io/grpc/netty/JettyTlsUtil.java @@ -16,6 +16,12 @@ package io.grpc.netty; +import java.lang.reflect.Method; +import java.security.AccessController; +import java.security.PrivilegedExceptionAction; +import javax.net.ssl.SSLContext; +import javax.net.ssl.SSLEngine; + /** * Utility class for determining support for Jetty TLS ALPN/NPN. */ @@ -26,6 +32,30 @@ private JettyTlsUtil() { private static Throwable jettyAlpnUnavailabilityCause; private static Throwable jettyNpnUnavailabilityCause; + private static class Java9AlpnUnavailabilityCauseHolder { + + static final Throwable cause = checkAlpnAvailability(); + + static Throwable checkAlpnAvailability() { + try { + SSLContext context = SSLContext.getInstance("TLS"); + context.init(null, null, null); + SSLEngine engine = context.createSSLEngine(); + Method getApplicationProtocol = + AccessController.doPrivileged(new PrivilegedExceptionAction() { + @Override + public Method run() throws Exception { + return SSLEngine.class.getMethod("getApplicationProtocol"); + } + }); + getApplicationProtocol.invoke(engine); + return null; + } catch (Throwable t) { + return t; + } + } + } + /** * Indicates whether or not the Jetty ALPN jar is installed in the boot classloader. */ @@ -67,4 +97,15 @@ static synchronized Throwable getJettyNpnUnavailabilityCause() { } return jettyNpnUnavailabilityCause; } + + /** + * Indicates whether Java 9 ALPN is available. + */ + static boolean isJava9AlpnAvailable() { + return getJava9AlpnUnavailabilityCause() == null; + } + + static Throwable getJava9AlpnUnavailabilityCause() { + return Java9AlpnUnavailabilityCauseHolder.cause; + } } diff --git a/netty/src/main/java/io/grpc/netty/ProtocolNegotiators.java b/netty/src/main/java/io/grpc/netty/ProtocolNegotiators.java index c7dc2f3e66c..52c9a717424 100644 --- a/netty/src/main/java/io/grpc/netty/ProtocolNegotiators.java +++ b/netty/src/main/java/io/grpc/netty/ProtocolNegotiators.java @@ -304,7 +304,7 @@ public Handler newHandler(GrpcHttp2ConnectionHandler handler) { @Override public void handlerAdded(ChannelHandlerContext ctx) throws Exception { SSLEngine sslEngine = sslContext.newEngine(ctx.alloc(), host, port); - SSLParameters sslParams = new SSLParameters(); + SSLParameters sslParams = sslEngine.getSSLParameters(); sslParams.setEndpointIdentificationAlgorithm("HTTPS"); sslEngine.setSSLParameters(sslParams); ctx.pipeline().replace(this, null, new SslHandler(sslEngine, false)); @@ -374,6 +374,8 @@ static void logSslEngineDetails(Level level, ChannelHandlerContext ctx, String m builder.append(" Jetty ALPN"); } else if (JettyTlsUtil.isJettyNpnConfigured()) { builder.append(" Jetty NPN"); + } else if (JettyTlsUtil.isJava9AlpnAvailable()) { + builder.append(" JDK9 ALPN"); } builder.append("\n TLS Protocol: "); builder.append(engine.getSession().getProtocol());