mirror of
https://github.com/square/okhttp.git
synced 2026-01-25 16:01:38 +03:00
Merge pull request #239 from square/jwilson/refactor_to_client
Push state from HttpURLConnectionImpl to OkHttpClient
This commit is contained in:
@@ -23,7 +23,6 @@ import com.squareup.okhttp.internal.Util;
|
||||
import com.squareup.okhttp.internal.http.HttpEngine;
|
||||
import com.squareup.okhttp.internal.http.HttpURLConnectionImpl;
|
||||
import com.squareup.okhttp.internal.http.HttpsURLConnectionImpl;
|
||||
import com.squareup.okhttp.internal.http.OkResponseCache;
|
||||
import com.squareup.okhttp.internal.http.RawHeaders;
|
||||
import com.squareup.okhttp.internal.http.ResponseHeaders;
|
||||
import java.io.BufferedWriter;
|
||||
|
||||
@@ -16,10 +16,10 @@
|
||||
package com.squareup.okhttp;
|
||||
|
||||
import com.squareup.okhttp.internal.Util;
|
||||
import com.squareup.okhttp.internal.http.Dispatcher;
|
||||
import com.squareup.okhttp.internal.http.HttpAuthenticator;
|
||||
import com.squareup.okhttp.internal.http.HttpURLConnectionImpl;
|
||||
import com.squareup.okhttp.internal.http.HttpsURLConnectionImpl;
|
||||
import com.squareup.okhttp.internal.http.OkResponseCache;
|
||||
import com.squareup.okhttp.internal.http.OkResponseCacheAdapter;
|
||||
import com.squareup.okhttp.internal.tls.OkHostnameVerifier;
|
||||
import java.net.CookieHandler;
|
||||
@@ -32,10 +32,7 @@ import java.net.URLConnection;
|
||||
import java.net.URLStreamHandler;
|
||||
import java.net.URLStreamHandlerFactory;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collections;
|
||||
import java.util.LinkedHashSet;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
import javax.net.ssl.HostnameVerifier;
|
||||
import javax.net.ssl.HttpsURLConnection;
|
||||
@@ -46,9 +43,10 @@ public final class OkHttpClient implements URLStreamHandlerFactory {
|
||||
private static final List<String> DEFAULT_TRANSPORTS
|
||||
= Util.immutableList(Arrays.asList("spdy/3", "http/1.1"));
|
||||
|
||||
private final RouteDatabase routeDatabase;
|
||||
private final Dispatcher dispatcher;
|
||||
private Proxy proxy;
|
||||
private List<String> transports;
|
||||
private final Set<Route> failedRoutes;
|
||||
private ProxySelector proxySelector;
|
||||
private CookieHandler cookieHandler;
|
||||
private ResponseCache responseCache;
|
||||
@@ -59,14 +57,15 @@ public final class OkHttpClient implements URLStreamHandlerFactory {
|
||||
private boolean followProtocolRedirects = true;
|
||||
private int connectTimeout;
|
||||
private int readTimeout;
|
||||
private Dispatcher dispatcher = new Dispatcher();
|
||||
|
||||
public OkHttpClient() {
|
||||
this.failedRoutes = Collections.synchronizedSet(new LinkedHashSet<Route>());
|
||||
routeDatabase = new RouteDatabase();
|
||||
dispatcher = new Dispatcher();
|
||||
}
|
||||
|
||||
private OkHttpClient(OkHttpClient copyFrom) {
|
||||
this.failedRoutes = copyFrom.failedRoutes; // Avoid allocating an unnecessary LinkedHashSet.
|
||||
routeDatabase = copyFrom.routeDatabase;
|
||||
dispatcher = copyFrom.dispatcher;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -109,7 +108,7 @@ public final class OkHttpClient implements URLStreamHandlerFactory {
|
||||
if (millis > Integer.MAX_VALUE) {
|
||||
throw new IllegalArgumentException("Timeout too large.");
|
||||
}
|
||||
connectTimeout = (int) millis;
|
||||
readTimeout = (int) millis;
|
||||
}
|
||||
|
||||
/** Default read timeout (in milliseconds). */
|
||||
@@ -181,7 +180,7 @@ public final class OkHttpClient implements URLStreamHandlerFactory {
|
||||
return responseCache;
|
||||
}
|
||||
|
||||
private OkResponseCache okResponseCache() {
|
||||
public OkResponseCache getOkResponseCache() {
|
||||
if (responseCache instanceof HttpResponseCache) {
|
||||
return ((HttpResponseCache) responseCache).okResponseCache;
|
||||
} else if (responseCache != null) {
|
||||
@@ -269,6 +268,10 @@ public final class OkHttpClient implements URLStreamHandlerFactory {
|
||||
return followProtocolRedirects;
|
||||
}
|
||||
|
||||
public RouteDatabase getRoutesDatabase() {
|
||||
return routeDatabase;
|
||||
}
|
||||
|
||||
/**
|
||||
* Configure the transports used by this client to communicate with remote
|
||||
* servers. By default this client will prefer the most efficient transport
|
||||
@@ -304,6 +307,9 @@ public final class OkHttpClient implements URLStreamHandlerFactory {
|
||||
if (transports.contains(null)) {
|
||||
throw new IllegalArgumentException("transports must not contain null");
|
||||
}
|
||||
if (transports.contains("")) {
|
||||
throw new IllegalArgumentException("transports contains an empty string");
|
||||
}
|
||||
this.transports = transports;
|
||||
return this;
|
||||
}
|
||||
@@ -331,15 +337,7 @@ public final class OkHttpClient implements URLStreamHandlerFactory {
|
||||
}
|
||||
|
||||
public HttpURLConnection open(URL url) {
|
||||
String protocol = url.getProtocol();
|
||||
OkHttpClient copy = copyWithDefaults();
|
||||
if (protocol.equals("http")) {
|
||||
return new HttpURLConnectionImpl(url, copy, copy.okResponseCache(), copy.failedRoutes);
|
||||
} else if (protocol.equals("https")) {
|
||||
return new HttpsURLConnectionImpl(url, copy, copy.okResponseCache(), copy.failedRoutes);
|
||||
} else {
|
||||
throw new IllegalArgumentException("Unexpected protocol: " + protocol);
|
||||
}
|
||||
return open(url, proxy);
|
||||
}
|
||||
|
||||
HttpURLConnection open(URL url, Proxy proxy) {
|
||||
@@ -347,18 +345,9 @@ public final class OkHttpClient implements URLStreamHandlerFactory {
|
||||
OkHttpClient copy = copyWithDefaults();
|
||||
copy.proxy = proxy;
|
||||
|
||||
HttpURLConnection connection;
|
||||
if (protocol.equals("http")) {
|
||||
connection = new HttpURLConnectionImpl(url, copy, copy.okResponseCache(), copy.failedRoutes);
|
||||
} else if (protocol.equals("https")) {
|
||||
connection = new HttpsURLConnectionImpl(url, copy, copy.okResponseCache(), copy.failedRoutes);
|
||||
} else {
|
||||
throw new IllegalArgumentException("Unexpected protocol: " + protocol);
|
||||
}
|
||||
|
||||
connection.setReadTimeout(readTimeout);
|
||||
connection.setConnectTimeout(connectTimeout);
|
||||
return connection;
|
||||
if (protocol.equals("http")) return new HttpURLConnectionImpl(url, copy);
|
||||
if (protocol.equals("https")) return new HttpsURLConnectionImpl(url, copy);
|
||||
throw new IllegalArgumentException("Unexpected protocol: " + protocol);
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -13,9 +13,8 @@
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package com.squareup.okhttp.internal.http;
|
||||
package com.squareup.okhttp;
|
||||
|
||||
import com.squareup.okhttp.ResponseSource;
|
||||
import java.io.IOException;
|
||||
import java.net.CacheRequest;
|
||||
import java.net.CacheResponse;
|
||||
@@ -29,9 +28,8 @@ import java.util.Map;
|
||||
* An extended response cache API. Unlike {@link java.net.ResponseCache}, this
|
||||
* interface supports conditional caching and statistics.
|
||||
*
|
||||
* <p>Along with the rest of the {@code internal} package, this is not a public
|
||||
* API. Applications wishing to supply their own caches must use the more
|
||||
* limited {@link java.net.ResponseCache} interface.
|
||||
* <h3>Warning: Experimental OkHttp 2.0 API</h3>
|
||||
* This class is in beta. APIs are subject to change!
|
||||
*/
|
||||
public interface OkResponseCache {
|
||||
CacheResponse get(URI uri, String requestMethod, Map<String, List<String>> requestHeaders)
|
||||
@@ -59,13 +59,13 @@ public class Route {
|
||||
return inetSocketAddress;
|
||||
}
|
||||
|
||||
/** Returns true if this route uses modern tls. */
|
||||
/** Returns true if this route uses modern TLS. */
|
||||
public boolean isModernTls() {
|
||||
return modernTls;
|
||||
}
|
||||
|
||||
/** Returns a copy of this route with flipped tls mode. */
|
||||
public Route flipTlsMode() {
|
||||
/** Returns a copy of this route with flipped TLS mode. */
|
||||
Route flipTlsMode() {
|
||||
return new Route(address, proxy, inetSocketAddress, !modernTls);
|
||||
}
|
||||
|
||||
|
||||
57
okhttp/src/main/java/com/squareup/okhttp/RouteDatabase.java
Normal file
57
okhttp/src/main/java/com/squareup/okhttp/RouteDatabase.java
Normal file
@@ -0,0 +1,57 @@
|
||||
/*
|
||||
* Copyright (C) 2013 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 java.io.IOException;
|
||||
import java.util.LinkedHashSet;
|
||||
import java.util.Set;
|
||||
import javax.net.ssl.SSLHandshakeException;
|
||||
|
||||
/**
|
||||
* A blacklist of failed routes to avoid when creating a new connection to a
|
||||
* target address. This is used so that OkHttp can learn from its mistakes: if
|
||||
* there was a failure attempting to connect to a specific IP address, proxy
|
||||
* server or TLS mode, that failure is remembered and alternate routes are
|
||||
* preferred.
|
||||
*/
|
||||
public final class RouteDatabase {
|
||||
private final Set<Route> failedRoutes = new LinkedHashSet<Route>();
|
||||
|
||||
/** Records a failure connecting to {@code failedRoute}. */
|
||||
public synchronized void failed(Route failedRoute, IOException failure) {
|
||||
failedRoutes.add(failedRoute);
|
||||
|
||||
if (!(failure instanceof SSLHandshakeException)) {
|
||||
// If the problem was not related to SSL then it will also fail with
|
||||
// a different TLS mode therefore we can be proactive about it.
|
||||
failedRoutes.add(failedRoute.flipTlsMode());
|
||||
}
|
||||
}
|
||||
|
||||
/** Records success connecting to {@code failedRoute}. */
|
||||
public synchronized void connected(Route route) {
|
||||
failedRoutes.remove(route);
|
||||
}
|
||||
|
||||
/** Returns true if {@code route} has failed recently and should be avoided. */
|
||||
public synchronized boolean shouldPostpone(Route route) {
|
||||
return failedRoutes.contains(route);
|
||||
}
|
||||
|
||||
public synchronized int failedRoutesCount() {
|
||||
return failedRoutes.size();
|
||||
}
|
||||
}
|
||||
@@ -13,8 +13,10 @@
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package com.squareup.okhttp;
|
||||
package com.squareup.okhttp.internal.http;
|
||||
|
||||
import com.squareup.okhttp.Request;
|
||||
import com.squareup.okhttp.Response;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.net.HttpURLConnection;
|
||||
@@ -26,7 +28,7 @@ import java.util.concurrent.LinkedBlockingQueue;
|
||||
import java.util.concurrent.ThreadPoolExecutor;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
class Dispatcher {
|
||||
public final class Dispatcher {
|
||||
// TODO: thread pool size should be configurable; possibly configurable per host.
|
||||
private final ThreadPoolExecutor executorService = new ThreadPoolExecutor(
|
||||
8, 8, 60, TimeUnit.SECONDS, new LinkedBlockingQueue<Runnable>());
|
||||
@@ -34,7 +36,7 @@ class Dispatcher {
|
||||
|
||||
public synchronized void enqueue(
|
||||
HttpURLConnection connection, Request request, Response.Receiver responseReceiver) {
|
||||
Job job = new Job(connection, request, responseReceiver);
|
||||
Job job = new Job(this, connection, request, responseReceiver);
|
||||
List<Job> jobsForTag = enqueuedJobs.get(request.tag());
|
||||
if (jobsForTag == null) {
|
||||
jobsForTag = new ArrayList<Job>(2);
|
||||
@@ -52,75 +54,11 @@ class Dispatcher {
|
||||
}
|
||||
}
|
||||
|
||||
private synchronized void finished(Job job) {
|
||||
synchronized void finished(Job job) {
|
||||
List<Job> jobs = enqueuedJobs.get(job.request.tag());
|
||||
if (jobs != null) jobs.remove(job);
|
||||
}
|
||||
|
||||
public class Job implements Runnable {
|
||||
private final HttpURLConnection connection;
|
||||
private final Request request;
|
||||
private final Response.Receiver responseReceiver;
|
||||
|
||||
public Job(HttpURLConnection connection, Request request, Response.Receiver responseReceiver) {
|
||||
this.connection = connection;
|
||||
this.request = request;
|
||||
this.responseReceiver = responseReceiver;
|
||||
}
|
||||
|
||||
@Override public void run() {
|
||||
try {
|
||||
sendRequest();
|
||||
Response response = readResponse();
|
||||
responseReceiver.onResponse(response);
|
||||
} catch (IOException e) {
|
||||
responseReceiver.onFailure(new Failure.Builder()
|
||||
.request(request)
|
||||
.exception(e)
|
||||
.build());
|
||||
} finally {
|
||||
connection.disconnect();
|
||||
finished(this);
|
||||
}
|
||||
}
|
||||
|
||||
private HttpURLConnection sendRequest()
|
||||
throws IOException {
|
||||
for (int i = 0; i < request.headerCount(); i++) {
|
||||
connection.addRequestProperty(request.headerName(i), request.headerValue(i));
|
||||
}
|
||||
Request.Body body = request.body();
|
||||
if (body != null) {
|
||||
connection.setDoOutput(true);
|
||||
long contentLength = body.contentLength();
|
||||
if (contentLength == -1 || contentLength > Integer.MAX_VALUE) {
|
||||
connection.setChunkedStreamingMode(0);
|
||||
} else {
|
||||
// Don't call setFixedLengthStreamingMode(long); that's only available on Java 1.7+.
|
||||
connection.setFixedLengthStreamingMode((int) contentLength);
|
||||
}
|
||||
body.writeTo(connection.getOutputStream());
|
||||
}
|
||||
return connection;
|
||||
}
|
||||
|
||||
private Response readResponse() throws IOException {
|
||||
int responseCode = connection.getResponseCode();
|
||||
Response.Builder responseBuilder = new Response.Builder(request, responseCode);
|
||||
|
||||
for (int i = 0; true; i++) {
|
||||
String name = connection.getHeaderFieldKey(i);
|
||||
if (name == null) break;
|
||||
String value = connection.getHeaderField(i);
|
||||
responseBuilder.addHeader(name, value);
|
||||
}
|
||||
|
||||
responseBuilder.body(new RealResponseBody(connection, connection.getInputStream()));
|
||||
// TODO: set redirectedBy
|
||||
return responseBuilder.build();
|
||||
}
|
||||
}
|
||||
|
||||
static class RealResponseBody extends Response.Body {
|
||||
private final HttpURLConnection connection;
|
||||
private final InputStream in;
|
||||
@@ -19,6 +19,8 @@ package com.squareup.okhttp.internal.http;
|
||||
|
||||
import com.squareup.okhttp.Address;
|
||||
import com.squareup.okhttp.Connection;
|
||||
import com.squareup.okhttp.OkHttpClient;
|
||||
import com.squareup.okhttp.OkResponseCache;
|
||||
import com.squareup.okhttp.ResponseSource;
|
||||
import com.squareup.okhttp.TunnelRequest;
|
||||
import com.squareup.okhttp.internal.Dns;
|
||||
@@ -87,6 +89,7 @@ public class HttpEngine {
|
||||
public static final int HTTP_CONTINUE = 100;
|
||||
|
||||
protected final HttpURLConnectionImpl policy;
|
||||
protected final OkHttpClient client;
|
||||
|
||||
protected final String method;
|
||||
|
||||
@@ -147,6 +150,7 @@ public class HttpEngine {
|
||||
public HttpEngine(HttpURLConnectionImpl policy, String method, RawHeaders requestHeaders,
|
||||
Connection connection, RetryableOutputStream requestBodyOut) throws IOException {
|
||||
this.policy = policy;
|
||||
this.client = policy.client;
|
||||
this.method = method;
|
||||
this.connection = connection;
|
||||
this.requestBodyOut = requestBodyOut;
|
||||
@@ -176,8 +180,9 @@ public class HttpEngine {
|
||||
|
||||
prepareRawRequestHeaders();
|
||||
initResponseSource();
|
||||
if (policy.responseCache != null) {
|
||||
policy.responseCache.trackResponse(responseSource);
|
||||
OkResponseCache responseCache = client.getOkResponseCache();
|
||||
if (responseCache != null) {
|
||||
responseCache.trackResponse(responseSource);
|
||||
}
|
||||
|
||||
// The raw response source may require the network, but the request
|
||||
@@ -197,7 +202,7 @@ public class HttpEngine {
|
||||
if (responseSource.requiresConnection()) {
|
||||
sendSocketRequest();
|
||||
} else if (connection != null) {
|
||||
policy.connectionPool.recycle(connection);
|
||||
client.getConnectionPool().recycle(connection);
|
||||
connection = null;
|
||||
}
|
||||
}
|
||||
@@ -208,15 +213,14 @@ public class HttpEngine {
|
||||
*/
|
||||
private void initResponseSource() throws IOException {
|
||||
responseSource = ResponseSource.NETWORK;
|
||||
if (!policy.getUseCaches() || policy.responseCache == null) {
|
||||
return;
|
||||
}
|
||||
if (!policy.getUseCaches()) return;
|
||||
|
||||
CacheResponse candidate =
|
||||
policy.responseCache.get(uri, method, requestHeaders.getHeaders().toMultimap(false));
|
||||
if (candidate == null) {
|
||||
return;
|
||||
}
|
||||
OkResponseCache responseCache = client.getOkResponseCache();
|
||||
if (responseCache == null) return;
|
||||
|
||||
CacheResponse candidate = responseCache.get(
|
||||
uri, method, requestHeaders.getHeaders().toMultimap(false));
|
||||
if (candidate == null) return;
|
||||
|
||||
Map<String, List<String>> responseHeadersMap = candidate.getHeaders();
|
||||
cachedResponseBody = candidate.getBody();
|
||||
@@ -274,22 +278,22 @@ public class HttpEngine {
|
||||
SSLSocketFactory sslSocketFactory = null;
|
||||
HostnameVerifier hostnameVerifier = null;
|
||||
if (uri.getScheme().equalsIgnoreCase("https")) {
|
||||
sslSocketFactory = policy.sslSocketFactory;
|
||||
hostnameVerifier = policy.hostnameVerifier;
|
||||
sslSocketFactory = client.getSslSocketFactory();
|
||||
hostnameVerifier = client.getHostnameVerifier();
|
||||
}
|
||||
Address address = new Address(uriHost, getEffectivePort(uri), sslSocketFactory,
|
||||
hostnameVerifier, policy.authenticator, policy.requestedProxy, policy.getTransports());
|
||||
routeSelector = new RouteSelector(address, uri, policy.proxySelector, policy.connectionPool,
|
||||
Dns.DEFAULT, policy.getFailedRoutes());
|
||||
hostnameVerifier, client.getAuthenticator(), client.getProxy(), client.getTransports());
|
||||
routeSelector = new RouteSelector(address, uri, client.getProxySelector(),
|
||||
client.getConnectionPool(), Dns.DEFAULT, client.getRoutesDatabase());
|
||||
}
|
||||
connection = routeSelector.next();
|
||||
if (!connection.isConnected()) {
|
||||
connection.connect(policy.getConnectTimeout(), policy.getReadTimeout(), getTunnelConfig());
|
||||
policy.connectionPool.maybeShare(connection);
|
||||
policy.getFailedRoutes().remove(connection.getRoute());
|
||||
connection.connect(client.getConnectTimeout(), client.getReadTimeout(), getTunnelConfig());
|
||||
client.getConnectionPool().maybeShare(connection);
|
||||
client.getRoutesDatabase().connected(connection.getRoute());
|
||||
}
|
||||
connected(connection);
|
||||
if (connection.getRoute().getProxy() != policy.requestedProxy) {
|
||||
if (connection.getRoute().getProxy() != client.getProxy()) {
|
||||
// Update the request line if the proxy changed; it may need a host name.
|
||||
requestHeaders.getHeaders().setRequestLine(getRequestLine());
|
||||
}
|
||||
@@ -387,20 +391,20 @@ public class HttpEngine {
|
||||
|
||||
private void maybeCache() throws IOException {
|
||||
// Are we caching at all?
|
||||
if (!policy.getUseCaches() || policy.responseCache == null) {
|
||||
return;
|
||||
}
|
||||
if (!policy.getUseCaches()) return;
|
||||
OkResponseCache responseCache = client.getOkResponseCache();
|
||||
if (responseCache == null) return;
|
||||
|
||||
HttpURLConnection connectionToCache = policy.getHttpConnectionToCache();
|
||||
|
||||
// Should we cache this response for this request?
|
||||
if (!responseHeaders.isCacheable(requestHeaders)) {
|
||||
policy.responseCache.maybeRemove(connectionToCache.getRequestMethod(), uri);
|
||||
responseCache.maybeRemove(connectionToCache.getRequestMethod(), uri);
|
||||
return;
|
||||
}
|
||||
|
||||
// Offer this request to the cache.
|
||||
cacheRequest = policy.responseCache.put(uri, connectionToCache);
|
||||
cacheRequest = responseCache.put(uri, connectionToCache);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -412,7 +416,7 @@ public class HttpEngine {
|
||||
public final void automaticallyReleaseConnectionToPool() {
|
||||
automaticallyReleaseConnectionToPool = true;
|
||||
if (connection != null && connectionReleased) {
|
||||
policy.connectionPool.recycle(connection);
|
||||
client.getConnectionPool().recycle(connection);
|
||||
connection = null;
|
||||
}
|
||||
}
|
||||
@@ -436,7 +440,7 @@ public class HttpEngine {
|
||||
Util.closeQuietly(connection);
|
||||
connection = null;
|
||||
} else if (automaticallyReleaseConnectionToPool) {
|
||||
policy.connectionPool.recycle(connection);
|
||||
client.getConnectionPool().recycle(connection);
|
||||
connection = null;
|
||||
}
|
||||
}
|
||||
@@ -524,7 +528,7 @@ public class HttpEngine {
|
||||
requestHeaders.setIfModifiedSince(new Date(ifModifiedSince));
|
||||
}
|
||||
|
||||
CookieHandler cookieHandler = policy.cookieHandler;
|
||||
CookieHandler cookieHandler = client.getCookieHandler();
|
||||
if (cookieHandler != null) {
|
||||
requestHeaders.addCookies(
|
||||
cookieHandler.get(uri, requestHeaders.getHeaders().toMultimap(false)));
|
||||
@@ -639,8 +643,9 @@ public class HttpEngine {
|
||||
release(false);
|
||||
ResponseHeaders combinedHeaders = cachedResponseHeaders.combine(responseHeaders);
|
||||
setResponse(combinedHeaders, cachedResponseBody);
|
||||
policy.responseCache.trackConditionalCacheHit();
|
||||
policy.responseCache.update(cacheResponse, policy.getHttpConnectionToCache());
|
||||
OkResponseCache responseCache = client.getOkResponseCache();
|
||||
responseCache.trackConditionalCacheHit();
|
||||
responseCache.update(cacheResponse, policy.getHttpConnectionToCache());
|
||||
return;
|
||||
} else {
|
||||
Util.closeQuietly(cachedResponseBody);
|
||||
@@ -659,7 +664,7 @@ public class HttpEngine {
|
||||
}
|
||||
|
||||
public void receiveHeaders(RawHeaders headers) throws IOException {
|
||||
CookieHandler cookieHandler = policy.cookieHandler;
|
||||
CookieHandler cookieHandler = client.getCookieHandler();
|
||||
if (cookieHandler != null) {
|
||||
cookieHandler.put(uri, headers.toMultimap(true));
|
||||
}
|
||||
|
||||
@@ -18,10 +18,7 @@
|
||||
package com.squareup.okhttp.internal.http;
|
||||
|
||||
import com.squareup.okhttp.Connection;
|
||||
import com.squareup.okhttp.ConnectionPool;
|
||||
import com.squareup.okhttp.OkAuthenticator;
|
||||
import com.squareup.okhttp.OkHttpClient;
|
||||
import com.squareup.okhttp.Route;
|
||||
import com.squareup.okhttp.internal.AbstractOutputStream;
|
||||
import com.squareup.okhttp.internal.FaultRecoveringOutputStream;
|
||||
import com.squareup.okhttp.internal.Platform;
|
||||
@@ -30,13 +27,11 @@ import java.io.FileNotFoundException;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.io.OutputStream;
|
||||
import java.net.CookieHandler;
|
||||
import java.net.HttpRetryException;
|
||||
import java.net.HttpURLConnection;
|
||||
import java.net.InetSocketAddress;
|
||||
import java.net.ProtocolException;
|
||||
import java.net.Proxy;
|
||||
import java.net.ProxySelector;
|
||||
import java.net.SocketPermission;
|
||||
import java.net.URL;
|
||||
import java.security.Permission;
|
||||
@@ -44,10 +39,8 @@ import java.security.cert.CertificateException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
import javax.net.ssl.HostnameVerifier;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
import javax.net.ssl.SSLHandshakeException;
|
||||
import javax.net.ssl.SSLSocketFactory;
|
||||
|
||||
import static com.squareup.okhttp.internal.Util.getEffectivePort;
|
||||
|
||||
@@ -83,52 +76,17 @@ public class HttpURLConnectionImpl extends HttpURLConnection {
|
||||
*/
|
||||
private static final int MAX_REPLAY_BUFFER_LENGTH = 8192;
|
||||
|
||||
private final boolean followProtocolRedirects;
|
||||
|
||||
/** The proxy requested by the client, or null for a proxy to be selected automatically. */
|
||||
final Proxy requestedProxy;
|
||||
|
||||
final ProxySelector proxySelector;
|
||||
final CookieHandler cookieHandler;
|
||||
final OkResponseCache responseCache;
|
||||
final ConnectionPool connectionPool;
|
||||
/* SSL configuration; necessary for HTTP requests that get redirected to HTTPS. */
|
||||
SSLSocketFactory sslSocketFactory;
|
||||
HostnameVerifier hostnameVerifier;
|
||||
private List<String> transports;
|
||||
OkAuthenticator authenticator;
|
||||
final Set<Route> failedRoutes;
|
||||
final OkHttpClient client;
|
||||
|
||||
private final RawHeaders rawRequestHeaders = new RawHeaders();
|
||||
|
||||
private int redirectionCount;
|
||||
private FaultRecoveringOutputStream faultRecoveringRequestBody;
|
||||
|
||||
protected IOException httpEngineFailure;
|
||||
protected HttpEngine httpEngine;
|
||||
|
||||
public HttpURLConnectionImpl(URL url, OkHttpClient client, OkResponseCache responseCache,
|
||||
Set<Route> failedRoutes) {
|
||||
public HttpURLConnectionImpl(URL url, OkHttpClient client) {
|
||||
super(url);
|
||||
this.followProtocolRedirects = client.getFollowProtocolRedirects();
|
||||
this.failedRoutes = failedRoutes;
|
||||
this.requestedProxy = client.getProxy();
|
||||
this.proxySelector = client.getProxySelector();
|
||||
this.cookieHandler = client.getCookieHandler();
|
||||
this.connectionPool = client.getConnectionPool();
|
||||
this.sslSocketFactory = client.getSslSocketFactory();
|
||||
this.hostnameVerifier = client.getHostnameVerifier();
|
||||
this.transports = client.getTransports();
|
||||
this.authenticator = client.getAuthenticator();
|
||||
this.responseCache = responseCache;
|
||||
}
|
||||
|
||||
Set<Route> getFailedRoutes() {
|
||||
return failedRoutes;
|
||||
}
|
||||
|
||||
List<String> getTransports() {
|
||||
return transports;
|
||||
this.client = client;
|
||||
}
|
||||
|
||||
@Override public final void connect() throws IOException {
|
||||
@@ -274,7 +232,7 @@ public class HttpURLConnectionImpl extends HttpURLConnection {
|
||||
String hostName = getURL().getHost();
|
||||
int hostPort = Util.getEffectivePort(getURL());
|
||||
if (usingProxy()) {
|
||||
InetSocketAddress proxyAddress = (InetSocketAddress) requestedProxy.address();
|
||||
InetSocketAddress proxyAddress = (InetSocketAddress) client.getProxy().address();
|
||||
hostName = proxyAddress.getHostName();
|
||||
hostPort = proxyAddress.getPort();
|
||||
}
|
||||
@@ -288,6 +246,22 @@ public class HttpURLConnectionImpl extends HttpURLConnection {
|
||||
return rawRequestHeaders.get(field);
|
||||
}
|
||||
|
||||
@Override public void setConnectTimeout(int timeoutMillis) {
|
||||
client.setConnectTimeout(timeoutMillis, TimeUnit.MILLISECONDS);
|
||||
}
|
||||
|
||||
@Override public int getConnectTimeout() {
|
||||
return client.getConnectTimeout();
|
||||
}
|
||||
|
||||
@Override public void setReadTimeout(int timeoutMillis) {
|
||||
client.setReadTimeout(timeoutMillis, TimeUnit.MILLISECONDS);
|
||||
}
|
||||
|
||||
@Override public int getReadTimeout() {
|
||||
return client.getReadTimeout();
|
||||
}
|
||||
|
||||
private void initHttpEngine() throws IOException {
|
||||
if (httpEngineFailure != null) {
|
||||
throw httpEngineFailure;
|
||||
@@ -468,7 +442,7 @@ public class HttpURLConnectionImpl extends HttpURLConnection {
|
||||
private Retry processResponseHeaders() throws IOException {
|
||||
Proxy selectedProxy = httpEngine.connection != null
|
||||
? httpEngine.connection.getRoute().getProxy()
|
||||
: requestedProxy;
|
||||
: client.getProxy();
|
||||
final int responseCode = getResponseCode();
|
||||
switch (responseCode) {
|
||||
case HTTP_PROXY_AUTH:
|
||||
@@ -477,7 +451,7 @@ public class HttpURLConnectionImpl extends HttpURLConnection {
|
||||
}
|
||||
// fall-through
|
||||
case HTTP_UNAUTHORIZED:
|
||||
boolean credentialsFound = HttpAuthenticator.processAuthHeader(authenticator,
|
||||
boolean credentialsFound = HttpAuthenticator.processAuthHeader(client.getAuthenticator(),
|
||||
getResponseCode(), httpEngine.getResponseHeaders().getHeaders(), rawRequestHeaders,
|
||||
selectedProxy, url);
|
||||
return credentialsFound ? Retry.SAME_CONNECTION : Retry.NONE;
|
||||
@@ -508,7 +482,7 @@ public class HttpURLConnectionImpl extends HttpURLConnection {
|
||||
return Retry.NONE; // Don't follow redirects to unsupported protocols.
|
||||
}
|
||||
boolean sameProtocol = previousUrl.getProtocol().equals(url.getProtocol());
|
||||
if (!sameProtocol && !followProtocolRedirects) {
|
||||
if (!sameProtocol && !client.getFollowProtocolRedirects()) {
|
||||
return Retry.NONE; // This client doesn't follow redirects across protocols.
|
||||
}
|
||||
boolean sameHost = previousUrl.getHost().equals(url.getHost());
|
||||
@@ -535,7 +509,8 @@ public class HttpURLConnectionImpl extends HttpURLConnection {
|
||||
}
|
||||
|
||||
@Override public final boolean usingProxy() {
|
||||
return (requestedProxy != null && requestedProxy.type() != Proxy.Type.DIRECT);
|
||||
Proxy proxy = client.getProxy();
|
||||
return proxy != null && proxy.type() != Proxy.Type.DIRECT;
|
||||
}
|
||||
|
||||
@Override public String getResponseMessage() throws IOException {
|
||||
@@ -599,37 +574,13 @@ public class HttpURLConnectionImpl extends HttpURLConnection {
|
||||
* When append == false, we require that the transport list contains "http/1.1".
|
||||
*/
|
||||
private void setTransports(String transportsString, boolean append) {
|
||||
String[] transports = transportsString.split(",", -1);
|
||||
ArrayList<String> transportsList = new ArrayList<String>();
|
||||
if (!append) {
|
||||
// If we're not appending to the list, we need to make sure
|
||||
// the list contains "http/1.1". We do this in a separate loop
|
||||
// to avoid modifying any state before we validate the input.
|
||||
boolean containsHttp = false;
|
||||
for (String transport : transports) {
|
||||
if ("http/1.1".equals(transport)) {
|
||||
containsHttp = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (!containsHttp) {
|
||||
throw new IllegalArgumentException("Transport list doesn't contain http/1.1");
|
||||
}
|
||||
} else {
|
||||
transportsList.addAll(this.transports);
|
||||
List<String> transportsList = new ArrayList<String>();
|
||||
if (append) {
|
||||
transportsList.addAll(client.getTransports());
|
||||
}
|
||||
|
||||
for (String transport : transports) {
|
||||
if (transport.length() == 0) {
|
||||
throw new IllegalArgumentException("Transport list contains an empty transport");
|
||||
}
|
||||
|
||||
if (!transportsList.contains(transport)) {
|
||||
transportsList.add(transport);
|
||||
}
|
||||
for (String transport : transportsString.split(",", -1)) {
|
||||
transportsList.add(transport);
|
||||
}
|
||||
|
||||
this.transports = Util.immutableList(transportsList);
|
||||
client.setTransports(transportsList);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -18,7 +18,6 @@ package com.squareup.okhttp.internal.http;
|
||||
|
||||
import com.squareup.okhttp.Connection;
|
||||
import com.squareup.okhttp.OkHttpClient;
|
||||
import com.squareup.okhttp.Route;
|
||||
import com.squareup.okhttp.TunnelRequest;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
@@ -33,7 +32,6 @@ import java.security.Principal;
|
||||
import java.security.cert.Certificate;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
import javax.net.ssl.HostnameVerifier;
|
||||
import javax.net.ssl.HttpsURLConnection;
|
||||
import javax.net.ssl.SSLPeerUnverifiedException;
|
||||
@@ -47,10 +45,9 @@ public final class HttpsURLConnectionImpl extends HttpsURLConnection {
|
||||
/** HttpUrlConnectionDelegate allows reuse of HttpURLConnectionImpl. */
|
||||
private final HttpUrlConnectionDelegate delegate;
|
||||
|
||||
public HttpsURLConnectionImpl(URL url, OkHttpClient client, OkResponseCache responseCache,
|
||||
Set<Route> failedRoutes) {
|
||||
public HttpsURLConnectionImpl(URL url, OkHttpClient client) {
|
||||
super(url);
|
||||
delegate = new HttpUrlConnectionDelegate(url, client, responseCache, failedRoutes);
|
||||
delegate = new HttpUrlConnectionDelegate(url, client);
|
||||
}
|
||||
|
||||
@Override public String getCipherSuite() {
|
||||
@@ -386,25 +383,24 @@ public final class HttpsURLConnectionImpl extends HttpsURLConnection {
|
||||
}
|
||||
|
||||
@Override public void setHostnameVerifier(HostnameVerifier hostnameVerifier) {
|
||||
delegate.hostnameVerifier = hostnameVerifier;
|
||||
delegate.client.setHostnameVerifier(hostnameVerifier);
|
||||
}
|
||||
|
||||
@Override public HostnameVerifier getHostnameVerifier() {
|
||||
return delegate.hostnameVerifier;
|
||||
return delegate.client.getHostnameVerifier();
|
||||
}
|
||||
|
||||
@Override public void setSSLSocketFactory(SSLSocketFactory sslSocketFactory) {
|
||||
delegate.sslSocketFactory = sslSocketFactory;
|
||||
delegate.client.setSslSocketFactory(sslSocketFactory);
|
||||
}
|
||||
|
||||
@Override public SSLSocketFactory getSSLSocketFactory() {
|
||||
return delegate.sslSocketFactory;
|
||||
return delegate.client.getSslSocketFactory();
|
||||
}
|
||||
|
||||
private final class HttpUrlConnectionDelegate extends HttpURLConnectionImpl {
|
||||
private HttpUrlConnectionDelegate(URL url, OkHttpClient client, OkResponseCache responseCache,
|
||||
Set<Route> failedRoutes) {
|
||||
super(url, client, responseCache, failedRoutes);
|
||||
private HttpUrlConnectionDelegate(URL url, OkHttpClient client) {
|
||||
super(url, client);
|
||||
}
|
||||
|
||||
@Override protected HttpURLConnection getHttpConnectionToCache() {
|
||||
|
||||
@@ -0,0 +1,88 @@
|
||||
/*
|
||||
* Copyright (C) 2013 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.internal.http;
|
||||
|
||||
import com.squareup.okhttp.Failure;
|
||||
import com.squareup.okhttp.Request;
|
||||
import com.squareup.okhttp.Response;
|
||||
import java.io.IOException;
|
||||
import java.net.HttpURLConnection;
|
||||
|
||||
public final class Job implements Runnable {
|
||||
final HttpURLConnection connection;
|
||||
final Request request;
|
||||
final Response.Receiver responseReceiver;
|
||||
final Dispatcher dispatcher;
|
||||
|
||||
public Job(Dispatcher dispatcher, HttpURLConnection connection, Request request,
|
||||
Response.Receiver responseReceiver) {
|
||||
this.dispatcher = dispatcher;
|
||||
this.connection = connection;
|
||||
this.request = request;
|
||||
this.responseReceiver = responseReceiver;
|
||||
}
|
||||
|
||||
@Override public void run() {
|
||||
try {
|
||||
sendRequest();
|
||||
Response response = readResponse();
|
||||
responseReceiver.onResponse(response);
|
||||
} catch (IOException e) {
|
||||
responseReceiver.onFailure(new Failure.Builder()
|
||||
.request(request)
|
||||
.exception(e)
|
||||
.build());
|
||||
} finally {
|
||||
connection.disconnect();
|
||||
dispatcher.finished(this);
|
||||
}
|
||||
}
|
||||
|
||||
private HttpURLConnection sendRequest() throws IOException {
|
||||
for (int i = 0; i < request.headerCount(); i++) {
|
||||
connection.addRequestProperty(request.headerName(i), request.headerValue(i));
|
||||
}
|
||||
Request.Body body = request.body();
|
||||
if (body != null) {
|
||||
connection.setDoOutput(true);
|
||||
long contentLength = body.contentLength();
|
||||
if (contentLength == -1 || contentLength > Integer.MAX_VALUE) {
|
||||
connection.setChunkedStreamingMode(0);
|
||||
} else {
|
||||
// Don't call setFixedLengthStreamingMode(long); that's only available on Java 1.7+.
|
||||
connection.setFixedLengthStreamingMode((int) contentLength);
|
||||
}
|
||||
body.writeTo(connection.getOutputStream());
|
||||
}
|
||||
return connection;
|
||||
}
|
||||
|
||||
private Response readResponse() throws IOException {
|
||||
int responseCode = connection.getResponseCode();
|
||||
Response.Builder responseBuilder = new Response.Builder(request, responseCode);
|
||||
|
||||
for (int i = 0; true; i++) {
|
||||
String name = connection.getHeaderFieldKey(i);
|
||||
if (name == null) break;
|
||||
String value = connection.getHeaderField(i);
|
||||
responseBuilder.addHeader(name, value);
|
||||
}
|
||||
|
||||
responseBuilder.body(new Dispatcher.RealResponseBody(connection, connection.getInputStream()));
|
||||
// TODO: set redirectedBy
|
||||
return responseBuilder.build();
|
||||
}
|
||||
}
|
||||
@@ -15,6 +15,7 @@
|
||||
*/
|
||||
package com.squareup.okhttp.internal.http;
|
||||
|
||||
import com.squareup.okhttp.OkResponseCache;
|
||||
import com.squareup.okhttp.ResponseSource;
|
||||
import java.io.IOException;
|
||||
import java.net.CacheRequest;
|
||||
|
||||
@@ -19,6 +19,7 @@ import com.squareup.okhttp.Address;
|
||||
import com.squareup.okhttp.Connection;
|
||||
import com.squareup.okhttp.ConnectionPool;
|
||||
import com.squareup.okhttp.Route;
|
||||
import com.squareup.okhttp.RouteDatabase;
|
||||
import com.squareup.okhttp.internal.Dns;
|
||||
import java.io.IOException;
|
||||
import java.net.InetAddress;
|
||||
@@ -32,8 +33,6 @@ import java.util.Iterator;
|
||||
import java.util.LinkedList;
|
||||
import java.util.List;
|
||||
import java.util.NoSuchElementException;
|
||||
import java.util.Set;
|
||||
import javax.net.ssl.SSLHandshakeException;
|
||||
|
||||
import static com.squareup.okhttp.internal.Util.getEffectivePort;
|
||||
|
||||
@@ -55,7 +54,7 @@ public final class RouteSelector {
|
||||
private final ProxySelector proxySelector;
|
||||
private final ConnectionPool pool;
|
||||
private final Dns dns;
|
||||
private final Set<Route> failedRoutes;
|
||||
private final RouteDatabase routeDatabase;
|
||||
|
||||
/* The most recently attempted route. */
|
||||
private Proxy lastProxy;
|
||||
@@ -78,13 +77,13 @@ public final class RouteSelector {
|
||||
private final List<Route> postponedRoutes;
|
||||
|
||||
public RouteSelector(Address address, URI uri, ProxySelector proxySelector, ConnectionPool pool,
|
||||
Dns dns, Set<Route> failedRoutes) {
|
||||
Dns dns, RouteDatabase routeDatabase) {
|
||||
this.address = address;
|
||||
this.uri = uri;
|
||||
this.proxySelector = proxySelector;
|
||||
this.pool = pool;
|
||||
this.dns = dns;
|
||||
this.failedRoutes = failedRoutes;
|
||||
this.routeDatabase = routeDatabase;
|
||||
this.postponedRoutes = new LinkedList<Route>();
|
||||
|
||||
resetNextProxy(uri, address.getProxy());
|
||||
@@ -128,7 +127,7 @@ public final class RouteSelector {
|
||||
|
||||
boolean modernTls = nextTlsMode() == TLS_MODE_MODERN;
|
||||
Route route = new Route(address, lastProxy, lastInetSocketAddress, modernTls);
|
||||
if (failedRoutes.contains(route)) {
|
||||
if (routeDatabase.shouldPostpone(route)) {
|
||||
postponedRoutes.add(route);
|
||||
// We will only recurse in order to skip previously failed routes. They will be
|
||||
// tried last.
|
||||
@@ -149,12 +148,7 @@ public final class RouteSelector {
|
||||
proxySelector.connectFailed(uri, failedRoute.getProxy().address(), failure);
|
||||
}
|
||||
|
||||
failedRoutes.add(failedRoute);
|
||||
if (!(failure instanceof SSLHandshakeException)) {
|
||||
// If the problem was not related to SSL then it will also fail with
|
||||
// a different Tls mode therefore we can be proactive about it.
|
||||
failedRoutes.add(failedRoute.flipTlsMode());
|
||||
}
|
||||
routeDatabase.failed(failedRoute, failure);
|
||||
}
|
||||
|
||||
/** Resets {@link #nextProxy} to the first option. */
|
||||
|
||||
@@ -55,7 +55,7 @@ public final class SpdyTransport implements Transport {
|
||||
boolean hasResponseBody = true;
|
||||
stream = spdyConnection.newStream(requestHeaders.toNameValueBlock(), hasRequestBody,
|
||||
hasResponseBody);
|
||||
stream.setReadTimeout(httpEngine.policy.getReadTimeout());
|
||||
stream.setReadTimeout(httpEngine.client.getReadTimeout());
|
||||
}
|
||||
|
||||
@Override public void writeRequestBody(RetryableOutputStream requestBody) throws IOException {
|
||||
|
||||
@@ -19,7 +19,7 @@ import com.squareup.okhttp.Address;
|
||||
import com.squareup.okhttp.Connection;
|
||||
import com.squareup.okhttp.ConnectionPool;
|
||||
import com.squareup.okhttp.OkAuthenticator;
|
||||
import com.squareup.okhttp.Route;
|
||||
import com.squareup.okhttp.RouteDatabase;
|
||||
import com.squareup.okhttp.internal.Dns;
|
||||
import com.squareup.okhttp.internal.SslContextBuilder;
|
||||
import java.io.IOException;
|
||||
@@ -32,11 +32,8 @@ import java.net.URI;
|
||||
import java.net.UnknownHostException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collections;
|
||||
import java.util.LinkedHashSet;
|
||||
import java.util.List;
|
||||
import java.util.NoSuchElementException;
|
||||
import java.util.Set;
|
||||
import javax.net.ssl.HostnameVerifier;
|
||||
import javax.net.ssl.SSLContext;
|
||||
import javax.net.ssl.SSLHandshakeException;
|
||||
@@ -87,7 +84,7 @@ public final class RouteSelectorTest {
|
||||
@Test public void singleRoute() throws Exception {
|
||||
Address address = new Address(uriHost, uriPort, null, null, authenticator, null, transports);
|
||||
RouteSelector routeSelector = new RouteSelector(address, uri, proxySelector, pool, dns,
|
||||
Collections.EMPTY_SET);
|
||||
new RouteDatabase());
|
||||
|
||||
assertTrue(routeSelector.hasNext());
|
||||
dns.inetAddresses = makeFakeAddresses(255, 1);
|
||||
@@ -105,15 +102,14 @@ public final class RouteSelectorTest {
|
||||
@Test public void singleRouteReturnsFailedRoute() throws Exception {
|
||||
Address address = new Address(uriHost, uriPort, null, null, authenticator, null, transports);
|
||||
RouteSelector routeSelector = new RouteSelector(address, uri, proxySelector, pool, dns,
|
||||
Collections.EMPTY_SET);
|
||||
new RouteDatabase());
|
||||
|
||||
assertTrue(routeSelector.hasNext());
|
||||
dns.inetAddresses = makeFakeAddresses(255, 1);
|
||||
Connection connection = routeSelector.next();
|
||||
Set<Route> failedRoutes = new LinkedHashSet<Route>();
|
||||
failedRoutes.add(connection.getRoute());
|
||||
routeSelector = new RouteSelector(address, uri, proxySelector, pool, dns,
|
||||
Collections.EMPTY_SET);
|
||||
RouteDatabase routeDatabase = new RouteDatabase();
|
||||
routeDatabase.failed(connection.getRoute(), new IOException());
|
||||
routeSelector = new RouteSelector(address, uri, proxySelector, pool, dns, routeDatabase);
|
||||
assertConnection(routeSelector.next(), address, NO_PROXY, dns.inetAddresses[0], uriPort, false);
|
||||
assertFalse(routeSelector.hasNext());
|
||||
try {
|
||||
@@ -126,7 +122,7 @@ public final class RouteSelectorTest {
|
||||
@Test public void explicitProxyTriesThatProxiesAddressesOnly() throws Exception {
|
||||
Address address = new Address(uriHost, uriPort, null, null, authenticator, proxyA, transports);
|
||||
RouteSelector routeSelector = new RouteSelector(address, uri, proxySelector, pool, dns,
|
||||
Collections.EMPTY_SET);
|
||||
new RouteDatabase());
|
||||
|
||||
assertTrue(routeSelector.hasNext());
|
||||
dns.inetAddresses = makeFakeAddresses(255, 2);
|
||||
@@ -144,7 +140,7 @@ public final class RouteSelectorTest {
|
||||
Address address = new Address(uriHost, uriPort, null, null, authenticator, NO_PROXY,
|
||||
transports);
|
||||
RouteSelector routeSelector = new RouteSelector(address, uri, proxySelector, pool, dns,
|
||||
Collections.EMPTY_SET);
|
||||
new RouteDatabase());
|
||||
|
||||
assertTrue(routeSelector.hasNext());
|
||||
dns.inetAddresses = makeFakeAddresses(255, 2);
|
||||
@@ -161,7 +157,7 @@ public final class RouteSelectorTest {
|
||||
|
||||
proxySelector.proxies = null;
|
||||
RouteSelector routeSelector = new RouteSelector(address, uri, proxySelector, pool, dns,
|
||||
Collections.EMPTY_SET);
|
||||
new RouteDatabase());
|
||||
proxySelector.assertRequests(uri);
|
||||
|
||||
assertTrue(routeSelector.hasNext());
|
||||
@@ -175,7 +171,7 @@ public final class RouteSelectorTest {
|
||||
@Test public void proxySelectorReturnsNoProxies() throws Exception {
|
||||
Address address = new Address(uriHost, uriPort, null, null, authenticator, null, transports);
|
||||
RouteSelector routeSelector = new RouteSelector(address, uri, proxySelector, pool, dns,
|
||||
Collections.EMPTY_SET);
|
||||
new RouteDatabase());
|
||||
|
||||
assertTrue(routeSelector.hasNext());
|
||||
dns.inetAddresses = makeFakeAddresses(255, 2);
|
||||
@@ -193,7 +189,7 @@ public final class RouteSelectorTest {
|
||||
proxySelector.proxies.add(proxyA);
|
||||
proxySelector.proxies.add(proxyB);
|
||||
RouteSelector routeSelector = new RouteSelector(address, uri, proxySelector, pool, dns,
|
||||
Collections.EMPTY_SET);
|
||||
new RouteDatabase());
|
||||
proxySelector.assertRequests(uri);
|
||||
|
||||
// First try the IP addresses of the first proxy, in sequence.
|
||||
@@ -226,7 +222,7 @@ public final class RouteSelectorTest {
|
||||
|
||||
proxySelector.proxies.add(NO_PROXY);
|
||||
RouteSelector routeSelector = new RouteSelector(address, uri, proxySelector, pool, dns,
|
||||
Collections.EMPTY_SET);
|
||||
new RouteDatabase());
|
||||
proxySelector.assertRequests(uri);
|
||||
|
||||
// Only the origin server will be attempted.
|
||||
@@ -245,7 +241,7 @@ public final class RouteSelectorTest {
|
||||
proxySelector.proxies.add(proxyB);
|
||||
proxySelector.proxies.add(proxyA);
|
||||
RouteSelector routeSelector = new RouteSelector(address, uri, proxySelector, pool, dns,
|
||||
Collections.EMPTY_SET);
|
||||
new RouteDatabase());
|
||||
proxySelector.assertRequests(uri);
|
||||
|
||||
assertTrue(routeSelector.hasNext());
|
||||
@@ -280,27 +276,27 @@ public final class RouteSelectorTest {
|
||||
@Test public void nonSslErrorAddsAllTlsModesToFailedRoute() throws Exception {
|
||||
Address address = new Address(uriHost, uriPort, socketFactory, hostnameVerifier, authenticator,
|
||||
Proxy.NO_PROXY, transports);
|
||||
Set<Route> failedRoutes = new LinkedHashSet<Route>();
|
||||
RouteDatabase routeDatabase = new RouteDatabase();
|
||||
RouteSelector routeSelector = new RouteSelector(address, uri, proxySelector, pool, dns,
|
||||
failedRoutes);
|
||||
routeDatabase);
|
||||
|
||||
dns.inetAddresses = makeFakeAddresses(255, 1);
|
||||
Connection connection = routeSelector.next();
|
||||
routeSelector.connectFailed(connection, new IOException("Non SSL exception"));
|
||||
assertTrue(failedRoutes.size() == 2);
|
||||
assertTrue(routeDatabase.failedRoutesCount() == 2);
|
||||
}
|
||||
|
||||
@Test public void sslErrorAddsOnlyFailedTlsModeToFailedRoute() throws Exception {
|
||||
Address address = new Address(uriHost, uriPort, socketFactory, hostnameVerifier, authenticator,
|
||||
Proxy.NO_PROXY, transports);
|
||||
Set<Route> failedRoutes = new LinkedHashSet<Route>();
|
||||
RouteDatabase routeDatabase = new RouteDatabase();
|
||||
RouteSelector routeSelector = new RouteSelector(address, uri, proxySelector, pool, dns,
|
||||
failedRoutes);
|
||||
routeDatabase);
|
||||
|
||||
dns.inetAddresses = makeFakeAddresses(255, 1);
|
||||
Connection connection = routeSelector.next();
|
||||
routeSelector.connectFailed(connection, new SSLHandshakeException("SSL exception"));
|
||||
assertTrue(failedRoutes.size() == 1);
|
||||
assertTrue(routeDatabase.failedRoutesCount() == 1);
|
||||
}
|
||||
|
||||
@Test public void multipleProxiesMultipleInetAddressesMultipleTlsModes() throws Exception {
|
||||
@@ -309,7 +305,7 @@ public final class RouteSelectorTest {
|
||||
proxySelector.proxies.add(proxyA);
|
||||
proxySelector.proxies.add(proxyB);
|
||||
RouteSelector routeSelector = new RouteSelector(address, uri, proxySelector, pool, dns,
|
||||
Collections.EMPTY_SET);
|
||||
new RouteDatabase());
|
||||
|
||||
// Proxy A
|
||||
dns.inetAddresses = makeFakeAddresses(255, 2);
|
||||
@@ -346,9 +342,9 @@ public final class RouteSelectorTest {
|
||||
Address address = new Address(uriHost, uriPort, socketFactory, hostnameVerifier, authenticator,
|
||||
Proxy.NO_PROXY, transports);
|
||||
|
||||
Set<Route> failedRoutes = new LinkedHashSet<Route>(1);
|
||||
RouteDatabase routeDatabase = new RouteDatabase();
|
||||
RouteSelector routeSelector = new RouteSelector(address, uri, proxySelector, pool, dns,
|
||||
failedRoutes);
|
||||
routeDatabase);
|
||||
dns.inetAddresses = makeFakeAddresses(255, 1);
|
||||
|
||||
// Extract the regular sequence of routes from selector.
|
||||
@@ -360,9 +356,9 @@ public final class RouteSelectorTest {
|
||||
// Check that we do indeed have more than one route.
|
||||
assertTrue(regularRoutes.size() > 1);
|
||||
// Add first regular route as failed.
|
||||
failedRoutes.add(regularRoutes.get(0).getRoute());
|
||||
routeDatabase.failed(regularRoutes.get(0).getRoute(), new SSLHandshakeException("none"));
|
||||
// Reset selector
|
||||
routeSelector = new RouteSelector(address, uri, proxySelector, pool, dns, failedRoutes);
|
||||
routeSelector = new RouteSelector(address, uri, proxySelector, pool, dns, routeDatabase);
|
||||
|
||||
List<Connection> routesWithFailedRoute = new ArrayList<Connection>();
|
||||
while (routeSelector.hasNext()) {
|
||||
|
||||
Reference in New Issue
Block a user