diff --git a/okhttp-tests/src/test/java/com/squareup/okhttp/internal/http/RouteSelectorTest.java b/okhttp-tests/src/test/java/com/squareup/okhttp/internal/http/RouteSelectorTest.java index f69b10db0..8efd308f7 100644 --- a/okhttp-tests/src/test/java/com/squareup/okhttp/internal/http/RouteSelectorTest.java +++ b/okhttp-tests/src/test/java/com/squareup/okhttp/internal/http/RouteSelectorTest.java @@ -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 regularRoutes = new ArrayList<>(); + List 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 routesWithFailedRoute = new ArrayList<>(); + List 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]; diff --git a/okhttp/src/main/java/com/squareup/okhttp/internal/http/HttpEngine.java b/okhttp/src/main/java/com/squareup/okhttp/internal/http/HttpEngine.java index d4d9b4cb1..643fa09e5 100644 --- a/okhttp/src/main/java/com/squareup/okhttp/internal/http/HttpEngine.java +++ b/okhttp/src/main/java/com/squareup/okhttp/internal/http/HttpEngine.java @@ -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()); + } } diff --git a/okhttp/src/main/java/com/squareup/okhttp/internal/http/RouteSelector.java b/okhttp/src/main/java/com/squareup/okhttp/internal/http/RouteSelector.java index 0700cb955..db9ae3b6c 100644 --- a/okhttp/src/main/java/com/squareup/okhttp/internal/http/RouteSelector.java +++ b/okhttp/src/main/java/com/squareup/okhttp/internal/http/RouteSelector.java @@ -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);