mirror of
https://github.com/square/okhttp.git
synced 2026-01-12 10:23:16 +03:00
Merge pull request #1087 from square/jwilson_1012_tls_12
Revise how TLS connections are negotiated.
This commit is contained in:
@@ -67,7 +67,7 @@ public final class SpdyServer implements IncomingStreamHandler {
|
||||
(SSLSocket) sslSocketFactory.createSocket(socket, socket.getInetAddress().getHostAddress(),
|
||||
socket.getPort(), true);
|
||||
sslSocket.setUseClientMode(false);
|
||||
Platform.get().setProtocols(sslSocket, spdyProtocols);
|
||||
Platform.get().configureTlsExtensions(sslSocket, null, spdyProtocols);
|
||||
sslSocket.startHandshake();
|
||||
String protocolString = Platform.get().getSelectedProtocol(sslSocket);
|
||||
protocol = protocolString != null ? Protocol.get(protocolString) : null;
|
||||
|
||||
@@ -369,7 +369,7 @@ public final class MockWebServer {
|
||||
openClientSockets.put(socket, true);
|
||||
|
||||
if (protocolNegotiationEnabled) {
|
||||
Platform.get().setProtocols(sslSocket, protocols);
|
||||
Platform.get().configureTlsExtensions(sslSocket, null, protocols);
|
||||
}
|
||||
|
||||
sslSocket.startHandshake();
|
||||
|
||||
@@ -31,7 +31,6 @@ import org.junit.After;
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
|
||||
import static com.squareup.okhttp.internal.http.RouteSelector.TLS_V1;
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import static org.junit.Assert.assertFalse;
|
||||
import static org.junit.Assert.assertNotNull;
|
||||
@@ -88,8 +87,10 @@ public final class ConnectionPoolTest {
|
||||
spdySocketAddress = new InetSocketAddress(InetAddress.getByName(spdyServer.getHostName()),
|
||||
spdyServer.getPort());
|
||||
|
||||
Route httpRoute = new Route(httpAddress, Proxy.NO_PROXY, httpSocketAddress, TLS_V1);
|
||||
Route spdyRoute = new Route(spdyAddress, Proxy.NO_PROXY, spdySocketAddress, TLS_V1);
|
||||
Route httpRoute = new Route(httpAddress, Proxy.NO_PROXY, httpSocketAddress,
|
||||
TlsConfiguration.PREFERRED);
|
||||
Route spdyRoute = new Route(spdyAddress, Proxy.NO_PROXY, spdySocketAddress,
|
||||
TlsConfiguration.PREFERRED);
|
||||
pool = new ConnectionPool(poolSize, KEEP_ALIVE_DURATION_MS);
|
||||
httpA = new Connection(pool, httpRoute);
|
||||
httpA.connect(200, 200, 200, null);
|
||||
@@ -134,8 +135,8 @@ public final class ConnectionPoolTest {
|
||||
Connection connection = pool.get(httpAddress);
|
||||
assertNull(connection);
|
||||
|
||||
connection = new Connection(
|
||||
pool, new Route(httpAddress, Proxy.NO_PROXY, httpSocketAddress, TLS_V1));
|
||||
connection = new Connection(pool, new Route(httpAddress, Proxy.NO_PROXY, httpSocketAddress,
|
||||
TlsConfiguration.PREFERRED));
|
||||
connection.connect(200, 200, 200, null);
|
||||
connection.setOwner(owner);
|
||||
assertEquals(0, pool.getConnectionCount());
|
||||
|
||||
@@ -17,12 +17,12 @@ package com.squareup.okhttp.internal.http;
|
||||
|
||||
import com.squareup.okhttp.Address;
|
||||
import com.squareup.okhttp.Authenticator;
|
||||
import com.squareup.okhttp.CertificatePinner;
|
||||
import com.squareup.okhttp.Connection;
|
||||
import com.squareup.okhttp.ConnectionPool;
|
||||
import com.squareup.okhttp.OkHttpClient;
|
||||
import com.squareup.okhttp.Protocol;
|
||||
import com.squareup.okhttp.Request;
|
||||
import com.squareup.okhttp.TlsConfiguration;
|
||||
import com.squareup.okhttp.internal.Internal;
|
||||
import com.squareup.okhttp.internal.Network;
|
||||
import com.squareup.okhttp.internal.RouteDatabase;
|
||||
@@ -45,8 +45,6 @@ import javax.net.ssl.SSLSocketFactory;
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
|
||||
import static com.squareup.okhttp.internal.http.RouteSelector.SSL_V3;
|
||||
import static com.squareup.okhttp.internal.http.RouteSelector.TLS_V1;
|
||||
import static java.net.Proxy.NO_PROXY;
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import static org.junit.Assert.assertFalse;
|
||||
@@ -110,7 +108,7 @@ public final class RouteSelectorTest {
|
||||
assertTrue(routeSelector.hasNext());
|
||||
dns.inetAddresses = makeFakeAddresses(255, 1);
|
||||
assertConnection(routeSelector.nextUnconnected(), address, NO_PROXY, dns.inetAddresses[0],
|
||||
uriPort, SSL_V3);
|
||||
uriPort, TlsConfiguration.FALLBACK);
|
||||
dns.assertRequests(uriHost);
|
||||
|
||||
assertFalse(routeSelector.hasNext());
|
||||
@@ -131,7 +129,7 @@ public final class RouteSelectorTest {
|
||||
routeDatabase.failed(connection.getRoute());
|
||||
routeSelector = RouteSelector.get(httpRequest, client);
|
||||
assertConnection(routeSelector.nextUnconnected(), address, NO_PROXY, dns.inetAddresses[0],
|
||||
uriPort, SSL_V3);
|
||||
uriPort, TlsConfiguration.FALLBACK);
|
||||
assertFalse(routeSelector.hasNext());
|
||||
try {
|
||||
routeSelector.nextUnconnected();
|
||||
@@ -149,9 +147,9 @@ public final class RouteSelectorTest {
|
||||
assertTrue(routeSelector.hasNext());
|
||||
dns.inetAddresses = makeFakeAddresses(255, 2);
|
||||
assertConnection(routeSelector.nextUnconnected(), address, proxyA, dns.inetAddresses[0],
|
||||
proxyAPort, SSL_V3);
|
||||
proxyAPort, TlsConfiguration.FALLBACK);
|
||||
assertConnection(routeSelector.nextUnconnected(), address, proxyA, dns.inetAddresses[1],
|
||||
proxyAPort, SSL_V3);
|
||||
proxyAPort, TlsConfiguration.FALLBACK);
|
||||
|
||||
assertFalse(routeSelector.hasNext());
|
||||
dns.assertRequests(proxyAHost);
|
||||
@@ -167,9 +165,9 @@ public final class RouteSelectorTest {
|
||||
assertTrue(routeSelector.hasNext());
|
||||
dns.inetAddresses = makeFakeAddresses(255, 2);
|
||||
assertConnection(routeSelector.nextUnconnected(), address, NO_PROXY, dns.inetAddresses[0],
|
||||
uriPort, SSL_V3);
|
||||
uriPort, TlsConfiguration.FALLBACK);
|
||||
assertConnection(routeSelector.nextUnconnected(), address, NO_PROXY, dns.inetAddresses[1],
|
||||
uriPort, SSL_V3);
|
||||
uriPort, TlsConfiguration.FALLBACK);
|
||||
|
||||
assertFalse(routeSelector.hasNext());
|
||||
dns.assertRequests(uriHost);
|
||||
@@ -186,7 +184,7 @@ public final class RouteSelectorTest {
|
||||
assertTrue(routeSelector.hasNext());
|
||||
dns.inetAddresses = makeFakeAddresses(255, 1);
|
||||
assertConnection(routeSelector.nextUnconnected(), address, NO_PROXY, dns.inetAddresses[0],
|
||||
uriPort, SSL_V3);
|
||||
uriPort, TlsConfiguration.FALLBACK);
|
||||
dns.assertRequests(uriHost);
|
||||
|
||||
assertFalse(routeSelector.hasNext());
|
||||
@@ -199,9 +197,9 @@ public final class RouteSelectorTest {
|
||||
assertTrue(routeSelector.hasNext());
|
||||
dns.inetAddresses = makeFakeAddresses(255, 2);
|
||||
assertConnection(routeSelector.nextUnconnected(), address, NO_PROXY, dns.inetAddresses[0],
|
||||
uriPort, SSL_V3);
|
||||
uriPort, TlsConfiguration.FALLBACK);
|
||||
assertConnection(routeSelector.nextUnconnected(), address, NO_PROXY, dns.inetAddresses[1],
|
||||
uriPort, SSL_V3);
|
||||
uriPort, TlsConfiguration.FALLBACK);
|
||||
|
||||
assertFalse(routeSelector.hasNext());
|
||||
dns.assertRequests(uriHost);
|
||||
@@ -220,23 +218,23 @@ public final class RouteSelectorTest {
|
||||
assertTrue(routeSelector.hasNext());
|
||||
dns.inetAddresses = makeFakeAddresses(255, 2);
|
||||
assertConnection(routeSelector.nextUnconnected(), address, proxyA, dns.inetAddresses[0], proxyAPort,
|
||||
SSL_V3);
|
||||
TlsConfiguration.FALLBACK);
|
||||
assertConnection(routeSelector.nextUnconnected(), address, proxyA, dns.inetAddresses[1], proxyAPort,
|
||||
SSL_V3);
|
||||
TlsConfiguration.FALLBACK);
|
||||
dns.assertRequests(proxyAHost);
|
||||
|
||||
// Next try the IP address of the second proxy.
|
||||
assertTrue(routeSelector.hasNext());
|
||||
dns.inetAddresses = makeFakeAddresses(254, 1);
|
||||
assertConnection(routeSelector.nextUnconnected(), address, proxyB, dns.inetAddresses[0], proxyBPort,
|
||||
SSL_V3);
|
||||
TlsConfiguration.FALLBACK);
|
||||
dns.assertRequests(proxyBHost);
|
||||
|
||||
// Finally try the only IP address of the origin server.
|
||||
assertTrue(routeSelector.hasNext());
|
||||
dns.inetAddresses = makeFakeAddresses(253, 1);
|
||||
assertConnection(routeSelector.nextUnconnected(), address, NO_PROXY, dns.inetAddresses[0], uriPort,
|
||||
SSL_V3);
|
||||
TlsConfiguration.FALLBACK);
|
||||
dns.assertRequests(uriHost);
|
||||
|
||||
assertFalse(routeSelector.hasNext());
|
||||
@@ -253,7 +251,7 @@ public final class RouteSelectorTest {
|
||||
assertTrue(routeSelector.hasNext());
|
||||
dns.inetAddresses = makeFakeAddresses(255, 1);
|
||||
assertConnection(routeSelector.nextUnconnected(), address, NO_PROXY, dns.inetAddresses[0], uriPort,
|
||||
SSL_V3);
|
||||
TlsConfiguration.FALLBACK);
|
||||
dns.assertRequests(uriHost);
|
||||
|
||||
assertFalse(routeSelector.hasNext());
|
||||
@@ -270,8 +268,8 @@ public final class RouteSelectorTest {
|
||||
|
||||
assertTrue(routeSelector.hasNext());
|
||||
dns.inetAddresses = makeFakeAddresses(255, 1);
|
||||
assertConnection(routeSelector.nextUnconnected(), address, proxyA, dns.inetAddresses[0], proxyAPort,
|
||||
SSL_V3);
|
||||
assertConnection(routeSelector.nextUnconnected(), address, proxyA, dns.inetAddresses[0],
|
||||
proxyAPort, TlsConfiguration.FALLBACK);
|
||||
dns.assertRequests(proxyAHost);
|
||||
|
||||
assertTrue(routeSelector.hasNext());
|
||||
@@ -285,14 +283,14 @@ public final class RouteSelectorTest {
|
||||
|
||||
assertTrue(routeSelector.hasNext());
|
||||
dns.inetAddresses = makeFakeAddresses(255, 1);
|
||||
assertConnection(routeSelector.nextUnconnected(), address, proxyA, dns.inetAddresses[0], proxyAPort,
|
||||
SSL_V3);
|
||||
assertConnection(routeSelector.nextUnconnected(), address, proxyA, dns.inetAddresses[0],
|
||||
proxyAPort, TlsConfiguration.FALLBACK);
|
||||
dns.assertRequests(proxyAHost);
|
||||
|
||||
assertTrue(routeSelector.hasNext());
|
||||
dns.inetAddresses = makeFakeAddresses(254, 1);
|
||||
assertConnection(routeSelector.nextUnconnected(), address, NO_PROXY, dns.inetAddresses[0], uriPort,
|
||||
SSL_V3);
|
||||
assertConnection(routeSelector.nextUnconnected(), address, NO_PROXY, dns.inetAddresses[0],
|
||||
uriPort, TlsConfiguration.FALLBACK);
|
||||
dns.assertRequests(uriHost);
|
||||
|
||||
assertFalse(routeSelector.hasNext());
|
||||
@@ -306,7 +304,7 @@ public final class RouteSelectorTest {
|
||||
dns.inetAddresses = makeFakeAddresses(255, 1);
|
||||
Connection connection = routeSelector.nextUnconnected();
|
||||
routeSelector.connectFailed(connection, new IOException("Non SSL exception"));
|
||||
assertTrue(routeDatabase.failedRoutesCount() == 2);
|
||||
assertEquals(RouteSelector.TLS_CONFIGURATIONS.size(), routeDatabase.failedRoutesCount());
|
||||
assertFalse(routeSelector.hasNext());
|
||||
}
|
||||
|
||||
@@ -331,38 +329,38 @@ public final class RouteSelectorTest {
|
||||
// Proxy A
|
||||
dns.inetAddresses = makeFakeAddresses(255, 2);
|
||||
assertConnection(routeSelector.nextUnconnected(), address, proxyA, dns.inetAddresses[0],
|
||||
proxyAPort, TLS_V1);
|
||||
proxyAPort, TlsConfiguration.PREFERRED);
|
||||
dns.assertRequests(proxyAHost);
|
||||
assertConnection(routeSelector.nextUnconnected(), address, proxyA, dns.inetAddresses[0],
|
||||
proxyAPort, SSL_V3);
|
||||
proxyAPort, TlsConfiguration.FALLBACK);
|
||||
assertConnection(routeSelector.nextUnconnected(), address, proxyA, dns.inetAddresses[1],
|
||||
proxyAPort, TLS_V1);
|
||||
proxyAPort, TlsConfiguration.PREFERRED);
|
||||
assertConnection(routeSelector.nextUnconnected(), address, proxyA, dns.inetAddresses[1],
|
||||
proxyAPort, SSL_V3);
|
||||
proxyAPort, TlsConfiguration.FALLBACK);
|
||||
|
||||
// Proxy B
|
||||
dns.inetAddresses = makeFakeAddresses(254, 2);
|
||||
assertConnection(routeSelector.nextUnconnected(), address, proxyB, dns.inetAddresses[0],
|
||||
proxyBPort, TLS_V1);
|
||||
proxyBPort, TlsConfiguration.PREFERRED);
|
||||
dns.assertRequests(proxyBHost);
|
||||
assertConnection(routeSelector.nextUnconnected(), address, proxyB, dns.inetAddresses[0],
|
||||
proxyBPort, SSL_V3);
|
||||
proxyBPort, TlsConfiguration.FALLBACK);
|
||||
assertConnection(routeSelector.nextUnconnected(), address, proxyB, dns.inetAddresses[1],
|
||||
proxyBPort, TLS_V1);
|
||||
proxyBPort, TlsConfiguration.PREFERRED);
|
||||
assertConnection(routeSelector.nextUnconnected(), address, proxyB, dns.inetAddresses[1],
|
||||
proxyBPort, SSL_V3);
|
||||
proxyBPort, TlsConfiguration.FALLBACK);
|
||||
|
||||
// Origin
|
||||
dns.inetAddresses = makeFakeAddresses(253, 2);
|
||||
assertConnection(routeSelector.nextUnconnected(), address, NO_PROXY, dns.inetAddresses[0],
|
||||
uriPort, TLS_V1);
|
||||
uriPort, TlsConfiguration.PREFERRED);
|
||||
dns.assertRequests(uriHost);
|
||||
assertConnection(routeSelector.nextUnconnected(), address, NO_PROXY, dns.inetAddresses[0],
|
||||
uriPort, SSL_V3);
|
||||
uriPort, TlsConfiguration.FALLBACK);
|
||||
assertConnection(routeSelector.nextUnconnected(), address, NO_PROXY, dns.inetAddresses[1],
|
||||
uriPort, TLS_V1);
|
||||
uriPort, TlsConfiguration.PREFERRED);
|
||||
assertConnection(routeSelector.nextUnconnected(), address, NO_PROXY, dns.inetAddresses[1],
|
||||
uriPort, SSL_V3);
|
||||
uriPort, TlsConfiguration.FALLBACK);
|
||||
|
||||
assertFalse(routeSelector.hasNext());
|
||||
}
|
||||
@@ -397,12 +395,12 @@ public final class RouteSelectorTest {
|
||||
}
|
||||
|
||||
private void assertConnection(Connection connection, Address address, Proxy proxy,
|
||||
InetAddress socketAddress, int socketPort, String tlsVersion) {
|
||||
InetAddress socketAddress, int socketPort, TlsConfiguration tlsConfiguration) {
|
||||
assertEquals(address, connection.getRoute().getAddress());
|
||||
assertEquals(proxy, connection.getRoute().getProxy());
|
||||
assertEquals(socketAddress, connection.getRoute().getSocketAddress().getAddress());
|
||||
assertEquals(socketPort, connection.getRoute().getSocketAddress().getPort());
|
||||
assertEquals(tlsVersion, connection.getRoute().getTlsVersion());
|
||||
assertEquals(tlsConfiguration, connection.getRoute().getTlsConfiguration());
|
||||
}
|
||||
|
||||
/** Returns an address that's without an SSL socket factory or hostname verifier. */
|
||||
|
||||
@@ -25,7 +25,9 @@ import com.squareup.okhttp.OkHttpClient;
|
||||
import com.squareup.okhttp.OkUrlFactory;
|
||||
import com.squareup.okhttp.Protocol;
|
||||
import com.squareup.okhttp.Response;
|
||||
import com.squareup.okhttp.TlsConfiguration;
|
||||
import com.squareup.okhttp.internal.Internal;
|
||||
import com.squareup.okhttp.internal.Network;
|
||||
import com.squareup.okhttp.internal.RecordingAuthenticator;
|
||||
import com.squareup.okhttp.internal.RecordingHostnameVerifier;
|
||||
import com.squareup.okhttp.internal.RecordingOkAuthenticator;
|
||||
@@ -856,12 +858,11 @@ public final class URLConnectionTest {
|
||||
.setSocketPolicy(SocketPolicy.UPGRADE_TO_SSL_AT_END)
|
||||
.setBody("bogus proxy connect response content");
|
||||
|
||||
// Enqueue a pair of responses for every IP address held by localhost, because the
|
||||
// route selector will try each in sequence.
|
||||
// TODO: use the fake Dns implementation instead of a loop
|
||||
for (InetAddress inetAddress : InetAddress.getAllByName(server.getHostName())) {
|
||||
server.enqueue(response); // For the first TLS tolerant connection
|
||||
server.enqueue(response); // For the backwards-compatible SSLv3 retry
|
||||
// Configure a single IP address for the host, so we don't retry once for each. Enqueue a
|
||||
// response for all TLS configurations that will be attempted.
|
||||
Internal.instance.setNetwork(client.client(), networkWithFirstAddressOnly());
|
||||
for (TlsConfiguration tlsConfiguration : RouteSelector.TLS_CONFIGURATIONS) {
|
||||
server.enqueue(response);
|
||||
}
|
||||
server.play();
|
||||
client.client().setProxy(server.toProxyAddress());
|
||||
@@ -3296,4 +3297,14 @@ public final class URLConnectionTest {
|
||||
server.setProtocolNegotiationEnabled(true);
|
||||
server.setProtocols(client.client().getProtocols());
|
||||
}
|
||||
|
||||
/** Returns a network that resolves only one IP address per host. */
|
||||
private Network networkWithFirstAddressOnly() {
|
||||
return new Network() {
|
||||
@Override public InetAddress[] resolveInetAddresses(String host) throws UnknownHostException {
|
||||
InetAddress[] allInetAddresses = Network.DEFAULT.resolveInetAddresses(host);
|
||||
return new InetAddress[] { allInetAddresses[0] };
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
@@ -17,7 +17,6 @@
|
||||
package com.squareup.okhttp;
|
||||
|
||||
import com.squareup.okhttp.internal.Platform;
|
||||
import com.squareup.okhttp.internal.Util;
|
||||
import com.squareup.okhttp.internal.http.HttpConnection;
|
||||
import com.squareup.okhttp.internal.http.HttpEngine;
|
||||
import com.squareup.okhttp.internal.http.HttpTransport;
|
||||
@@ -29,14 +28,10 @@ import java.io.IOException;
|
||||
import java.net.Proxy;
|
||||
import java.net.Socket;
|
||||
import java.net.URL;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
import java.util.concurrent.atomic.AtomicReference;
|
||||
import javax.net.ssl.SSLSocket;
|
||||
|
||||
import static com.squareup.okhttp.internal.Util.getDefaultPort;
|
||||
import static com.squareup.okhttp.internal.Util.getEffectivePort;
|
||||
import static com.squareup.okhttp.internal.Util.immutableList;
|
||||
import static java.net.HttpURLConnection.HTTP_OK;
|
||||
import static java.net.HttpURLConnection.HTTP_PROXY_AUTH;
|
||||
|
||||
@@ -67,39 +62,6 @@ import static java.net.HttpURLConnection.HTTP_PROXY_AUTH;
|
||||
* should the attempt fail.
|
||||
*/
|
||||
public final class Connection {
|
||||
/**
|
||||
* This is a subset of the cipher suites supported in Chrome 37, current as of 2014-10-5. All of
|
||||
* these suites are available on Android L; earlier releases support a subset of these suites.
|
||||
* https://github.com/square/okhttp/issues/330
|
||||
*/
|
||||
private static final List<String> CIPHER_SUITES = immutableList(
|
||||
"TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256", // 0xC0,0x2B Android L
|
||||
"TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256", // 0xC0,0x2F Android L
|
||||
"TLS_DHE_RSA_WITH_AES_128_GCM_SHA256", // 0x00,0x9E Android L
|
||||
"TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA", // 0xC0,0x0A Android 4.0
|
||||
"TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA", // 0xC0,0x09 Android 4.0
|
||||
"TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA", // 0xC0,0x13 Android 4.0
|
||||
"TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA", // 0xC0,0x14 Android 4.0
|
||||
"TLS_ECDHE_ECDSA_WITH_RC4_128_SHA", // 0xC0,0x07 Android 4.0
|
||||
"TLS_ECDHE_RSA_WITH_RC4_128_SHA", // 0xC0,0x11 Android 4.0
|
||||
"TLS_DHE_RSA_WITH_AES_128_CBC_SHA", // 0x00,0x33 Android 2.3
|
||||
"TLS_DHE_DSS_WITH_AES_128_CBC_SHA", // 0x00,0x32 Android 2.3
|
||||
"TLS_DHE_RSA_WITH_AES_256_CBC_SHA", // 0x00,0x39 Android 2.3
|
||||
"TLS_RSA_WITH_AES_128_GCM_SHA256", // 0x00,0x9C Android L
|
||||
"TLS_RSA_WITH_AES_128_CBC_SHA", // 0x00,0x2F Android 2.3
|
||||
"TLS_RSA_WITH_AES_256_CBC_SHA", // 0x00,0x35 Android 2.3
|
||||
"SSL_RSA_WITH_3DES_EDE_CBC_SHA", // 0x00,0x0A Android 2.3 (Deprecated in L)
|
||||
"SSL_RSA_WITH_RC4_128_SHA", // 0x00,0x05 Android 2.3
|
||||
"SSL_RSA_WITH_RC4_128_MD5" // 0x00,0x04 Android 2.3 (Deprecated in L)
|
||||
);
|
||||
|
||||
/**
|
||||
* Cache of the intersection between {@link #CIPHER_SUITES} and the platform's supported suites.
|
||||
* It's possible that the platform hosts multiple implementations of {@link SSLSocket}, in which
|
||||
* case this cache will be incorrect.
|
||||
*/
|
||||
private static final AtomicReference<String[]> SELECTED_CIPHER_SUITES = new AtomicReference<>();
|
||||
|
||||
private final ConnectionPool pool;
|
||||
private final Route route;
|
||||
|
||||
@@ -265,13 +227,9 @@ public final class Connection {
|
||||
socket = route.address.sslSocketFactory
|
||||
.createSocket(socket, route.address.uriHost, route.address.uriPort, true /* autoClose */);
|
||||
SSLSocket sslSocket = (SSLSocket) socket;
|
||||
sslSocket.setEnabledCipherSuites(cipherSuites(sslSocket));
|
||||
platform.configureTls(sslSocket, route.address.uriHost, route.tlsVersion);
|
||||
|
||||
boolean useNpn = route.supportsNpn();
|
||||
if (useNpn) {
|
||||
platform.setProtocols(sslSocket, route.address.protocols);
|
||||
}
|
||||
// Configure the socket's ciphers, TLS versions, and extensions.
|
||||
route.tlsConfiguration.apply(sslSocket, route);
|
||||
|
||||
// Force handshake. This can throw!
|
||||
sslSocket.startHandshake();
|
||||
@@ -288,7 +246,8 @@ public final class Connection {
|
||||
handshake = Handshake.get(sslSocket.getSession());
|
||||
|
||||
String maybeProtocol;
|
||||
if (useNpn && (maybeProtocol = platform.getSelectedProtocol(sslSocket)) != null) {
|
||||
if (route.tlsConfiguration.supportsTlsExtensions()
|
||||
&& (maybeProtocol = platform.getSelectedProtocol(sslSocket)) != null) {
|
||||
protocol = Protocol.get(maybeProtocol); // Throws IOE on unknown.
|
||||
}
|
||||
|
||||
@@ -302,17 +261,6 @@ public final class Connection {
|
||||
}
|
||||
}
|
||||
|
||||
private String[] cipherSuites(SSLSocket sslSocket) {
|
||||
String[] result = SELECTED_CIPHER_SUITES.get();
|
||||
if (result == null) {
|
||||
List<String> intersection = Util.intersect(CIPHER_SUITES,
|
||||
Arrays.asList(sslSocket.getSupportedCipherSuites()));
|
||||
result = intersection.toArray(new String[intersection.size()]);
|
||||
SELECTED_CIPHER_SUITES.set(result);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
/** Returns true if {@link #connect} has been attempted on this connection. */
|
||||
boolean isConnected() {
|
||||
return connected;
|
||||
|
||||
@@ -148,25 +148,26 @@ public class OkHttpClient implements Cloneable {
|
||||
}
|
||||
|
||||
private OkHttpClient(OkHttpClient okHttpClient) {
|
||||
this.routeDatabase = okHttpClient.routeDatabase();
|
||||
this.dispatcher = okHttpClient.getDispatcher();
|
||||
this.proxy = okHttpClient.getProxy();
|
||||
this.protocols = okHttpClient.getProtocols();
|
||||
this.proxySelector = okHttpClient.getProxySelector();
|
||||
this.cookieHandler = okHttpClient.getCookieHandler();
|
||||
this.cache = okHttpClient.getCache();
|
||||
this.routeDatabase = okHttpClient.routeDatabase;
|
||||
this.dispatcher = okHttpClient.dispatcher;
|
||||
this.proxy = okHttpClient.proxy;
|
||||
this.protocols = okHttpClient.protocols;
|
||||
this.proxySelector = okHttpClient.proxySelector;
|
||||
this.cookieHandler = okHttpClient.cookieHandler;
|
||||
this.cache = okHttpClient.cache;
|
||||
this.internalCache = cache != null ? cache.internalCache : okHttpClient.internalCache;
|
||||
this.socketFactory = okHttpClient.getSocketFactory();
|
||||
this.sslSocketFactory = okHttpClient.getSslSocketFactory();
|
||||
this.hostnameVerifier = okHttpClient.getHostnameVerifier();
|
||||
this.certificatePinner = okHttpClient.getCertificatePinner();
|
||||
this.authenticator = okHttpClient.getAuthenticator();
|
||||
this.connectionPool = okHttpClient.getConnectionPool();
|
||||
this.followSslRedirects = okHttpClient.getFollowSslRedirects();
|
||||
this.followRedirects = okHttpClient.getFollowRedirects();
|
||||
this.connectTimeout = okHttpClient.getConnectTimeout();
|
||||
this.readTimeout = okHttpClient.getReadTimeout();
|
||||
this.writeTimeout = okHttpClient.getWriteTimeout();
|
||||
this.socketFactory = okHttpClient.socketFactory;
|
||||
this.sslSocketFactory = okHttpClient.sslSocketFactory;
|
||||
this.hostnameVerifier = okHttpClient.hostnameVerifier;
|
||||
this.certificatePinner = okHttpClient.certificatePinner;
|
||||
this.authenticator = okHttpClient.authenticator;
|
||||
this.connectionPool = okHttpClient.connectionPool;
|
||||
this.network = okHttpClient.network;
|
||||
this.followSslRedirects = okHttpClient.followSslRedirects;
|
||||
this.followRedirects = okHttpClient.followRedirects;
|
||||
this.connectTimeout = okHttpClient.connectTimeout;
|
||||
this.readTimeout = okHttpClient.readTimeout;
|
||||
this.writeTimeout = okHttpClient.writeTimeout;
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -15,7 +15,6 @@
|
||||
*/
|
||||
package com.squareup.okhttp;
|
||||
|
||||
import com.squareup.okhttp.internal.http.RouteSelector;
|
||||
import java.net.InetSocketAddress;
|
||||
import java.net.Proxy;
|
||||
|
||||
@@ -29,8 +28,8 @@ import java.net.Proxy;
|
||||
* <li><strong>IP address:</strong> whether connecting directly to an origin
|
||||
* server or a proxy, opening a socket requires an IP address. The DNS
|
||||
* server may return multiple IP addresses to attempt.
|
||||
* <li><strong>TLS version:</strong> which TLS version to attempt with the
|
||||
* HTTPS connection.
|
||||
* <li><strong>TLS configuration:</strong> which cipher suites and TLS
|
||||
* versions to attempt with the HTTPS connection.
|
||||
* </ul>
|
||||
* Each route is a specific selection of these options.
|
||||
*/
|
||||
@@ -38,18 +37,25 @@ public final class Route {
|
||||
final Address address;
|
||||
final Proxy proxy;
|
||||
final InetSocketAddress inetSocketAddress;
|
||||
final String tlsVersion;
|
||||
final TlsConfiguration tlsConfiguration;
|
||||
|
||||
/** @deprecated replaced with a constructor that takes a {@link TlsConfiguration}. */
|
||||
public Route(Address address, Proxy proxy, InetSocketAddress inetSocketAddress,
|
||||
String tlsVersion) {
|
||||
this(address, proxy, inetSocketAddress,
|
||||
tlsVersion.equals("SSLv3") ? TlsConfiguration.PREFERRED : TlsConfiguration.FALLBACK);
|
||||
}
|
||||
|
||||
public Route(Address address, Proxy proxy, InetSocketAddress inetSocketAddress,
|
||||
TlsConfiguration tlsConfiguration) {
|
||||
if (address == null) throw new NullPointerException("address == null");
|
||||
if (proxy == null) throw new NullPointerException("proxy == null");
|
||||
if (inetSocketAddress == null) throw new NullPointerException("inetSocketAddress == null");
|
||||
if (tlsVersion == null) throw new NullPointerException("tlsVersion == null");
|
||||
if (tlsConfiguration == null) throw new NullPointerException("tlsConfiguration == null");
|
||||
this.address = address;
|
||||
this.proxy = proxy;
|
||||
this.inetSocketAddress = inetSocketAddress;
|
||||
this.tlsVersion = tlsVersion;
|
||||
this.tlsConfiguration = tlsConfiguration;
|
||||
}
|
||||
|
||||
public Address getAddress() {
|
||||
@@ -67,16 +73,17 @@ public final class Route {
|
||||
return proxy;
|
||||
}
|
||||
|
||||
/** @deprecated replaced with {@link #getTlsConfiguration()}. */
|
||||
public String getTlsVersion() {
|
||||
return tlsConfiguration.tlsVersions().get(0);
|
||||
}
|
||||
|
||||
public InetSocketAddress getSocketAddress() {
|
||||
return inetSocketAddress;
|
||||
}
|
||||
|
||||
public String getTlsVersion() {
|
||||
return tlsVersion;
|
||||
}
|
||||
|
||||
boolean supportsNpn() {
|
||||
return !tlsVersion.equals(RouteSelector.SSL_V3);
|
||||
public TlsConfiguration getTlsConfiguration() {
|
||||
return tlsConfiguration;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -93,7 +100,7 @@ public final class Route {
|
||||
return address.equals(other.address)
|
||||
&& proxy.equals(other.proxy)
|
||||
&& inetSocketAddress.equals(other.inetSocketAddress)
|
||||
&& tlsVersion.equals(other.tlsVersion);
|
||||
&& tlsConfiguration.equals(other.tlsConfiguration);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
@@ -103,7 +110,7 @@ public final class Route {
|
||||
result = 31 * result + address.hashCode();
|
||||
result = 31 * result + proxy.hashCode();
|
||||
result = 31 * result + inetSocketAddress.hashCode();
|
||||
result = 31 * result + tlsVersion.hashCode();
|
||||
result = 31 * result + tlsConfiguration.hashCode();
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
||||
127
okhttp/src/main/java/com/squareup/okhttp/TlsConfiguration.java
Normal file
127
okhttp/src/main/java/com/squareup/okhttp/TlsConfiguration.java
Normal file
@@ -0,0 +1,127 @@
|
||||
/*
|
||||
* Copyright (C) 2014 Square, Inc.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package com.squareup.okhttp;
|
||||
|
||||
import com.squareup.okhttp.internal.Platform;
|
||||
import com.squareup.okhttp.internal.Util;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
import javax.net.ssl.SSLSocket;
|
||||
|
||||
/**
|
||||
* The TLS version and ciphers used to negotiate a secure connection. */
|
||||
public final class TlsConfiguration {
|
||||
/**
|
||||
* This is a subset of the cipher suites supported in Chrome 37, current as of 2014-10-5. All of
|
||||
* these suites are available on Android L; earlier releases support a subset of these suites.
|
||||
* https://github.com/square/okhttp/issues/330
|
||||
*/
|
||||
private static final String[] CIPHER_SUITES = new String[] {
|
||||
"TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256", // 0xC0,0x2B Android L
|
||||
"TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256", // 0xC0,0x2F Android L
|
||||
"TLS_DHE_RSA_WITH_AES_128_GCM_SHA256", // 0x00,0x9E Android L
|
||||
"TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA", // 0xC0,0x0A Android 4.0
|
||||
"TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA", // 0xC0,0x09 Android 4.0
|
||||
"TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA", // 0xC0,0x13 Android 4.0
|
||||
"TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA", // 0xC0,0x14 Android 4.0
|
||||
"TLS_ECDHE_ECDSA_WITH_RC4_128_SHA", // 0xC0,0x07 Android 4.0
|
||||
"TLS_ECDHE_RSA_WITH_RC4_128_SHA", // 0xC0,0x11 Android 4.0
|
||||
"TLS_DHE_RSA_WITH_AES_128_CBC_SHA", // 0x00,0x33 Android 2.3
|
||||
"TLS_DHE_DSS_WITH_AES_128_CBC_SHA", // 0x00,0x32 Android 2.3
|
||||
"TLS_DHE_RSA_WITH_AES_256_CBC_SHA", // 0x00,0x39 Android 2.3
|
||||
"TLS_RSA_WITH_AES_128_GCM_SHA256", // 0x00,0x9C Android L
|
||||
"TLS_RSA_WITH_AES_128_CBC_SHA", // 0x00,0x2F Android 2.3
|
||||
"TLS_RSA_WITH_AES_256_CBC_SHA", // 0x00,0x35 Android 2.3
|
||||
"SSL_RSA_WITH_3DES_EDE_CBC_SHA", // 0x00,0x0A Android 2.3 (Deprecated in L)
|
||||
"SSL_RSA_WITH_RC4_128_SHA", // 0x00,0x05 Android 2.3
|
||||
"SSL_RSA_WITH_RC4_128_MD5" // 0x00,0x04 Android 2.3 (Deprecated in L)
|
||||
};
|
||||
|
||||
private static final String TLS_1_2 = "TLSv1.2"; // 2008.
|
||||
private static final String TLS_1_1 = "TLSv1.1"; // 2006.
|
||||
private static final String TLS_1_0 = "TLSv1"; // 1999.
|
||||
private static final String SSL_3_0 = "SSLv3"; // 1996.
|
||||
|
||||
/** A modern TLS configuration with extensions like SNI and ALPN available. */
|
||||
public static final TlsConfiguration PREFERRED = new TlsConfiguration(
|
||||
CIPHER_SUITES, new String[] { TLS_1_2, TLS_1_1, TLS_1_0, SSL_3_0 }, true);
|
||||
|
||||
/** A backwards-compatible fallback configuration for interop with obsolete servers. */
|
||||
public static final TlsConfiguration FALLBACK = new TlsConfiguration(
|
||||
CIPHER_SUITES, new String[] { SSL_3_0 }, true);
|
||||
|
||||
private final String[] cipherSuites;
|
||||
private final String[] tlsVersions;
|
||||
private final boolean supportsTlsExtensions;
|
||||
|
||||
/**
|
||||
* Caches the subset of this TLS configuration that's supported by the platform. It's possible
|
||||
* that the platform hosts multiple implementations of {@link SSLSocket}, in which case this cache
|
||||
* will be incorrect.
|
||||
*/
|
||||
private TlsConfiguration supportedConfiguration;
|
||||
|
||||
private TlsConfiguration(String[] cipherSuites, String[] tlsVersions,
|
||||
boolean supportsTlsExtensions) {
|
||||
this.cipherSuites = cipherSuites;
|
||||
this.tlsVersions = tlsVersions;
|
||||
this.supportsTlsExtensions = supportsTlsExtensions;
|
||||
}
|
||||
|
||||
public List<String> cipherSuites() {
|
||||
return Util.immutableList(cipherSuites);
|
||||
}
|
||||
|
||||
public List<String> tlsVersions() {
|
||||
return Util.immutableList(tlsVersions);
|
||||
}
|
||||
|
||||
public boolean supportsTlsExtensions() {
|
||||
return supportsTlsExtensions;
|
||||
}
|
||||
|
||||
/** Applies this configuration to {@code sslSocket} for {@code route}. */
|
||||
public void apply(SSLSocket sslSocket, Route route) {
|
||||
TlsConfiguration configurationToApply = supportedConfiguration;
|
||||
if (configurationToApply == null) {
|
||||
configurationToApply = supportedConfiguration(sslSocket);
|
||||
supportedConfiguration = configurationToApply;
|
||||
}
|
||||
|
||||
sslSocket.setEnabledProtocols(configurationToApply.tlsVersions);
|
||||
sslSocket.setEnabledCipherSuites(configurationToApply.cipherSuites);
|
||||
|
||||
Platform platform = Platform.get();
|
||||
if (configurationToApply.supportsTlsExtensions) {
|
||||
platform.configureTlsExtensions(sslSocket, route.address.uriHost, route.address.protocols);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a copy of this that omits cipher suites and TLS versions not
|
||||
* supported by {@code sslSocket}.
|
||||
*/
|
||||
private TlsConfiguration supportedConfiguration(SSLSocket sslSocket) {
|
||||
List<String> supportedCipherSuites = Util.intersect(Arrays.asList(cipherSuites),
|
||||
Arrays.asList(sslSocket.getSupportedCipherSuites()));
|
||||
List<String> supportedTlsVersions = Util.intersect(Arrays.asList(tlsVersions),
|
||||
Arrays.asList(sslSocket.getSupportedProtocols()));
|
||||
return new TlsConfiguration(
|
||||
supportedCipherSuites.toArray(new String[supportedCipherSuites.size()]),
|
||||
supportedTlsVersions.toArray(new String[supportedTlsVersions.size()]),
|
||||
supportsTlsExtensions);
|
||||
}
|
||||
}
|
||||
@@ -37,6 +37,7 @@ import okio.Buffer;
|
||||
|
||||
/**
|
||||
* Access to Platform-specific features necessary for SPDY and advanced TLS.
|
||||
* This includes Server Name Indication (SNI) and session tickets.
|
||||
*
|
||||
* <h3>ALPN and NPN</h3>
|
||||
* This class uses TLS extensions ALPN and NPN to negotiate the upgrade from
|
||||
@@ -84,17 +85,13 @@ public class Platform {
|
||||
}
|
||||
|
||||
/**
|
||||
* Configure the TLS connection to use {@code tlsVersion}. We also bundle
|
||||
* certain extensions with certain versions. In particular, we enable Server
|
||||
* Name Indication (SNI) and Next Protocol Negotiation (NPN) with TLSv1 on
|
||||
* platforms that support them.
|
||||
* Configure TLS extensions on {@code sslSocket} for {@code route}.
|
||||
*
|
||||
* @param hostname non-null for client-side handshakes; null for
|
||||
* server-side handshakes.
|
||||
*/
|
||||
public void configureTls(SSLSocket socket, String uriHost, String tlsVersion) {
|
||||
// We don't call setEnabledProtocols("TLSv1") on the assumption that that's
|
||||
// the default. TODO: confirm this and support more TLS versions.
|
||||
if (tlsVersion.equals("SSLv3")) {
|
||||
socket.setEnabledProtocols(new String[] {"SSLv3"});
|
||||
}
|
||||
public void configureTlsExtensions(SSLSocket sslSocket, String hostname,
|
||||
List<Protocol> protocols) {
|
||||
}
|
||||
|
||||
/** Returns the negotiated protocol, or null if no protocol was negotiated. */
|
||||
@@ -102,13 +99,6 @@ public class Platform {
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets client-supported protocols on a socket to send to a server. The
|
||||
* protocols are only sent if the socket implementation supports ALPN or NPN.
|
||||
*/
|
||||
public void setProtocols(SSLSocket socket, List<Protocol> protocols) {
|
||||
}
|
||||
|
||||
public void connectSocket(Socket socket, InetSocketAddress address,
|
||||
int connectTimeout) throws IOException {
|
||||
socket.connect(address, connectTimeout);
|
||||
@@ -227,31 +217,32 @@ public class Platform {
|
||||
}
|
||||
}
|
||||
|
||||
@Override public void configureTls(SSLSocket socket, String uriHost, String tlsVersion) {
|
||||
super.configureTls(socket, uriHost, tlsVersion);
|
||||
@Override public void configureTlsExtensions(
|
||||
SSLSocket sslSocket, String hostname, List<Protocol> protocols) {
|
||||
if (!openSslSocketClass.isInstance(sslSocket)) return;
|
||||
|
||||
if (tlsVersion.equals("TLSv1") && openSslSocketClass.isInstance(socket)) {
|
||||
// Enable SNI and session tickets.
|
||||
if (hostname != null) {
|
||||
try {
|
||||
setUseSessionTickets.invoke(socket, true);
|
||||
setHostname.invoke(socket, uriHost);
|
||||
setUseSessionTickets.invoke(sslSocket, true);
|
||||
setHostname.invoke(sslSocket, hostname);
|
||||
} catch (InvocationTargetException e) {
|
||||
throw new RuntimeException(e);
|
||||
throw new RuntimeException(e.getCause());
|
||||
} catch (IllegalAccessException e) {
|
||||
throw new AssertionError(e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override public void setProtocols(SSLSocket socket, List<Protocol> protocols) {
|
||||
if (setNpnProtocols == null) return;
|
||||
if (!openSslSocketClass.isInstance(socket)) return;
|
||||
try {
|
||||
Object[] parameters = { concatLengthPrefixed(protocols) };
|
||||
setNpnProtocols.invoke(socket, parameters);
|
||||
} catch (IllegalAccessException e) {
|
||||
throw new AssertionError(e);
|
||||
} catch (InvocationTargetException e) {
|
||||
throw new RuntimeException(e);
|
||||
// Enable NPN.
|
||||
if (setNpnProtocols != null) {
|
||||
try {
|
||||
Object[] parameters = { concatLengthPrefixed(protocols) };
|
||||
setNpnProtocols.invoke(sslSocket, parameters);
|
||||
} catch (IllegalAccessException e) {
|
||||
throw new AssertionError(e);
|
||||
} catch (InvocationTargetException e) {
|
||||
throw new RuntimeException(e.getCause());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -263,7 +254,7 @@ public class Platform {
|
||||
if (npnResult == null) return null;
|
||||
return new String(npnResult, Util.UTF_8);
|
||||
} catch (InvocationTargetException e) {
|
||||
throw new RuntimeException(e);
|
||||
throw new RuntimeException(e.getCause());
|
||||
} catch (IllegalAccessException e) {
|
||||
throw new AssertionError(e);
|
||||
}
|
||||
@@ -277,7 +268,7 @@ public class Platform {
|
||||
} catch (IllegalAccessException e) {
|
||||
throw new RuntimeException(e);
|
||||
} catch (InvocationTargetException e) {
|
||||
throw new RuntimeException(e);
|
||||
throw new RuntimeException(e.getCause());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -289,7 +280,7 @@ public class Platform {
|
||||
} catch (IllegalAccessException e) {
|
||||
throw new RuntimeException(e);
|
||||
} catch (InvocationTargetException e) {
|
||||
throw new RuntimeException(e);
|
||||
throw new RuntimeException(e.getCause());
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -312,17 +303,18 @@ public class Platform {
|
||||
this.serverProviderClass = serverProviderClass;
|
||||
}
|
||||
|
||||
@Override public void setProtocols(SSLSocket socket, List<Protocol> protocols) {
|
||||
@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 NPN or ALPN.
|
||||
names.add(protocol.toString());
|
||||
}
|
||||
try {
|
||||
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 NPN or ALPN.
|
||||
names.add(protocol.toString());
|
||||
}
|
||||
Object provider = Proxy.newProxyInstance(Platform.class.getClassLoader(),
|
||||
new Class[] { clientProviderClass, serverProviderClass }, new JettyNegoProvider(names));
|
||||
putMethod.invoke(null, socket, provider);
|
||||
putMethod.invoke(null, sslSocket, provider);
|
||||
} catch (InvocationTargetException e) {
|
||||
throw new AssertionError(e);
|
||||
} catch (IllegalAccessException e) {
|
||||
|
||||
@@ -19,12 +19,14 @@ import com.squareup.okhttp.Address;
|
||||
import com.squareup.okhttp.CertificatePinner;
|
||||
import com.squareup.okhttp.Connection;
|
||||
import com.squareup.okhttp.ConnectionPool;
|
||||
import com.squareup.okhttp.internal.Network;
|
||||
import com.squareup.okhttp.OkHttpClient;
|
||||
import com.squareup.okhttp.Request;
|
||||
import com.squareup.okhttp.Route;
|
||||
import com.squareup.okhttp.TlsConfiguration;
|
||||
import com.squareup.okhttp.internal.Internal;
|
||||
import com.squareup.okhttp.internal.Network;
|
||||
import com.squareup.okhttp.internal.RouteDatabase;
|
||||
import com.squareup.okhttp.internal.Util;
|
||||
import java.io.IOException;
|
||||
import java.net.InetAddress;
|
||||
import java.net.InetSocketAddress;
|
||||
@@ -50,8 +52,8 @@ import static com.squareup.okhttp.internal.Util.getEffectivePort;
|
||||
* recycled.
|
||||
*/
|
||||
public final class RouteSelector {
|
||||
public static final String TLS_V1 = "TLSv1";
|
||||
public static final String SSL_V3 = "SSLv3";
|
||||
public static final List<TlsConfiguration> TLS_CONFIGURATIONS = Util.immutableList(
|
||||
TlsConfiguration.PREFERRED, TlsConfiguration.FALLBACK);
|
||||
|
||||
private final Address address;
|
||||
private final URI uri;
|
||||
@@ -76,8 +78,8 @@ public final class RouteSelector {
|
||||
private int nextSocketAddressIndex;
|
||||
private int socketPort;
|
||||
|
||||
/* TLS version to attempt with the connection. */
|
||||
private String nextTlsVersion;
|
||||
/* TLS configuration to attempt with the connection. */
|
||||
private int nextTlsConfigurationIndex = TLS_CONFIGURATIONS.size();
|
||||
|
||||
/* State for negotiating failed routes */
|
||||
private final List<Route> postponedRoutes = new ArrayList<>();
|
||||
@@ -122,7 +124,7 @@ public final class RouteSelector {
|
||||
* least one route.
|
||||
*/
|
||||
public boolean hasNext() {
|
||||
return hasNextTlsVersion()
|
||||
return hasNextTlsConfiguration()
|
||||
|| hasNextInetSocketAddress()
|
||||
|| hasNextProxy()
|
||||
|| hasNextPostponed();
|
||||
@@ -148,7 +150,7 @@ public final class RouteSelector {
|
||||
}
|
||||
|
||||
// Compute the next route to attempt.
|
||||
if (!hasNextTlsVersion()) {
|
||||
if (!hasNextTlsConfiguration()) {
|
||||
if (!hasNextInetSocketAddress()) {
|
||||
if (!hasNextProxy()) {
|
||||
if (!hasNextPostponed()) {
|
||||
@@ -160,11 +162,11 @@ public final class RouteSelector {
|
||||
resetNextInetSocketAddress(lastProxy);
|
||||
}
|
||||
lastInetSocketAddress = nextInetSocketAddress();
|
||||
resetNextTlsVersion();
|
||||
resetNextTlsConfiguration();
|
||||
}
|
||||
|
||||
String tlsVersion = nextTlsVersion();
|
||||
Route route = new Route(address, lastProxy, lastInetSocketAddress, tlsVersion);
|
||||
TlsConfiguration tlsConfiguration = nextTlsConfiguration();
|
||||
Route route = new Route(address, lastProxy, lastInetSocketAddress, tlsConfiguration);
|
||||
if (routeDatabase.shouldPostpone(route)) {
|
||||
postponedRoutes.add(route);
|
||||
// We will only recurse in order to skip previously failed routes. They will be
|
||||
@@ -195,8 +197,9 @@ public final class RouteSelector {
|
||||
// the next route only changes the TLS mode, we shouldn't even attempt it.
|
||||
// This suppresses it in both this selector and also in the route database.
|
||||
if (!(failure instanceof SSLHandshakeException) && !(failure instanceof SSLProtocolException)) {
|
||||
while (hasNextTlsVersion()) {
|
||||
Route toSuppress = new Route(address, lastProxy, lastInetSocketAddress, nextTlsVersion());
|
||||
while (hasNextTlsConfiguration()) {
|
||||
Route toSuppress = new Route(address, lastProxy, lastInetSocketAddress,
|
||||
nextTlsConfiguration());
|
||||
routeDatabase.failed(toSuppress);
|
||||
}
|
||||
}
|
||||
@@ -286,31 +289,25 @@ public final class RouteSelector {
|
||||
}
|
||||
|
||||
/**
|
||||
* Resets {@link #nextTlsVersion} to the first option. For routes that don't
|
||||
* use SSL, this returns {@link #SSL_V3} so that there is no SSL fallback.
|
||||
* Resets {@link #nextTlsConfiguration} to the first option. For routes that
|
||||
* don't use TLS, this returns the fallback parameters so that there are no
|
||||
* unnecessary retries.
|
||||
*/
|
||||
private void resetNextTlsVersion() {
|
||||
nextTlsVersion = (address.getSslSocketFactory() != null) ? TLS_V1 : SSL_V3;
|
||||
private void resetNextTlsConfiguration() {
|
||||
nextTlsConfigurationIndex = address.getSslSocketFactory() != null
|
||||
? 0
|
||||
: TLS_CONFIGURATIONS.size() - 1;
|
||||
}
|
||||
|
||||
/** Returns true if there's another TLS version to try. */
|
||||
private boolean hasNextTlsVersion() {
|
||||
return nextTlsVersion != null;
|
||||
/** Returns true if there's another TLS configuration to try. */
|
||||
private boolean hasNextTlsConfiguration() {
|
||||
return nextTlsConfigurationIndex < TLS_CONFIGURATIONS.size();
|
||||
}
|
||||
|
||||
/** Returns the next TLS mode to try. */
|
||||
private String nextTlsVersion() {
|
||||
if (nextTlsVersion == null) {
|
||||
throw new IllegalStateException("No next TLS version");
|
||||
} else if (nextTlsVersion.equals(TLS_V1)) {
|
||||
nextTlsVersion = SSL_V3;
|
||||
return TLS_V1;
|
||||
} else if (nextTlsVersion.equals(SSL_V3)) {
|
||||
nextTlsVersion = null; // So that hasNextTlsVersion() returns false.
|
||||
return SSL_V3;
|
||||
} else {
|
||||
throw new AssertionError();
|
||||
}
|
||||
/** Returns the next TLS configuration to try. */
|
||||
private TlsConfiguration nextTlsConfiguration() {
|
||||
if (!hasNextTlsConfiguration()) throw new IllegalStateException("No next TLS configuration");
|
||||
return TLS_CONFIGURATIONS.get(nextTlsConfigurationIndex++);
|
||||
}
|
||||
|
||||
/** Returns true if there is another postponed route to try. */
|
||||
|
||||
Reference in New Issue
Block a user