12231db3e6bb54447a9b14cf004a6cb03c373651cjwilson/* 22231db3e6bb54447a9b14cf004a6cb03c373651cjwilson * Copyright (C) 2012 Square, Inc. 32231db3e6bb54447a9b14cf004a6cb03c373651cjwilson * Copyright (C) 2012 The Android Open Source Project 42231db3e6bb54447a9b14cf004a6cb03c373651cjwilson * 52231db3e6bb54447a9b14cf004a6cb03c373651cjwilson * Licensed under the Apache License, Version 2.0 (the "License"); 62231db3e6bb54447a9b14cf004a6cb03c373651cjwilson * you may not use this file except in compliance with the License. 72231db3e6bb54447a9b14cf004a6cb03c373651cjwilson * You may obtain a copy of the License at 82231db3e6bb54447a9b14cf004a6cb03c373651cjwilson * 92231db3e6bb54447a9b14cf004a6cb03c373651cjwilson * http://www.apache.org/licenses/LICENSE-2.0 102231db3e6bb54447a9b14cf004a6cb03c373651cjwilson * 112231db3e6bb54447a9b14cf004a6cb03c373651cjwilson * Unless required by applicable law or agreed to in writing, software 122231db3e6bb54447a9b14cf004a6cb03c373651cjwilson * distributed under the License is distributed on an "AS IS" BASIS, 132231db3e6bb54447a9b14cf004a6cb03c373651cjwilson * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 142231db3e6bb54447a9b14cf004a6cb03c373651cjwilson * See the License for the specific language governing permissions and 152231db3e6bb54447a9b14cf004a6cb03c373651cjwilson * limitations under the License. 162231db3e6bb54447a9b14cf004a6cb03c373651cjwilson */ 172231db3e6bb54447a9b14cf004a6cb03c373651cjwilsonpackage com.squareup.okhttp.internal; 182231db3e6bb54447a9b14cf004a6cb03c373651cjwilson 192231db3e6bb54447a9b14cf004a6cb03c373651cjwilsonimport com.squareup.okhttp.OkHttpClient; 202231db3e6bb54447a9b14cf004a6cb03c373651cjwilsonimport java.io.OutputStream; 212231db3e6bb54447a9b14cf004a6cb03c373651cjwilsonimport java.io.UnsupportedEncodingException; 222231db3e6bb54447a9b14cf004a6cb03c373651cjwilsonimport java.lang.reflect.Constructor; 232231db3e6bb54447a9b14cf004a6cb03c373651cjwilsonimport java.lang.reflect.InvocationHandler; 242231db3e6bb54447a9b14cf004a6cb03c373651cjwilsonimport java.lang.reflect.InvocationTargetException; 252231db3e6bb54447a9b14cf004a6cb03c373651cjwilsonimport java.lang.reflect.Method; 262231db3e6bb54447a9b14cf004a6cb03c373651cjwilsonimport java.lang.reflect.Proxy; 272231db3e6bb54447a9b14cf004a6cb03c373651cjwilsonimport java.net.Socket; 282231db3e6bb54447a9b14cf004a6cb03c373651cjwilsonimport java.net.SocketException; 292231db3e6bb54447a9b14cf004a6cb03c373651cjwilsonimport java.net.URI; 302231db3e6bb54447a9b14cf004a6cb03c373651cjwilsonimport java.net.URISyntaxException; 312231db3e6bb54447a9b14cf004a6cb03c373651cjwilsonimport java.net.URL; 322231db3e6bb54447a9b14cf004a6cb03c373651cjwilsonimport java.util.ArrayList; 332231db3e6bb54447a9b14cf004a6cb03c373651cjwilsonimport java.util.List; 342231db3e6bb54447a9b14cf004a6cb03c373651cjwilsonimport java.util.logging.Level; 352231db3e6bb54447a9b14cf004a6cb03c373651cjwilsonimport java.util.logging.Logger; 362231db3e6bb54447a9b14cf004a6cb03c373651cjwilsonimport java.util.zip.Deflater; 372231db3e6bb54447a9b14cf004a6cb03c373651cjwilsonimport java.util.zip.DeflaterOutputStream; 382231db3e6bb54447a9b14cf004a6cb03c373651cjwilsonimport javax.net.ssl.SSLSocket; 392231db3e6bb54447a9b14cf004a6cb03c373651cjwilson 402231db3e6bb54447a9b14cf004a6cb03c373651cjwilson/** 412231db3e6bb54447a9b14cf004a6cb03c373651cjwilson * Access to Platform-specific features necessary for SPDY and advanced TLS. 422231db3e6bb54447a9b14cf004a6cb03c373651cjwilson * 432231db3e6bb54447a9b14cf004a6cb03c373651cjwilson * <h3>SPDY</h3> 442231db3e6bb54447a9b14cf004a6cb03c373651cjwilson * SPDY requires a TLS extension called NPN (Next Protocol Negotiation) that's 452231db3e6bb54447a9b14cf004a6cb03c373651cjwilson * available in Android 4.1+ and OpenJDK 7+ (with the npn-boot extension). It 462231db3e6bb54447a9b14cf004a6cb03c373651cjwilson * also requires a recent version of {@code DeflaterOutputStream} that is 472231db3e6bb54447a9b14cf004a6cb03c373651cjwilson * public API in Java 7 and callable via reflection in Android 4.1+. 482231db3e6bb54447a9b14cf004a6cb03c373651cjwilson */ 492231db3e6bb54447a9b14cf004a6cb03c373651cjwilsonpublic class Platform { 5054cf3446000fdcf88a9e62724f7deb0282e98da1jwilson private static final Platform PLATFORM = findPlatform(); 512231db3e6bb54447a9b14cf004a6cb03c373651cjwilson 5254cf3446000fdcf88a9e62724f7deb0282e98da1jwilson private Constructor<DeflaterOutputStream> deflaterConstructor; 532231db3e6bb54447a9b14cf004a6cb03c373651cjwilson 5454cf3446000fdcf88a9e62724f7deb0282e98da1jwilson public static Platform get() { 5554cf3446000fdcf88a9e62724f7deb0282e98da1jwilson return PLATFORM; 5654cf3446000fdcf88a9e62724f7deb0282e98da1jwilson } 572231db3e6bb54447a9b14cf004a6cb03c373651cjwilson 5854cf3446000fdcf88a9e62724f7deb0282e98da1jwilson public void logW(String warning) { 5954cf3446000fdcf88a9e62724f7deb0282e98da1jwilson System.out.println(warning); 6054cf3446000fdcf88a9e62724f7deb0282e98da1jwilson } 612231db3e6bb54447a9b14cf004a6cb03c373651cjwilson 6254cf3446000fdcf88a9e62724f7deb0282e98da1jwilson public void tagSocket(Socket socket) throws SocketException { 6354cf3446000fdcf88a9e62724f7deb0282e98da1jwilson } 642231db3e6bb54447a9b14cf004a6cb03c373651cjwilson 6554cf3446000fdcf88a9e62724f7deb0282e98da1jwilson public void untagSocket(Socket socket) throws SocketException { 6654cf3446000fdcf88a9e62724f7deb0282e98da1jwilson } 672231db3e6bb54447a9b14cf004a6cb03c373651cjwilson 6854cf3446000fdcf88a9e62724f7deb0282e98da1jwilson public URI toUriLenient(URL url) throws URISyntaxException { 6954cf3446000fdcf88a9e62724f7deb0282e98da1jwilson return url.toURI(); // this isn't as good as the built-in toUriLenient 7054cf3446000fdcf88a9e62724f7deb0282e98da1jwilson } 7154cf3446000fdcf88a9e62724f7deb0282e98da1jwilson 7254cf3446000fdcf88a9e62724f7deb0282e98da1jwilson /** 7354cf3446000fdcf88a9e62724f7deb0282e98da1jwilson * Attempt a TLS connection with useful extensions enabled. This mode 7454cf3446000fdcf88a9e62724f7deb0282e98da1jwilson * supports more features, but is less likely to be compatible with older 7554cf3446000fdcf88a9e62724f7deb0282e98da1jwilson * HTTPS servers. 7654cf3446000fdcf88a9e62724f7deb0282e98da1jwilson */ 7754cf3446000fdcf88a9e62724f7deb0282e98da1jwilson public void enableTlsExtensions(SSLSocket socket, String uriHost) { 7854cf3446000fdcf88a9e62724f7deb0282e98da1jwilson } 7954cf3446000fdcf88a9e62724f7deb0282e98da1jwilson 8054cf3446000fdcf88a9e62724f7deb0282e98da1jwilson /** 8154cf3446000fdcf88a9e62724f7deb0282e98da1jwilson * Attempt a secure connection with basic functionality to maximize 8254cf3446000fdcf88a9e62724f7deb0282e98da1jwilson * compatibility. Currently this uses SSL 3.0. 8354cf3446000fdcf88a9e62724f7deb0282e98da1jwilson */ 8454cf3446000fdcf88a9e62724f7deb0282e98da1jwilson public void supportTlsIntolerantServer(SSLSocket socket) { 8554cf3446000fdcf88a9e62724f7deb0282e98da1jwilson socket.setEnabledProtocols(new String[] {"SSLv3"}); 8654cf3446000fdcf88a9e62724f7deb0282e98da1jwilson } 8754cf3446000fdcf88a9e62724f7deb0282e98da1jwilson 8854cf3446000fdcf88a9e62724f7deb0282e98da1jwilson /** Returns the negotiated protocol, or null if no protocol was negotiated. */ 8954cf3446000fdcf88a9e62724f7deb0282e98da1jwilson public byte[] getNpnSelectedProtocol(SSLSocket socket) { 9054cf3446000fdcf88a9e62724f7deb0282e98da1jwilson return null; 9154cf3446000fdcf88a9e62724f7deb0282e98da1jwilson } 9254cf3446000fdcf88a9e62724f7deb0282e98da1jwilson 9354cf3446000fdcf88a9e62724f7deb0282e98da1jwilson /** 9454cf3446000fdcf88a9e62724f7deb0282e98da1jwilson * Sets client-supported protocols on a socket to send to a server. The 9554cf3446000fdcf88a9e62724f7deb0282e98da1jwilson * protocols are only sent if the socket implementation supports NPN. 9654cf3446000fdcf88a9e62724f7deb0282e98da1jwilson */ 9754cf3446000fdcf88a9e62724f7deb0282e98da1jwilson public void setNpnProtocols(SSLSocket socket, byte[] npnProtocols) { 9854cf3446000fdcf88a9e62724f7deb0282e98da1jwilson } 992231db3e6bb54447a9b14cf004a6cb03c373651cjwilson 10054cf3446000fdcf88a9e62724f7deb0282e98da1jwilson /** 10154cf3446000fdcf88a9e62724f7deb0282e98da1jwilson * Returns a deflater output stream that supports SYNC_FLUSH for SPDY name 10254cf3446000fdcf88a9e62724f7deb0282e98da1jwilson * value blocks. This throws an {@link UnsupportedOperationException} on 10354cf3446000fdcf88a9e62724f7deb0282e98da1jwilson * Java 6 and earlier where there is no built-in API to do SYNC_FLUSH. 10454cf3446000fdcf88a9e62724f7deb0282e98da1jwilson */ 10554cf3446000fdcf88a9e62724f7deb0282e98da1jwilson public OutputStream newDeflaterOutputStream(OutputStream out, Deflater deflater, 10654cf3446000fdcf88a9e62724f7deb0282e98da1jwilson boolean syncFlush) { 10754cf3446000fdcf88a9e62724f7deb0282e98da1jwilson try { 10854cf3446000fdcf88a9e62724f7deb0282e98da1jwilson Constructor<DeflaterOutputStream> constructor = deflaterConstructor; 10954cf3446000fdcf88a9e62724f7deb0282e98da1jwilson if (constructor == null) { 11054cf3446000fdcf88a9e62724f7deb0282e98da1jwilson constructor = deflaterConstructor = DeflaterOutputStream.class.getConstructor( 11154cf3446000fdcf88a9e62724f7deb0282e98da1jwilson OutputStream.class, Deflater.class, boolean.class); 11254cf3446000fdcf88a9e62724f7deb0282e98da1jwilson } 11354cf3446000fdcf88a9e62724f7deb0282e98da1jwilson return constructor.newInstance(out, deflater, syncFlush); 11454cf3446000fdcf88a9e62724f7deb0282e98da1jwilson } catch (NoSuchMethodException e) { 11554cf3446000fdcf88a9e62724f7deb0282e98da1jwilson throw new UnsupportedOperationException("Cannot SPDY; no SYNC_FLUSH available"); 11654cf3446000fdcf88a9e62724f7deb0282e98da1jwilson } catch (InvocationTargetException e) { 11754cf3446000fdcf88a9e62724f7deb0282e98da1jwilson throw e.getCause() instanceof RuntimeException ? (RuntimeException) e.getCause() 11854cf3446000fdcf88a9e62724f7deb0282e98da1jwilson : new RuntimeException(e.getCause()); 11954cf3446000fdcf88a9e62724f7deb0282e98da1jwilson } catch (InstantiationException e) { 12054cf3446000fdcf88a9e62724f7deb0282e98da1jwilson throw new RuntimeException(e); 12154cf3446000fdcf88a9e62724f7deb0282e98da1jwilson } catch (IllegalAccessException e) { 12254cf3446000fdcf88a9e62724f7deb0282e98da1jwilson throw new AssertionError(); 1232231db3e6bb54447a9b14cf004a6cb03c373651cjwilson } 12454cf3446000fdcf88a9e62724f7deb0282e98da1jwilson } 1252231db3e6bb54447a9b14cf004a6cb03c373651cjwilson 12654cf3446000fdcf88a9e62724f7deb0282e98da1jwilson /** Attempt to match the host runtime to a capable Platform implementation. */ 12754cf3446000fdcf88a9e62724f7deb0282e98da1jwilson private static Platform findPlatform() { 12854cf3446000fdcf88a9e62724f7deb0282e98da1jwilson // Attempt to find Android 2.3+ APIs. 12954cf3446000fdcf88a9e62724f7deb0282e98da1jwilson Class<?> openSslSocketClass; 13054cf3446000fdcf88a9e62724f7deb0282e98da1jwilson Method setUseSessionTickets; 13154cf3446000fdcf88a9e62724f7deb0282e98da1jwilson Method setHostname; 13254cf3446000fdcf88a9e62724f7deb0282e98da1jwilson try { 13354cf3446000fdcf88a9e62724f7deb0282e98da1jwilson openSslSocketClass = Class.forName("org.apache.harmony.xnet.provider.jsse.OpenSSLSocketImpl"); 13454cf3446000fdcf88a9e62724f7deb0282e98da1jwilson setUseSessionTickets = openSslSocketClass.getMethod("setUseSessionTickets", boolean.class); 13554cf3446000fdcf88a9e62724f7deb0282e98da1jwilson setHostname = openSslSocketClass.getMethod("setHostname", String.class); 13654cf3446000fdcf88a9e62724f7deb0282e98da1jwilson 13754cf3446000fdcf88a9e62724f7deb0282e98da1jwilson // Attempt to find Android 4.1+ APIs. 13854cf3446000fdcf88a9e62724f7deb0282e98da1jwilson try { 13954cf3446000fdcf88a9e62724f7deb0282e98da1jwilson Method setNpnProtocols = openSslSocketClass.getMethod("setNpnProtocols", byte[].class); 14054cf3446000fdcf88a9e62724f7deb0282e98da1jwilson Method getNpnSelectedProtocol = openSslSocketClass.getMethod("getNpnSelectedProtocol"); 14154cf3446000fdcf88a9e62724f7deb0282e98da1jwilson return new Android41(openSslSocketClass, setUseSessionTickets, setHostname, setNpnProtocols, 14254cf3446000fdcf88a9e62724f7deb0282e98da1jwilson getNpnSelectedProtocol); 14354cf3446000fdcf88a9e62724f7deb0282e98da1jwilson } catch (NoSuchMethodException ignored) { 14454cf3446000fdcf88a9e62724f7deb0282e98da1jwilson return new Android23(openSslSocketClass, setUseSessionTickets, setHostname); 14554cf3446000fdcf88a9e62724f7deb0282e98da1jwilson } 14654cf3446000fdcf88a9e62724f7deb0282e98da1jwilson } catch (ClassNotFoundException ignored) { 14754cf3446000fdcf88a9e62724f7deb0282e98da1jwilson // This isn't an Android runtime. 14854cf3446000fdcf88a9e62724f7deb0282e98da1jwilson } catch (NoSuchMethodException ignored) { 14954cf3446000fdcf88a9e62724f7deb0282e98da1jwilson // This isn't Android 2.3 or better. 1502231db3e6bb54447a9b14cf004a6cb03c373651cjwilson } 1512231db3e6bb54447a9b14cf004a6cb03c373651cjwilson 15254cf3446000fdcf88a9e62724f7deb0282e98da1jwilson // Attempt to find the Jetty's NPN extension for OpenJDK. 15354cf3446000fdcf88a9e62724f7deb0282e98da1jwilson try { 15454cf3446000fdcf88a9e62724f7deb0282e98da1jwilson String npnClassName = "org.eclipse.jetty.npn.NextProtoNego"; 15554cf3446000fdcf88a9e62724f7deb0282e98da1jwilson Class<?> nextProtoNegoClass = Class.forName(npnClassName); 15654cf3446000fdcf88a9e62724f7deb0282e98da1jwilson Class<?> providerClass = Class.forName(npnClassName + "$Provider"); 15754cf3446000fdcf88a9e62724f7deb0282e98da1jwilson Class<?> clientProviderClass = Class.forName(npnClassName + "$ClientProvider"); 15854cf3446000fdcf88a9e62724f7deb0282e98da1jwilson Class<?> serverProviderClass = Class.forName(npnClassName + "$ServerProvider"); 15954cf3446000fdcf88a9e62724f7deb0282e98da1jwilson Method putMethod = nextProtoNegoClass.getMethod("put", SSLSocket.class, providerClass); 16054cf3446000fdcf88a9e62724f7deb0282e98da1jwilson Method getMethod = nextProtoNegoClass.getMethod("get", SSLSocket.class); 16154cf3446000fdcf88a9e62724f7deb0282e98da1jwilson return new JdkWithJettyNpnPlatform(putMethod, getMethod, clientProviderClass, 16254cf3446000fdcf88a9e62724f7deb0282e98da1jwilson serverProviderClass); 16354cf3446000fdcf88a9e62724f7deb0282e98da1jwilson } catch (ClassNotFoundException ignored) { 16454cf3446000fdcf88a9e62724f7deb0282e98da1jwilson return new Platform(); // NPN isn't on the classpath. 16554cf3446000fdcf88a9e62724f7deb0282e98da1jwilson } catch (NoSuchMethodException ignored) { 16654cf3446000fdcf88a9e62724f7deb0282e98da1jwilson return new Platform(); // The NPN version isn't what we expect. 1672231db3e6bb54447a9b14cf004a6cb03c373651cjwilson } 16854cf3446000fdcf88a9e62724f7deb0282e98da1jwilson } 16954cf3446000fdcf88a9e62724f7deb0282e98da1jwilson 17054cf3446000fdcf88a9e62724f7deb0282e98da1jwilson /** 17154cf3446000fdcf88a9e62724f7deb0282e98da1jwilson * Android version 2.3 and newer support TLS session tickets and server name 17254cf3446000fdcf88a9e62724f7deb0282e98da1jwilson * indication (SNI). 17354cf3446000fdcf88a9e62724f7deb0282e98da1jwilson */ 17454cf3446000fdcf88a9e62724f7deb0282e98da1jwilson private static class Android23 extends Platform { 17554cf3446000fdcf88a9e62724f7deb0282e98da1jwilson protected final Class<?> openSslSocketClass; 17654cf3446000fdcf88a9e62724f7deb0282e98da1jwilson private final Method setUseSessionTickets; 17754cf3446000fdcf88a9e62724f7deb0282e98da1jwilson private final Method setHostname; 1782231db3e6bb54447a9b14cf004a6cb03c373651cjwilson 17954cf3446000fdcf88a9e62724f7deb0282e98da1jwilson private Android23(Class<?> openSslSocketClass, Method setUseSessionTickets, 18054cf3446000fdcf88a9e62724f7deb0282e98da1jwilson Method setHostname) { 18154cf3446000fdcf88a9e62724f7deb0282e98da1jwilson this.openSslSocketClass = openSslSocketClass; 18254cf3446000fdcf88a9e62724f7deb0282e98da1jwilson this.setUseSessionTickets = setUseSessionTickets; 18354cf3446000fdcf88a9e62724f7deb0282e98da1jwilson this.setHostname = setHostname; 1842231db3e6bb54447a9b14cf004a6cb03c373651cjwilson } 1852231db3e6bb54447a9b14cf004a6cb03c373651cjwilson 18654cf3446000fdcf88a9e62724f7deb0282e98da1jwilson @Override public void enableTlsExtensions(SSLSocket socket, String uriHost) { 18754cf3446000fdcf88a9e62724f7deb0282e98da1jwilson super.enableTlsExtensions(socket, uriHost); 18854cf3446000fdcf88a9e62724f7deb0282e98da1jwilson if (openSslSocketClass.isInstance(socket)) { 18954cf3446000fdcf88a9e62724f7deb0282e98da1jwilson // This is Android: use reflection on OpenSslSocketImpl. 1902231db3e6bb54447a9b14cf004a6cb03c373651cjwilson try { 19154cf3446000fdcf88a9e62724f7deb0282e98da1jwilson setUseSessionTickets.invoke(socket, true); 19254cf3446000fdcf88a9e62724f7deb0282e98da1jwilson setHostname.invoke(socket, uriHost); 1932231db3e6bb54447a9b14cf004a6cb03c373651cjwilson } catch (InvocationTargetException e) { 19454cf3446000fdcf88a9e62724f7deb0282e98da1jwilson throw new RuntimeException(e); 1952231db3e6bb54447a9b14cf004a6cb03c373651cjwilson } catch (IllegalAccessException e) { 19654cf3446000fdcf88a9e62724f7deb0282e98da1jwilson throw new AssertionError(e); 1972231db3e6bb54447a9b14cf004a6cb03c373651cjwilson } 19854cf3446000fdcf88a9e62724f7deb0282e98da1jwilson } 1992231db3e6bb54447a9b14cf004a6cb03c373651cjwilson } 20054cf3446000fdcf88a9e62724f7deb0282e98da1jwilson } 2012231db3e6bb54447a9b14cf004a6cb03c373651cjwilson 20254cf3446000fdcf88a9e62724f7deb0282e98da1jwilson /** Android version 4.1 and newer support NPN. */ 20354cf3446000fdcf88a9e62724f7deb0282e98da1jwilson private static class Android41 extends Android23 { 20454cf3446000fdcf88a9e62724f7deb0282e98da1jwilson private final Method setNpnProtocols; 20554cf3446000fdcf88a9e62724f7deb0282e98da1jwilson private final Method getNpnSelectedProtocol; 2062231db3e6bb54447a9b14cf004a6cb03c373651cjwilson 20754cf3446000fdcf88a9e62724f7deb0282e98da1jwilson private Android41(Class<?> openSslSocketClass, Method setUseSessionTickets, Method setHostname, 20854cf3446000fdcf88a9e62724f7deb0282e98da1jwilson Method setNpnProtocols, Method getNpnSelectedProtocol) { 20954cf3446000fdcf88a9e62724f7deb0282e98da1jwilson super(openSslSocketClass, setUseSessionTickets, setHostname); 21054cf3446000fdcf88a9e62724f7deb0282e98da1jwilson this.setNpnProtocols = setNpnProtocols; 21154cf3446000fdcf88a9e62724f7deb0282e98da1jwilson this.getNpnSelectedProtocol = getNpnSelectedProtocol; 2122231db3e6bb54447a9b14cf004a6cb03c373651cjwilson } 2132231db3e6bb54447a9b14cf004a6cb03c373651cjwilson 21454cf3446000fdcf88a9e62724f7deb0282e98da1jwilson @Override public void setNpnProtocols(SSLSocket socket, byte[] npnProtocols) { 21554cf3446000fdcf88a9e62724f7deb0282e98da1jwilson if (!openSslSocketClass.isInstance(socket)) { 21654cf3446000fdcf88a9e62724f7deb0282e98da1jwilson return; 21754cf3446000fdcf88a9e62724f7deb0282e98da1jwilson } 21854cf3446000fdcf88a9e62724f7deb0282e98da1jwilson try { 21954cf3446000fdcf88a9e62724f7deb0282e98da1jwilson setNpnProtocols.invoke(socket, new Object[] {npnProtocols}); 22054cf3446000fdcf88a9e62724f7deb0282e98da1jwilson } catch (IllegalAccessException e) { 22154cf3446000fdcf88a9e62724f7deb0282e98da1jwilson throw new AssertionError(e); 22254cf3446000fdcf88a9e62724f7deb0282e98da1jwilson } catch (InvocationTargetException e) { 22354cf3446000fdcf88a9e62724f7deb0282e98da1jwilson throw new RuntimeException(e); 22454cf3446000fdcf88a9e62724f7deb0282e98da1jwilson } 2252231db3e6bb54447a9b14cf004a6cb03c373651cjwilson } 2262231db3e6bb54447a9b14cf004a6cb03c373651cjwilson 22754cf3446000fdcf88a9e62724f7deb0282e98da1jwilson @Override public byte[] getNpnSelectedProtocol(SSLSocket socket) { 22854cf3446000fdcf88a9e62724f7deb0282e98da1jwilson if (!openSslSocketClass.isInstance(socket)) { 22954cf3446000fdcf88a9e62724f7deb0282e98da1jwilson return null; 23054cf3446000fdcf88a9e62724f7deb0282e98da1jwilson } 23154cf3446000fdcf88a9e62724f7deb0282e98da1jwilson try { 23254cf3446000fdcf88a9e62724f7deb0282e98da1jwilson return (byte[]) getNpnSelectedProtocol.invoke(socket); 23354cf3446000fdcf88a9e62724f7deb0282e98da1jwilson } catch (InvocationTargetException e) { 23454cf3446000fdcf88a9e62724f7deb0282e98da1jwilson throw new RuntimeException(e); 23554cf3446000fdcf88a9e62724f7deb0282e98da1jwilson } catch (IllegalAccessException e) { 23654cf3446000fdcf88a9e62724f7deb0282e98da1jwilson throw new AssertionError(e); 23754cf3446000fdcf88a9e62724f7deb0282e98da1jwilson } 2382231db3e6bb54447a9b14cf004a6cb03c373651cjwilson } 23954cf3446000fdcf88a9e62724f7deb0282e98da1jwilson } 2402231db3e6bb54447a9b14cf004a6cb03c373651cjwilson 24154cf3446000fdcf88a9e62724f7deb0282e98da1jwilson /** 24254cf3446000fdcf88a9e62724f7deb0282e98da1jwilson * OpenJDK 7 plus {@code org.mortbay.jetty.npn/npn-boot} on the boot class 24354cf3446000fdcf88a9e62724f7deb0282e98da1jwilson * path. 24454cf3446000fdcf88a9e62724f7deb0282e98da1jwilson */ 24554cf3446000fdcf88a9e62724f7deb0282e98da1jwilson private static class JdkWithJettyNpnPlatform extends Platform { 24654cf3446000fdcf88a9e62724f7deb0282e98da1jwilson private final Method getMethod; 24754cf3446000fdcf88a9e62724f7deb0282e98da1jwilson private final Method putMethod; 24854cf3446000fdcf88a9e62724f7deb0282e98da1jwilson private final Class<?> clientProviderClass; 24954cf3446000fdcf88a9e62724f7deb0282e98da1jwilson private final Class<?> serverProviderClass; 2502231db3e6bb54447a9b14cf004a6cb03c373651cjwilson 25154cf3446000fdcf88a9e62724f7deb0282e98da1jwilson public JdkWithJettyNpnPlatform(Method putMethod, Method getMethod, Class<?> clientProviderClass, 25254cf3446000fdcf88a9e62724f7deb0282e98da1jwilson Class<?> serverProviderClass) { 25354cf3446000fdcf88a9e62724f7deb0282e98da1jwilson this.putMethod = putMethod; 25454cf3446000fdcf88a9e62724f7deb0282e98da1jwilson this.getMethod = getMethod; 25554cf3446000fdcf88a9e62724f7deb0282e98da1jwilson this.clientProviderClass = clientProviderClass; 25654cf3446000fdcf88a9e62724f7deb0282e98da1jwilson this.serverProviderClass = serverProviderClass; 25754cf3446000fdcf88a9e62724f7deb0282e98da1jwilson } 2582231db3e6bb54447a9b14cf004a6cb03c373651cjwilson 25954cf3446000fdcf88a9e62724f7deb0282e98da1jwilson @Override public void setNpnProtocols(SSLSocket socket, byte[] npnProtocols) { 26054cf3446000fdcf88a9e62724f7deb0282e98da1jwilson try { 26154cf3446000fdcf88a9e62724f7deb0282e98da1jwilson List<String> strings = new ArrayList<String>(); 26254cf3446000fdcf88a9e62724f7deb0282e98da1jwilson for (int i = 0; i < npnProtocols.length; ) { 26354cf3446000fdcf88a9e62724f7deb0282e98da1jwilson int length = npnProtocols[i++]; 26454cf3446000fdcf88a9e62724f7deb0282e98da1jwilson strings.add(new String(npnProtocols, i, length, "US-ASCII")); 26554cf3446000fdcf88a9e62724f7deb0282e98da1jwilson i += length; 2662231db3e6bb54447a9b14cf004a6cb03c373651cjwilson } 26754cf3446000fdcf88a9e62724f7deb0282e98da1jwilson Object provider = Proxy.newProxyInstance(Platform.class.getClassLoader(), 26854cf3446000fdcf88a9e62724f7deb0282e98da1jwilson new Class[] {clientProviderClass, serverProviderClass}, 26954cf3446000fdcf88a9e62724f7deb0282e98da1jwilson new JettyNpnProvider(strings)); 27054cf3446000fdcf88a9e62724f7deb0282e98da1jwilson putMethod.invoke(null, socket, provider); 27154cf3446000fdcf88a9e62724f7deb0282e98da1jwilson } catch (UnsupportedEncodingException e) { 27254cf3446000fdcf88a9e62724f7deb0282e98da1jwilson throw new AssertionError(e); 27354cf3446000fdcf88a9e62724f7deb0282e98da1jwilson } catch (InvocationTargetException e) { 27454cf3446000fdcf88a9e62724f7deb0282e98da1jwilson throw new AssertionError(e); 27554cf3446000fdcf88a9e62724f7deb0282e98da1jwilson } catch (IllegalAccessException e) { 27654cf3446000fdcf88a9e62724f7deb0282e98da1jwilson throw new AssertionError(e); 27754cf3446000fdcf88a9e62724f7deb0282e98da1jwilson } 27854cf3446000fdcf88a9e62724f7deb0282e98da1jwilson } 2792231db3e6bb54447a9b14cf004a6cb03c373651cjwilson 28054cf3446000fdcf88a9e62724f7deb0282e98da1jwilson @Override public byte[] getNpnSelectedProtocol(SSLSocket socket) { 28154cf3446000fdcf88a9e62724f7deb0282e98da1jwilson try { 28254cf3446000fdcf88a9e62724f7deb0282e98da1jwilson JettyNpnProvider provider = 28354cf3446000fdcf88a9e62724f7deb0282e98da1jwilson (JettyNpnProvider) Proxy.getInvocationHandler(getMethod.invoke(null, socket)); 28454cf3446000fdcf88a9e62724f7deb0282e98da1jwilson if (!provider.unsupported && provider.selected == null) { 28554cf3446000fdcf88a9e62724f7deb0282e98da1jwilson Logger logger = Logger.getLogger(OkHttpClient.class.getName()); 28654cf3446000fdcf88a9e62724f7deb0282e98da1jwilson logger.log(Level.INFO, 28754cf3446000fdcf88a9e62724f7deb0282e98da1jwilson "NPN callback dropped so SPDY is disabled. " + "Is npn-boot on the boot class path?"); 28854cf3446000fdcf88a9e62724f7deb0282e98da1jwilson return null; 2892231db3e6bb54447a9b14cf004a6cb03c373651cjwilson } 29054cf3446000fdcf88a9e62724f7deb0282e98da1jwilson return provider.unsupported ? null : provider.selected.getBytes("US-ASCII"); 29154cf3446000fdcf88a9e62724f7deb0282e98da1jwilson } catch (UnsupportedEncodingException e) { 29254cf3446000fdcf88a9e62724f7deb0282e98da1jwilson throw new AssertionError(); 29354cf3446000fdcf88a9e62724f7deb0282e98da1jwilson } catch (InvocationTargetException e) { 29454cf3446000fdcf88a9e62724f7deb0282e98da1jwilson throw new AssertionError(); 29554cf3446000fdcf88a9e62724f7deb0282e98da1jwilson } catch (IllegalAccessException e) { 29654cf3446000fdcf88a9e62724f7deb0282e98da1jwilson throw new AssertionError(); 29754cf3446000fdcf88a9e62724f7deb0282e98da1jwilson } 2982231db3e6bb54447a9b14cf004a6cb03c373651cjwilson } 29954cf3446000fdcf88a9e62724f7deb0282e98da1jwilson } 3002231db3e6bb54447a9b14cf004a6cb03c373651cjwilson 30154cf3446000fdcf88a9e62724f7deb0282e98da1jwilson /** 30254cf3446000fdcf88a9e62724f7deb0282e98da1jwilson * Handle the methods of NextProtoNego's ClientProvider and ServerProvider 30354cf3446000fdcf88a9e62724f7deb0282e98da1jwilson * without a compile-time dependency on those interfaces. 30454cf3446000fdcf88a9e62724f7deb0282e98da1jwilson */ 30554cf3446000fdcf88a9e62724f7deb0282e98da1jwilson private static class JettyNpnProvider implements InvocationHandler { 30654cf3446000fdcf88a9e62724f7deb0282e98da1jwilson private final List<String> protocols; 30754cf3446000fdcf88a9e62724f7deb0282e98da1jwilson private boolean unsupported; 30854cf3446000fdcf88a9e62724f7deb0282e98da1jwilson private String selected; 3092231db3e6bb54447a9b14cf004a6cb03c373651cjwilson 31054cf3446000fdcf88a9e62724f7deb0282e98da1jwilson public JettyNpnProvider(List<String> protocols) { 31154cf3446000fdcf88a9e62724f7deb0282e98da1jwilson this.protocols = protocols; 31254cf3446000fdcf88a9e62724f7deb0282e98da1jwilson } 3132231db3e6bb54447a9b14cf004a6cb03c373651cjwilson 31454cf3446000fdcf88a9e62724f7deb0282e98da1jwilson @Override public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { 31554cf3446000fdcf88a9e62724f7deb0282e98da1jwilson String methodName = method.getName(); 31654cf3446000fdcf88a9e62724f7deb0282e98da1jwilson Class<?> returnType = method.getReturnType(); 31754cf3446000fdcf88a9e62724f7deb0282e98da1jwilson if (args == null) { 31854cf3446000fdcf88a9e62724f7deb0282e98da1jwilson args = Util.EMPTY_STRING_ARRAY; 31954cf3446000fdcf88a9e62724f7deb0282e98da1jwilson } 32054cf3446000fdcf88a9e62724f7deb0282e98da1jwilson if (methodName.equals("supports") && boolean.class == returnType) { 32154cf3446000fdcf88a9e62724f7deb0282e98da1jwilson return true; 32254cf3446000fdcf88a9e62724f7deb0282e98da1jwilson } else if (methodName.equals("unsupported") && void.class == returnType) { 32354cf3446000fdcf88a9e62724f7deb0282e98da1jwilson this.unsupported = true; 32454cf3446000fdcf88a9e62724f7deb0282e98da1jwilson return null; 32554cf3446000fdcf88a9e62724f7deb0282e98da1jwilson } else if (methodName.equals("protocols") && args.length == 0) { 32654cf3446000fdcf88a9e62724f7deb0282e98da1jwilson return protocols; 32754cf3446000fdcf88a9e62724f7deb0282e98da1jwilson } else if (methodName.equals("selectProtocol") 32854cf3446000fdcf88a9e62724f7deb0282e98da1jwilson && String.class == returnType 32954cf3446000fdcf88a9e62724f7deb0282e98da1jwilson && args.length == 1 33054cf3446000fdcf88a9e62724f7deb0282e98da1jwilson && (args[0] == null || args[0] instanceof List)) { 33154cf3446000fdcf88a9e62724f7deb0282e98da1jwilson // TODO: use OpenSSL's algorithm which uses both lists 33254cf3446000fdcf88a9e62724f7deb0282e98da1jwilson List<?> serverProtocols = (List) args[0]; 33354cf3446000fdcf88a9e62724f7deb0282e98da1jwilson this.selected = protocols.get(0); 33454cf3446000fdcf88a9e62724f7deb0282e98da1jwilson return selected; 33554cf3446000fdcf88a9e62724f7deb0282e98da1jwilson } else if (methodName.equals("protocolSelected") && args.length == 1) { 33654cf3446000fdcf88a9e62724f7deb0282e98da1jwilson this.selected = (String) args[0]; 33754cf3446000fdcf88a9e62724f7deb0282e98da1jwilson return null; 33854cf3446000fdcf88a9e62724f7deb0282e98da1jwilson } else { 33954cf3446000fdcf88a9e62724f7deb0282e98da1jwilson return method.invoke(this, args); 34054cf3446000fdcf88a9e62724f7deb0282e98da1jwilson } 3412231db3e6bb54447a9b14cf004a6cb03c373651cjwilson } 34254cf3446000fdcf88a9e62724f7deb0282e98da1jwilson } 3432231db3e6bb54447a9b14cf004a6cb03c373651cjwilson} 344