1
0
mirror of https://github.com/square/okhttp.git synced 2026-01-12 10:23:16 +03:00

Merge pull request #2494 from yschimke/alpn_java9_support

Java 9 support for ALPN without alpn-boot
This commit is contained in:
Jesse Wilson
2016-04-21 21:57:27 -10:00

View File

@@ -28,6 +28,7 @@ import java.net.Socket;
import java.util.ArrayList;
import java.util.List;
import java.util.logging.Level;
import javax.net.ssl.SSLParameters;
import javax.net.ssl.SSLSocket;
import javax.net.ssl.SSLSocketFactory;
import javax.net.ssl.X509TrustManager;
@@ -60,6 +61,8 @@ import static okhttp3.internal.Internal.logger;
*
* Supported on OpenJDK 7 and 8 (via the JettyALPN-boot library).
*
* Supported on OpenJDK 9 via SSLParameters and SSLSocket features.
*
* <h3>Trust Manager Extraction</h3>
*
* <p>Supported on Android 2.3+ and OpenJDK 7+. There are no public APIs to recover the trust
@@ -125,6 +128,16 @@ public class Platform {
System.out.println(message);
}
public static List<String> alpnProtocolNames(List<Protocol> protocols) {
List<String> names = new ArrayList<>(protocols.size());
for (int i = 0, size = protocols.size(); i < size; i++) {
Protocol protocol = protocols.get(i);
if (protocol == Protocol.HTTP_1_0) continue; // No HTTP/1.0 for ALPN.
names.add(protocol.toString());
}
return names;
}
/** Attempt to match the host runtime to a capable Platform implementation. */
private static Platform findPlatform() {
// Attempt to find Android 2.3+ APIs.
@@ -159,6 +172,18 @@ public class Platform {
// This isn't an Android runtime.
}
// Find JDK 9 new methods
try {
Method setProtocolMethod =
SSLParameters.class.getMethod("setApplicationProtocols", String[].class);
Method getProtocolMethod = SSLSocket.class.getMethod("getApplicationProtocol");
return new Jdk9Platform(setProtocolMethod, getProtocolMethod);
} catch (NoSuchMethodException ignored) {
// pre JDK 9
}
// Find Jetty's ALPN extension for OpenJDK.
try {
String negoClassName = "org.eclipse.jetty.alpn.ALPN";
@@ -275,6 +300,54 @@ public class Platform {
}
}
/**
* OpenJDK 9+.
*/
private static final class Jdk9Platform extends Platform {
private final Method setProtocolMethod;
private final Method getProtocolMethod;
public Jdk9Platform(Method setProtocolMethod, Method getProtocolMethod) {
this.setProtocolMethod = setProtocolMethod;
this.getProtocolMethod = getProtocolMethod;
}
@Override
public void configureTlsExtensions(SSLSocket sslSocket, String hostname,
List<Protocol> protocols) {
try {
SSLParameters sslParameters = sslSocket.getSSLParameters();
List<String> names = alpnProtocolNames(protocols);
setProtocolMethod.invoke(sslParameters,
new Object[]{names.toArray(new String[names.size()])});
sslSocket.setSSLParameters(sslParameters);
} catch (IllegalAccessException | InvocationTargetException e) {
throw new AssertionError();
}
}
@Override
public String getSelectedProtocol(SSLSocket socket) {
try {
String protocol = (String) getProtocolMethod.invoke(socket);
// SSLSocket.getApplicationProtocol returns "" if application protocols values will not
// be used. Observed if you didn't specify SSLParameters.setApplicationProtocols
if (protocol == null || protocol.equals("")) {
return null;
}
return protocol;
} catch (IllegalAccessException | InvocationTargetException e) {
throw new AssertionError();
}
}
}
/**
* OpenJDK 7+ with {@code org.mortbay.jetty.alpn/alpn-boot} in the boot class path.
*/
@@ -296,12 +369,8 @@ public class Platform {
@Override public void configureTlsExtensions(
SSLSocket sslSocket, String hostname, List<Protocol> protocols) {
List<String> names = new ArrayList<>(protocols.size());
for (int i = 0, size = protocols.size(); i < size; i++) {
Protocol protocol = protocols.get(i);
if (protocol == Protocol.HTTP_1_0) continue; // No HTTP/1.0 for ALPN.
names.add(protocol.toString());
}
List<String> names = alpnProtocolNames(protocols);
try {
Object provider = Proxy.newProxyInstance(Platform.class.getClassLoader(),
new Class[] {clientProviderClass, serverProviderClass}, new JettyNegoProvider(names));