1
0
mirror of https://github.com/square/okhttp.git synced 2026-01-18 20:40:58 +03:00

Merge pull request #1299 from nfuller/ConnectionRouteSelection2

Refactoring: Make RouteSelector independent of Connection
This commit is contained in:
Jesse Wilson
2015-01-13 17:09:54 -05:00
3 changed files with 151 additions and 129 deletions

View File

@@ -17,12 +17,12 @@ package com.squareup.okhttp.internal.http;
import com.squareup.okhttp.Address;
import com.squareup.okhttp.Authenticator;
import com.squareup.okhttp.Connection;
import com.squareup.okhttp.ConnectionSpec;
import com.squareup.okhttp.ConnectionPool;
import com.squareup.okhttp.ConnectionSpec;
import com.squareup.okhttp.OkHttpClient;
import com.squareup.okhttp.Protocol;
import com.squareup.okhttp.Request;
import com.squareup.okhttp.Route;
import com.squareup.okhttp.internal.Internal;
import com.squareup.okhttp.internal.Network;
import com.squareup.okhttp.internal.RouteDatabase;
@@ -110,17 +110,17 @@ public final class RouteSelectorTest {
@Test public void singleRoute() throws Exception {
Address address = httpAddress();
RouteSelector routeSelector = RouteSelector.get(httpRequest, client);
RouteSelector routeSelector = RouteSelector.get(address, httpRequest, client);
assertTrue(routeSelector.hasNext());
dns.inetAddresses = makeFakeAddresses(255, 1);
assertConnection(routeSelector.nextUnconnected(), address, NO_PROXY, dns.inetAddresses[0],
assertRoute(routeSelector.next(), address, NO_PROXY, dns.inetAddresses[0],
uriPort, ConnectionSpec.CLEARTEXT);
dns.assertRequests(uriHost);
assertFalse(routeSelector.hasNext());
try {
routeSelector.nextUnconnected();
routeSelector.next();
fail();
} catch (NoSuchElementException expected) {
}
@@ -128,18 +128,18 @@ public final class RouteSelectorTest {
@Test public void singleRouteReturnsFailedRoute() throws Exception {
Address address = httpAddress();
RouteSelector routeSelector = RouteSelector.get(httpRequest, client);
RouteSelector routeSelector = RouteSelector.get(address, httpRequest, client);
assertTrue(routeSelector.hasNext());
dns.inetAddresses = makeFakeAddresses(255, 1);
Connection connection = routeSelector.nextUnconnected();
routeDatabase.failed(connection.getRoute());
routeSelector = RouteSelector.get(httpRequest, client);
assertConnection(routeSelector.nextUnconnected(), address, NO_PROXY, dns.inetAddresses[0],
Route route = routeSelector.next();
routeDatabase.failed(route);
routeSelector = RouteSelector.get(address, httpRequest, client);
assertRoute(routeSelector.next(), address, NO_PROXY, dns.inetAddresses[0],
uriPort, ConnectionSpec.CLEARTEXT);
assertFalse(routeSelector.hasNext());
try {
routeSelector.nextUnconnected();
routeSelector.next();
fail();
} catch (NoSuchElementException expected) {
}
@@ -149,13 +149,13 @@ public final class RouteSelectorTest {
Address address = new Address(uriHost, uriPort, socketFactory, null, null, null, authenticator,
proxyA, protocols, connectionSpecs, proxySelector);
client.setProxy(proxyA);
RouteSelector routeSelector = RouteSelector.get(httpRequest, client);
RouteSelector routeSelector = RouteSelector.get(address, httpRequest, client);
assertTrue(routeSelector.hasNext());
dns.inetAddresses = makeFakeAddresses(255, 2);
assertConnection(routeSelector.nextUnconnected(), address, proxyA, dns.inetAddresses[0],
assertRoute(routeSelector.next(), address, proxyA, dns.inetAddresses[0],
proxyAPort, ConnectionSpec.CLEARTEXT);
assertConnection(routeSelector.nextUnconnected(), address, proxyA, dns.inetAddresses[1],
assertRoute(routeSelector.next(), address, proxyA, dns.inetAddresses[1],
proxyAPort, ConnectionSpec.CLEARTEXT);
assertFalse(routeSelector.hasNext());
@@ -167,13 +167,13 @@ public final class RouteSelectorTest {
Address address = new Address(uriHost, uriPort, socketFactory, null, null, null, authenticator,
NO_PROXY, protocols, connectionSpecs, proxySelector);
client.setProxy(NO_PROXY);
RouteSelector routeSelector = RouteSelector.get(httpRequest, client);
RouteSelector routeSelector = RouteSelector.get(address, httpRequest, client);
assertTrue(routeSelector.hasNext());
dns.inetAddresses = makeFakeAddresses(255, 2);
assertConnection(routeSelector.nextUnconnected(), address, NO_PROXY, dns.inetAddresses[0],
assertRoute(routeSelector.next(), address, NO_PROXY, dns.inetAddresses[0],
uriPort, ConnectionSpec.CLEARTEXT);
assertConnection(routeSelector.nextUnconnected(), address, NO_PROXY, dns.inetAddresses[1],
assertRoute(routeSelector.next(), address, NO_PROXY, dns.inetAddresses[1],
uriPort, ConnectionSpec.CLEARTEXT);
assertFalse(routeSelector.hasNext());
@@ -185,12 +185,12 @@ public final class RouteSelectorTest {
Address address = httpAddress();
proxySelector.proxies = null;
RouteSelector routeSelector = RouteSelector.get(httpRequest, client);
RouteSelector routeSelector = RouteSelector.get(address, httpRequest, client);
proxySelector.assertRequests(httpRequest.uri());
assertTrue(routeSelector.hasNext());
dns.inetAddresses = makeFakeAddresses(255, 1);
assertConnection(routeSelector.nextUnconnected(), address, NO_PROXY, dns.inetAddresses[0],
assertRoute(routeSelector.next(), address, NO_PROXY, dns.inetAddresses[0],
uriPort, ConnectionSpec.CLEARTEXT);
dns.assertRequests(uriHost);
@@ -199,13 +199,13 @@ public final class RouteSelectorTest {
@Test public void proxySelectorReturnsNoProxies() throws Exception {
Address address = httpAddress();
RouteSelector routeSelector = RouteSelector.get(httpRequest, client);
RouteSelector routeSelector = RouteSelector.get(address, httpRequest, client);
assertTrue(routeSelector.hasNext());
dns.inetAddresses = makeFakeAddresses(255, 2);
assertConnection(routeSelector.nextUnconnected(), address, NO_PROXY, dns.inetAddresses[0],
assertRoute(routeSelector.next(), address, NO_PROXY, dns.inetAddresses[0],
uriPort, ConnectionSpec.CLEARTEXT);
assertConnection(routeSelector.nextUnconnected(), address, NO_PROXY, dns.inetAddresses[1],
assertRoute(routeSelector.next(), address, NO_PROXY, dns.inetAddresses[1],
uriPort, ConnectionSpec.CLEARTEXT);
assertFalse(routeSelector.hasNext());
@@ -218,29 +218,30 @@ public final class RouteSelectorTest {
proxySelector.proxies.add(proxyA);
proxySelector.proxies.add(proxyB);
RouteSelector routeSelector = RouteSelector.get(httpRequest, client);
RouteSelector routeSelector = RouteSelector.get(address, httpRequest, client);
proxySelector.assertRequests(httpRequest.uri());
// First try the IP addresses of the first proxy, in sequence.
assertTrue(routeSelector.hasNext());
dns.inetAddresses = makeFakeAddresses(255, 2);
assertConnection(routeSelector.nextUnconnected(), address, proxyA, dns.inetAddresses[0], proxyAPort,
assertRoute(routeSelector.next(), address, proxyA, dns.inetAddresses[0], proxyAPort,
ConnectionSpec.CLEARTEXT);
assertConnection(routeSelector.nextUnconnected(), address, proxyA, dns.inetAddresses[1], proxyAPort,
assertRoute(routeSelector.next(), address, proxyA, dns.inetAddresses[1], proxyAPort,
ConnectionSpec.CLEARTEXT);
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,
assertRoute(routeSelector.next(), address, proxyB, dns.inetAddresses[0],
proxyBPort,
ConnectionSpec.CLEARTEXT);
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,
assertRoute(routeSelector.next(), address, NO_PROXY, dns.inetAddresses[0], uriPort,
ConnectionSpec.CLEARTEXT);
dns.assertRequests(uriHost);
@@ -251,13 +252,13 @@ public final class RouteSelectorTest {
Address address = httpAddress();
proxySelector.proxies.add(NO_PROXY);
RouteSelector routeSelector = RouteSelector.get(httpRequest, client);
RouteSelector routeSelector = RouteSelector.get(address, httpRequest, client);
proxySelector.assertRequests(httpRequest.uri());
// Only the origin server will be attempted.
assertTrue(routeSelector.hasNext());
dns.inetAddresses = makeFakeAddresses(255, 1);
assertConnection(routeSelector.nextUnconnected(), address, NO_PROXY, dns.inetAddresses[0], uriPort,
assertRoute(routeSelector.next(), address, NO_PROXY, dns.inetAddresses[0], uriPort,
ConnectionSpec.CLEARTEXT);
dns.assertRequests(uriHost);
@@ -270,19 +271,19 @@ public final class RouteSelectorTest {
proxySelector.proxies.add(proxyA);
proxySelector.proxies.add(proxyB);
proxySelector.proxies.add(proxyA);
RouteSelector routeSelector = RouteSelector.get(httpRequest, client);
RouteSelector routeSelector = RouteSelector.get(address, httpRequest, client);
proxySelector.assertRequests(httpRequest.uri());
assertTrue(routeSelector.hasNext());
dns.inetAddresses = makeFakeAddresses(255, 1);
assertConnection(routeSelector.nextUnconnected(), address, proxyA, dns.inetAddresses[0],
assertRoute(routeSelector.next(), address, proxyA, dns.inetAddresses[0],
proxyAPort, ConnectionSpec.CLEARTEXT);
dns.assertRequests(proxyAHost);
assertTrue(routeSelector.hasNext());
dns.inetAddresses = null;
try {
routeSelector.nextUnconnected();
routeSelector.next();
fail();
} catch (UnknownHostException expected) {
}
@@ -290,13 +291,13 @@ public final class RouteSelectorTest {
assertTrue(routeSelector.hasNext());
dns.inetAddresses = makeFakeAddresses(255, 1);
assertConnection(routeSelector.nextUnconnected(), address, proxyA, dns.inetAddresses[0],
assertRoute(routeSelector.next(), address, proxyA, dns.inetAddresses[0],
proxyAPort, ConnectionSpec.CLEARTEXT);
dns.assertRequests(proxyAHost);
assertTrue(routeSelector.hasNext());
dns.inetAddresses = makeFakeAddresses(254, 1);
assertConnection(routeSelector.nextUnconnected(), address, NO_PROXY, dns.inetAddresses[0],
assertRoute(routeSelector.next(), address, NO_PROXY, dns.inetAddresses[0],
uriPort, ConnectionSpec.CLEARTEXT);
dns.assertRequests(uriHost);
@@ -305,99 +306,101 @@ public final class RouteSelectorTest {
// https://github.com/square/okhttp/issues/442
@Test public void nonSslErrorAddsAllTlsModesToFailedRoute() throws Exception {
Address address = httpsAddress();
client.setProxy(Proxy.NO_PROXY);
RouteSelector routeSelector = RouteSelector.get(httpsRequest, client);
RouteSelector routeSelector = RouteSelector.get(address, httpsRequest, client);
dns.inetAddresses = makeFakeAddresses(255, 1);
Connection connection = routeSelector.nextUnconnected();
routeSelector.connectFailed(connection, new IOException("Non SSL exception"));
Route route = routeSelector.next();
routeSelector.connectFailed(route, new IOException("Non SSL exception"));
assertEquals(2, routeDatabase.failedRoutesCount());
assertFalse(routeSelector.hasNext());
}
@Test public void sslErrorAddsOnlyFailedConfigurationToFailedRoute() throws Exception {
Address address = httpsAddress();
client.setProxy(Proxy.NO_PROXY);
RouteSelector routeSelector = RouteSelector.get(httpsRequest, client);
RouteSelector routeSelector = RouteSelector.get(address, httpsRequest, client);
dns.inetAddresses = makeFakeAddresses(255, 1);
Connection connection = routeSelector.nextUnconnected();
routeSelector.connectFailed(connection, new SSLHandshakeException("SSL exception"));
Route route = routeSelector.next();
routeSelector.connectFailed(route, new SSLHandshakeException("SSL exception"));
assertTrue(routeDatabase.failedRoutesCount() == 1);
assertTrue(routeSelector.hasNext());
}
@Test public void multipleProxiesMultipleInetAddressesMultipleConfigurations() throws Exception {
Address address = new Address(uriHost, uriPort, socketFactory, sslSocketFactory,
hostnameVerifier, null, authenticator, null, protocols, connectionSpecs, proxySelector);
Address address = httpsAddress();
proxySelector.proxies.add(proxyA);
proxySelector.proxies.add(proxyB);
RouteSelector routeSelector = RouteSelector.get(httpsRequest, client);
RouteSelector routeSelector = RouteSelector.get(address, httpsRequest, client);
// Proxy A
dns.inetAddresses = makeFakeAddresses(255, 2);
assertConnection(routeSelector.nextUnconnected(), address, proxyA, dns.inetAddresses[0],
assertRoute(routeSelector.next(), address, proxyA, dns.inetAddresses[0],
proxyAPort, ConnectionSpec.MODERN_TLS);
dns.assertRequests(proxyAHost);
assertConnection(routeSelector.nextUnconnected(), address, proxyA, dns.inetAddresses[0],
assertRoute(routeSelector.next(), address, proxyA, dns.inetAddresses[0],
proxyAPort, ConnectionSpec.COMPATIBLE_TLS);
assertConnection(routeSelector.nextUnconnected(), address, proxyA, dns.inetAddresses[1],
assertRoute(routeSelector.next(), address, proxyA, dns.inetAddresses[1],
proxyAPort, ConnectionSpec.MODERN_TLS);
assertConnection(routeSelector.nextUnconnected(), address, proxyA, dns.inetAddresses[1],
assertRoute(routeSelector.next(), address, proxyA, dns.inetAddresses[1],
proxyAPort, ConnectionSpec.COMPATIBLE_TLS);
// Proxy B
dns.inetAddresses = makeFakeAddresses(254, 2);
assertConnection(routeSelector.nextUnconnected(), address, proxyB, dns.inetAddresses[0],
assertRoute(routeSelector.next(), address, proxyB, dns.inetAddresses[0],
proxyBPort, ConnectionSpec.MODERN_TLS);
dns.assertRequests(proxyBHost);
assertConnection(routeSelector.nextUnconnected(), address, proxyB, dns.inetAddresses[0],
assertRoute(routeSelector.next(), address, proxyB, dns.inetAddresses[0],
proxyBPort, ConnectionSpec.COMPATIBLE_TLS);
assertConnection(routeSelector.nextUnconnected(), address, proxyB, dns.inetAddresses[1],
assertRoute(routeSelector.next(), address, proxyB, dns.inetAddresses[1],
proxyBPort, ConnectionSpec.MODERN_TLS);
assertConnection(routeSelector.nextUnconnected(), address, proxyB, dns.inetAddresses[1],
assertRoute(routeSelector.next(), address, proxyB, dns.inetAddresses[1],
proxyBPort, ConnectionSpec.COMPATIBLE_TLS);
// Origin
dns.inetAddresses = makeFakeAddresses(253, 2);
assertConnection(routeSelector.nextUnconnected(), address, NO_PROXY, dns.inetAddresses[0],
assertRoute(routeSelector.next(), address, NO_PROXY, dns.inetAddresses[0],
uriPort, ConnectionSpec.MODERN_TLS);
dns.assertRequests(uriHost);
assertConnection(routeSelector.nextUnconnected(), address, NO_PROXY, dns.inetAddresses[0],
assertRoute(routeSelector.next(), address, NO_PROXY, dns.inetAddresses[0],
uriPort, ConnectionSpec.COMPATIBLE_TLS);
assertConnection(routeSelector.nextUnconnected(), address, NO_PROXY, dns.inetAddresses[1],
assertRoute(routeSelector.next(), address, NO_PROXY, dns.inetAddresses[1],
uriPort, ConnectionSpec.MODERN_TLS);
assertConnection(routeSelector.nextUnconnected(), address, NO_PROXY, dns.inetAddresses[1],
assertRoute(routeSelector.next(), address, NO_PROXY, dns.inetAddresses[1],
uriPort, ConnectionSpec.COMPATIBLE_TLS);
assertFalse(routeSelector.hasNext());
}
@Test public void failedRoutesAreLast() throws Exception {
Address address = httpsAddress();
client.setProxy(Proxy.NO_PROXY);
RouteSelector routeSelector = RouteSelector.get(httpsRequest, client);
RouteSelector routeSelector = RouteSelector.get(address, httpsRequest, client);
dns.inetAddresses = makeFakeAddresses(255, 1);
// Extract the regular sequence of routes from selector.
List<Connection> regularRoutes = new ArrayList<>();
List<Route> regularRoutes = new ArrayList<>();
while (routeSelector.hasNext()) {
regularRoutes.add(routeSelector.nextUnconnected());
regularRoutes.add(routeSelector.next());
}
// Check that we do indeed have more than one route.
assertTrue(regularRoutes.size() > 1);
// Add first regular route as failed.
routeDatabase.failed(regularRoutes.get(0).getRoute());
routeDatabase.failed(regularRoutes.get(0));
// Reset selector
routeSelector = RouteSelector.get(httpsRequest, client);
routeSelector = RouteSelector.get(address, httpsRequest, client);
List<Connection> routesWithFailedRoute = new ArrayList<>();
List<Route> routesWithFailedRoute = new ArrayList<>();
while (routeSelector.hasNext()) {
routesWithFailedRoute.add(routeSelector.nextUnconnected());
routesWithFailedRoute.add(routeSelector.next());
}
assertEquals(regularRoutes.get(0).getRoute(),
routesWithFailedRoute.get(routesWithFailedRoute.size() - 1).getRoute());
assertEquals(regularRoutes.get(0),
routesWithFailedRoute.get(routesWithFailedRoute.size() - 1));
assertEquals(regularRoutes.size(), routesWithFailedRoute.size());
}
@@ -419,13 +422,13 @@ public final class RouteSelectorTest {
assertEquals("127.0.0.1", RouteSelector.getHostString(socketAddress));
}
private void assertConnection(Connection connection, Address address, Proxy proxy,
private void assertRoute(Route route, Address address, Proxy proxy,
InetAddress socketAddress, int socketPort, ConnectionSpec connectionSpec) {
assertEquals(address, connection.getRoute().getAddress());
assertEquals(proxy, connection.getRoute().getProxy());
assertEquals(socketAddress, connection.getRoute().getSocketAddress().getAddress());
assertEquals(socketPort, connection.getRoute().getSocketAddress().getPort());
assertEquals(connectionSpec, connection.getRoute().getConnectionSpec());
assertEquals(address, route.getAddress());
assertEquals(proxy, route.getProxy());
assertEquals(socketAddress, route.getSocketAddress().getAddress());
assertEquals(socketPort, route.getSocketAddress().getPort());
assertEquals(connectionSpec, route.getConnectionSpec());
}
/** Returns an address that's without an SSL socket factory or hostname verifier. */
@@ -434,6 +437,11 @@ public final class RouteSelectorTest {
protocols, connectionSpecs, proxySelector);
}
private Address httpsAddress() {
return new Address(uriHost, uriPort, socketFactory, sslSocketFactory,
hostnameVerifier, null, authenticator, null, protocols, connectionSpecs, proxySelector);
}
private static InetAddress[] makeFakeAddresses(int prefix, int count) {
try {
InetAddress[] result = new InetAddress[count];

View File

@@ -18,7 +18,9 @@
package com.squareup.okhttp.internal.http;
import com.squareup.okhttp.Address;
import com.squareup.okhttp.CertificatePinner;
import com.squareup.okhttp.Connection;
import com.squareup.okhttp.ConnectionPool;
import com.squareup.okhttp.Headers;
import com.squareup.okhttp.Interceptor;
import com.squareup.okhttp.MediaType;
@@ -38,12 +40,15 @@ import java.net.CookieHandler;
import java.net.ProtocolException;
import java.net.Proxy;
import java.net.URL;
import java.net.UnknownHostException;
import java.security.cert.CertificateException;
import java.util.Date;
import java.util.List;
import java.util.Map;
import javax.net.ssl.HostnameVerifier;
import javax.net.ssl.SSLHandshakeException;
import javax.net.ssl.SSLPeerUnverifiedException;
import javax.net.ssl.SSLSocketFactory;
import okio.Buffer;
import okio.BufferedSink;
import okio.BufferedSource;
@@ -109,6 +114,7 @@ public final class HttpEngine {
final OkHttpClient client;
private Connection connection;
private Address address;
private RouteSelector routeSelector;
private Route route;
private final Response priorResponse;
@@ -232,7 +238,7 @@ public final class HttpEngine {
if (networkRequest != null) {
// Open a connection unless we inherited one from a redirect.
if (connection == null) {
connect(networkRequest);
connect();
}
transport = Internal.instance.newTransport(connection, this);
@@ -302,17 +308,43 @@ public final class HttpEngine {
}
/** Connect to the origin server either directly or via a proxy. */
private void connect(Request request) throws IOException {
private void connect() throws IOException {
if (connection != null) throw new IllegalStateException();
if (routeSelector == null) {
routeSelector = RouteSelector.get(request, client);
address = createAddress(client, networkRequest);
routeSelector = RouteSelector.get(address, networkRequest, client);
}
connection = routeSelector.next(this);
connection = nextConnection();
route = connection.getRoute();
}
/**
* Returns the next connection to attempt.
*
* @throws java.util.NoSuchElementException if there are no more routes to attempt.
*/
private Connection nextConnection() throws IOException {
Connection connection = createNextConnection();
Internal.instance.connectAndSetOwner(client, connection, this, networkRequest);
return connection;
}
private Connection createNextConnection() throws IOException {
ConnectionPool pool = client.getConnectionPool();
// Always prefer pooled connections over new connections.
for (Connection pooled; (pooled = pool.get(address)) != null; ) {
if (networkRequest.method().equals("GET") || Internal.instance.isReadable(pooled)) {
return pooled;
}
pooled.getSocket().close();
}
Route route = routeSelector.next();
return new Connection(pool, route);
}
/**
* Called immediately before the transport transmits HTTP request headers.
* This is used to observe the sent time should the request be cached.
@@ -368,7 +400,7 @@ public final class HttpEngine {
*/
public HttpEngine recover(IOException e, Sink requestBodyOut) {
if (routeSelector != null && connection != null) {
routeSelector.connectFailed(connection, e);
connectFailed(routeSelector, e);
}
boolean canRetryRequestBody = requestBodyOut == null || requestBodyOut instanceof RetryableSink;
@@ -386,6 +418,13 @@ public final class HttpEngine {
forWebSocket, connection, routeSelector, (RetryableSink) requestBodyOut, priorResponse);
}
private void connectFailed(RouteSelector routeSelector, IOException e) {
// If this is a recycled connection, don't count its failure against the route.
if (Internal.instance.recycleCount(connection) > 0) return;
Route failedRoute = connection.getRoute();
routeSelector.connectFailed(failedRoute, e);
}
public HttpEngine recover(IOException e) {
return recover(e, requestBodyOut);
}
@@ -1009,4 +1048,26 @@ public final class HttpEngine {
&& getEffectivePort(url) == getEffectivePort(followUp)
&& url.getProtocol().equals(followUp.getProtocol());
}
private static Address createAddress(OkHttpClient client, Request request)
throws UnknownHostException {
String uriHost = request.url().getHost();
if (uriHost == null || uriHost.length() == 0) {
throw new UnknownHostException(request.url().toString());
}
SSLSocketFactory sslSocketFactory = null;
HostnameVerifier hostnameVerifier = null;
CertificatePinner certificatePinner = null;
if (request.isHttps()) {
sslSocketFactory = client.getSslSocketFactory();
hostnameVerifier = client.getHostnameVerifier();
certificatePinner = client.getCertificatePinner();
}
return new Address(uriHost, getEffectivePort(request.url()),
client.getSocketFactory(), sslSocketFactory, hostnameVerifier, certificatePinner,
client.getAuthenticator(), client.getProxy(), client.getProtocols(),
client.getConnectionSpecs(), client.getProxySelector());
}
}

View File

@@ -16,9 +16,6 @@
package com.squareup.okhttp.internal.http;
import com.squareup.okhttp.Address;
import com.squareup.okhttp.CertificatePinner;
import com.squareup.okhttp.Connection;
import com.squareup.okhttp.ConnectionPool;
import com.squareup.okhttp.ConnectionSpec;
import com.squareup.okhttp.OkHttpClient;
import com.squareup.okhttp.Request;
@@ -38,10 +35,8 @@ import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.NoSuchElementException;
import javax.net.ssl.HostnameVerifier;
import javax.net.ssl.SSLHandshakeException;
import javax.net.ssl.SSLProtocolException;
import javax.net.ssl.SSLSocketFactory;
import static com.squareup.okhttp.internal.Util.getEffectivePort;
@@ -55,7 +50,6 @@ public final class RouteSelector {
private final URI uri;
private final Network network;
private final OkHttpClient client;
private final ConnectionPool pool;
private final RouteDatabase routeDatabase;
private final Request request;
@@ -83,7 +77,6 @@ public final class RouteSelector {
this.address = address;
this.uri = uri;
this.client = client;
this.pool = client.getConnectionPool();
this.routeDatabase = Internal.instance.routeDatabase(client);
this.network = Internal.instance.network(client);
this.request = request;
@@ -91,26 +84,8 @@ public final class RouteSelector {
resetNextProxy(uri, address.getProxy());
}
public static RouteSelector get(Request request, OkHttpClient client) throws IOException {
String uriHost = request.url().getHost();
if (uriHost == null || uriHost.length() == 0) {
throw new UnknownHostException(request.url().toString());
}
SSLSocketFactory sslSocketFactory = null;
HostnameVerifier hostnameVerifier = null;
CertificatePinner certificatePinner = null;
if (request.isHttps()) {
sslSocketFactory = client.getSslSocketFactory();
hostnameVerifier = client.getHostnameVerifier();
certificatePinner = client.getCertificatePinner();
}
Address address = new Address(uriHost, getEffectivePort(request.url()),
client.getSocketFactory(), sslSocketFactory, hostnameVerifier, certificatePinner,
client.getAuthenticator(), client.getProxy(), client.getProtocols(),
client.getConnectionSpecs(), client.getProxySelector());
public static RouteSelector get(Address address, Request request, OkHttpClient client)
throws IOException {
return new RouteSelector(address, request.uri(), client, request);
}
@@ -125,25 +100,7 @@ public final class RouteSelector {
|| hasNextPostponed();
}
/** Selects a route to attempt and connects it if it isn't already. */
public Connection next(HttpEngine owner) throws IOException {
Connection connection = nextUnconnected();
Internal.instance.connectAndSetOwner(client, connection, owner, request);
return connection;
}
/**
* Returns the next connection to attempt.
*
* @throws NoSuchElementException if there are no more routes to attempt.
*/
Connection nextUnconnected() throws IOException {
// Always prefer pooled connections over new connections.
for (Connection pooled; (pooled = pool.get(address)) != null; ) {
if (request.method().equals("GET") || Internal.instance.isReadable(pooled)) return pooled;
pooled.getSocket().close();
}
public Route next() throws IOException {
// Compute the next route to attempt.
if (!hasNextConnectionSpec()) {
if (!hasNextInetSocketAddress()) {
@@ -151,7 +108,7 @@ public final class RouteSelector {
if (!hasNextPostponed()) {
throw new NoSuchElementException();
}
return new Connection(pool, nextPostponed());
return nextPostponed();
}
lastProxy = nextProxy();
}
@@ -165,10 +122,10 @@ public final class RouteSelector {
if (routeDatabase.shouldPostpone(route)) {
postponedRoutes.add(route);
// We will only recurse in order to skip previously failed routes. They will be tried last.
return nextUnconnected();
return next();
}
return new Connection(pool, route);
return route;
}
private boolean shouldSendTlsFallbackIndicator(ConnectionSpec connectionSpec) {
@@ -180,11 +137,7 @@ public final class RouteSelector {
* Clients should invoke this method when they encounter a connectivity
* failure on a connection returned by this route selector.
*/
public void connectFailed(Connection connection, IOException failure) {
// If this is a recycled connection, don't count its failure against the route.
if (Internal.instance.recycleCount(connection) > 0) return;
Route failedRoute = connection.getRoute();
public void connectFailed(Route failedRoute, IOException failure) {
if (failedRoute.getProxy().type() != Proxy.Type.DIRECT && address.getProxySelector() != null) {
// Tell the proxy selector when we fail to connect on a fresh connection.
address.getProxySelector().connectFailed(uri, failedRoute.getProxy().address(), failure);