aboutsummaryrefslogtreecommitdiff
path: root/okhttp
diff options
context:
space:
mode:
authorEric Gribkoff <ericgribkoff@google.com>2018-03-20 17:29:24 -0700
committerGitHub <noreply@github.com>2018-03-20 17:29:24 -0700
commit52fedb624dfee7b6950eb379bed78b6c2e7ad309 (patch)
treeea81247644ea429fdc79414f9b0e337bed9919ec /okhttp
parent524117247530b847157b72d58a25372b87100e2a (diff)
downloadgrpc-grpc-java-52fedb624dfee7b6950eb379bed78b6c2e7ad309.tar.gz
okhttp: support JDK9 ALPN (#4136)
Diffstat (limited to 'okhttp')
-rw-r--r--okhttp/src/test/java/io/grpc/okhttp/OkHttpProtocolNegotiatorTest.java4
-rw-r--r--okhttp/third_party/okhttp/java/io/grpc/okhttp/internal/Platform.java105
2 files changed, 108 insertions, 1 deletions
diff --git a/okhttp/src/test/java/io/grpc/okhttp/OkHttpProtocolNegotiatorTest.java b/okhttp/src/test/java/io/grpc/okhttp/OkHttpProtocolNegotiatorTest.java
index 2ac31ea51..4e836eec5 100644
--- a/okhttp/src/test/java/io/grpc/okhttp/OkHttpProtocolNegotiatorTest.java
+++ b/okhttp/src/test/java/io/grpc/okhttp/OkHttpProtocolNegotiatorTest.java
@@ -19,6 +19,7 @@ package io.grpc.okhttp;
import static com.google.common.base.Charsets.UTF_8;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNotNull;
+import static org.mockito.Mockito.doReturn;
import static org.mockito.Mockito.doThrow;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.verify;
@@ -32,6 +33,7 @@ import io.grpc.okhttp.internal.Platform.TlsExtensionType;
import io.grpc.okhttp.internal.Protocol;
import java.io.IOException;
import javax.net.ssl.HandshakeCompletedListener;
+import javax.net.ssl.SSLParameters;
import javax.net.ssl.SSLSession;
import javax.net.ssl.SSLSocket;
import org.junit.Rule;
@@ -110,7 +112,9 @@ public class OkHttpProtocolNegotiatorTest {
@Test
public void negotiate_handshakeFails() throws IOException {
+ SSLParameters parameters = new SSLParameters();
OkHttpProtocolNegotiator negotiator = OkHttpProtocolNegotiator.get();
+ doReturn(parameters).when(sock).getSSLParameters();
doThrow(new IOException()).when(sock).startHandshake();
thrown.expect(IOException.class);
diff --git a/okhttp/third_party/okhttp/java/io/grpc/okhttp/internal/Platform.java b/okhttp/third_party/okhttp/java/io/grpc/okhttp/internal/Platform.java
index fb040d01a..d6f88ba0e 100644
--- a/okhttp/third_party/okhttp/java/io/grpc/okhttp/internal/Platform.java
+++ b/okhttp/third_party/okhttp/java/io/grpc/okhttp/internal/Platform.java
@@ -29,7 +29,11 @@ import java.lang.reflect.Proxy;
import java.net.InetSocketAddress;
import java.net.Socket;
import java.net.SocketException;
+import java.security.AccessController;
+import java.security.KeyManagementException;
import java.security.NoSuchAlgorithmException;
+import java.security.PrivilegedActionException;
+import java.security.PrivilegedExceptionAction;
import java.security.Provider;
import java.security.Security;
import java.util.ArrayList;
@@ -37,6 +41,8 @@ import java.util.List;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.net.ssl.SSLContext;
+import javax.net.ssl.SSLEngine;
+import javax.net.ssl.SSLParameters;
import javax.net.ssl.SSLSocket;
import okio.Buffer;
@@ -44,19 +50,25 @@ import okio.Buffer;
* Access to platform-specific features.
*
* <h3>Server name indication (SNI)</h3>
+ *
* Supported on Android 2.3+.
*
* <h3>Session Tickets</h3>
+ *
* Supported on Android 2.3+.
*
* <h3>Android Traffic Stats (Socket Tagging)</h3>
+ *
* Supported on Android 4.0+.
*
* <h3>ALPN (Application Layer Protocol Negotiation)</h3>
+ *
* Supported on Android 5.0+. The APIs were present in Android 4.4, but that implementation was
* unstable.
*
- * Supported on OpenJDK 7 and 8 (via the JettyALPN-boot library).
+ * <p>Supported on OpenJDK 9+.
+ *
+ * <p>Supported on OpenJDK 7 and 8 (via the JettyALPN-boot library).
*/
public class Platform {
public static final Logger logger = Logger.getLogger(Platform.class.getName());
@@ -199,6 +211,47 @@ public class Platform {
throw new RuntimeException(nsae);
}
+ // Find JDK9+ ALPN support
+ try {
+ // getApplicationProtocol() may throw UnsupportedOperationException, so first construct a
+ // dummy SSLEngine and verify the method does not throw.
+ SSLContext context = SSLContext.getInstance("TLS", sslProvider);
+ context.init(null, null, null);
+ SSLEngine engine = context.createSSLEngine();
+ Method getEngineApplicationProtocol =
+ AccessController.doPrivileged(
+ new PrivilegedExceptionAction<Method>() {
+ @Override
+ public Method run() throws Exception {
+ return SSLEngine.class.getMethod("getApplicationProtocol");
+ }
+ });
+ getEngineApplicationProtocol.invoke(engine);
+
+ Method setApplicationProtocols =
+ AccessController.doPrivileged(
+ new PrivilegedExceptionAction<Method>() {
+ @Override
+ public Method run() throws Exception {
+ return SSLParameters.class.getMethod("setApplicationProtocols", String[].class);
+ }
+ });
+ Method getApplicationProtocol =
+ AccessController.doPrivileged(
+ new PrivilegedExceptionAction<Method>() {
+ @Override
+ public Method run() throws Exception {
+ return SSLSocket.class.getMethod("getApplicationProtocol");
+ }
+ });
+ return new JdkAlpnPlatform(sslProvider, setApplicationProtocols, getApplicationProtocol);
+ } catch (NoSuchAlgorithmException ignored) {
+ } catch (KeyManagementException ignored) {
+ } catch (PrivilegedActionException ignored) {
+ } catch (IllegalAccessException ignored) {
+ } catch (InvocationTargetException ignored) {
+ }
+
// Find Jetty's ALPN extension for OpenJDK.
try {
String negoClassName = "org.eclipse.jetty.alpn.ALPN";
@@ -375,6 +428,56 @@ public class Platform {
}
}
+ /** OpenJDK 9+. */
+ private static class JdkAlpnPlatform extends Platform {
+ private final Method setApplicationProtocols;
+ private final Method getApplicationProtocol;
+
+ private JdkAlpnPlatform(
+ Provider provider, Method setApplicationProtocols, Method getApplicationProtocol) {
+ super(provider);
+ this.setApplicationProtocols = setApplicationProtocols;
+ this.getApplicationProtocol = getApplicationProtocol;
+ }
+
+ @Override
+ public TlsExtensionType getTlsExtensionType() {
+ return TlsExtensionType.ALPN_AND_NPN;
+ }
+
+ @Override
+ public void configureTlsExtensions(
+ SSLSocket sslSocket, String hostname, List<Protocol> protocols) {
+ SSLParameters parameters = sslSocket.getSSLParameters();
+ List<String> names = new ArrayList<String>(protocols.size());
+ for (Protocol protocol : protocols) {
+ if (protocol == Protocol.HTTP_1_0) continue; // No HTTP/1.0 for ALPN.
+ names.add(protocol.toString());
+ }
+ try {
+ setApplicationProtocols.invoke(
+ parameters, new Object[] {names.toArray(new String[names.size()])});
+ } catch (IllegalAccessException e) {
+ throw new RuntimeException(e);
+ } catch (InvocationTargetException e) {
+ throw new RuntimeException(e);
+ }
+ sslSocket.setSSLParameters(parameters);
+ }
+
+ /** Returns the negotiated protocol, or null if no protocol was negotiated. */
+ @Override
+ public String getSelectedProtocol(SSLSocket socket) {
+ try {
+ return (String) getApplicationProtocol.invoke(socket);
+ } catch (IllegalAccessException e) {
+ throw new RuntimeException(e);
+ } catch (InvocationTargetException e) {
+ throw new RuntimeException(e);
+ }
+ }
+ }
+
/**
* OpenJDK 7+ with {@code org.mortbay.jetty.alpn/alpn-boot} in the boot class path.
*/