diff --git a/src/main/java/com/squareup/okhttp/OkHttpClient.java b/src/main/java/com/squareup/okhttp/OkHttpClient.java index 4cc5ec62b..d21cdb710 100644 --- a/src/main/java/com/squareup/okhttp/OkHttpClient.java +++ b/src/main/java/com/squareup/okhttp/OkHttpClient.java @@ -36,6 +36,7 @@ public final class OkHttpClient { private SSLSocketFactory sslSocketFactory; private HostnameVerifier hostnameVerifier; private ConnectionPool connectionPool; + private boolean followProtocolRedirects = true; /** * Sets the HTTP proxy that will be used by connections created by this @@ -48,6 +49,10 @@ public final class OkHttpClient { return this; } + public Proxy getProxy() { + return proxy; + } + /** * Sets the proxy selection policy to be used if no {@link #setProxy proxy} * is specified explicitly. The proxy selector may return multiple proxies; @@ -62,6 +67,10 @@ public final class OkHttpClient { return this; } + public ProxySelector getProxySelector() { + return proxySelector; + } + /** * Sets the cookie handler to be used to read outgoing cookies and write * incoming cookies. @@ -74,6 +83,10 @@ public final class OkHttpClient { return this; } + public CookieHandler getCookieHandler() { + return cookieHandler; + } + /** * Sets the response cache to be used to read and write cached responses. * @@ -85,6 +98,10 @@ public final class OkHttpClient { return this; } + public ResponseCache getResponseCache() { + return responseCache; + } + /** * Sets the socket factory used to secure HTTPS connections. * @@ -96,6 +113,10 @@ public final class OkHttpClient { return this; } + public SSLSocketFactory getSslSocketFactory() { + return sslSocketFactory; + } + /** * Sets the verifier used to confirm that response certificates apply to * requested hostnames for HTTPS connections. @@ -108,6 +129,10 @@ public final class OkHttpClient { return this; } + public HostnameVerifier getHostnameVerifier() { + return hostnameVerifier; + } + /** * Sets the connection pool used to recycle HTTP and HTTPS connections. * @@ -119,31 +144,55 @@ public final class OkHttpClient { return this; } - public HttpURLConnection open(URL url) { - ProxySelector proxySelector = - this.proxySelector != null ? this.proxySelector : ProxySelector.getDefault(); - CookieHandler cookieHandler = - this.cookieHandler != null ? this.cookieHandler : CookieHandler.getDefault(); - ResponseCache responseCache = - this.responseCache != null ? this.responseCache : ResponseCache.getDefault(); - ConnectionPool connectionPool = - this.connectionPool != null ? this.connectionPool : ConnectionPool.getDefault(); + public ConnectionPool getConnectionPool() { + return connectionPool; + } + /** + * Configure this client to follow redirects from HTTPS to HTTP and from HTTP + * to HTTPS. + * + *
If unset, protocol redirects will be followed. This is different than
+ * the built-in {@code HttpURLConnection}'s default.
+ */
+ public OkHttpClient setFollowProtocolRedirects(boolean followProtocolRedirects) {
+ this.followProtocolRedirects = followProtocolRedirects;
+ return this;
+ }
+
+ public boolean getFollowProtocolRedirects() {
+ return followProtocolRedirects;
+ }
+
+ public HttpURLConnection open(URL url) {
String protocol = url.getProtocol();
if (protocol.equals("http")) {
- return new HttpURLConnectionImpl(url, 80, proxy, proxySelector, cookieHandler, responseCache,
- connectionPool);
+ return new HttpURLConnectionImpl(url, copyWithDefaults());
} else if (protocol.equals("https")) {
- HttpsURLConnectionImpl result =
- new HttpsURLConnectionImpl(url, 443, proxy, proxySelector, cookieHandler, responseCache,
- connectionPool);
- result.setSSLSocketFactory(this.sslSocketFactory != null ? this.sslSocketFactory
- : HttpsURLConnection.getDefaultSSLSocketFactory());
- result.setHostnameVerifier(this.hostnameVerifier != null ? this.hostnameVerifier
- : HttpsURLConnection.getDefaultHostnameVerifier());
- return result;
+ return new HttpsURLConnectionImpl(url, copyWithDefaults());
} else {
throw new IllegalArgumentException("Unexpected protocol: " + protocol);
}
}
+
+ /**
+ * Returns a copy of this OkHttpClient that uses the system-wide default for
+ * each field that hasn't been explicitly configured.
+ */
+ private OkHttpClient copyWithDefaults() {
+ OkHttpClient result = new OkHttpClient();
+ result.proxy = proxy;
+ result.proxySelector = proxySelector != null ? proxySelector : ProxySelector.getDefault();
+ result.cookieHandler = cookieHandler != null ? cookieHandler : CookieHandler.getDefault();
+ result.responseCache = responseCache != null ? responseCache : ResponseCache.getDefault();
+ result.sslSocketFactory = sslSocketFactory != null
+ ? sslSocketFactory
+ : HttpsURLConnection.getDefaultSSLSocketFactory();
+ result.hostnameVerifier = hostnameVerifier != null
+ ? hostnameVerifier
+ : HttpsURLConnection.getDefaultHostnameVerifier();
+ result.connectionPool = connectionPool != null ? connectionPool : ConnectionPool.getDefault();
+ result.followProtocolRedirects = followProtocolRedirects;
+ return result;
+ }
}
diff --git a/src/main/java/com/squareup/okhttp/internal/http/HttpEngine.java b/src/main/java/com/squareup/okhttp/internal/http/HttpEngine.java
index 947bb690d..8816bc41a 100644
--- a/src/main/java/com/squareup/okhttp/internal/http/HttpEngine.java
+++ b/src/main/java/com/squareup/okhttp/internal/http/HttpEngine.java
@@ -32,7 +32,6 @@ import java.io.OutputStream;
import java.net.CacheRequest;
import java.net.CacheResponse;
import java.net.CookieHandler;
-import java.net.HttpURLConnection;
import java.net.Proxy;
import java.net.URI;
import java.net.URISyntaxException;
@@ -272,8 +271,14 @@ public class HttpEngine {
if (uriHost == null) {
throw new UnknownHostException(uri.toString());
}
- Address address = new Address(uriHost, getEffectivePort(uri), getSslSocketFactory(),
- getHostnameVerifier(), policy.requestedProxy);
+ SSLSocketFactory sslSocketFactory = null;
+ HostnameVerifier hostnameVerifier = null;
+ if (uri.getScheme().equalsIgnoreCase("https")) {
+ sslSocketFactory = policy.sslSocketFactory;
+ hostnameVerifier = policy.hostnameVerifier;
+ }
+ Address address = new Address(uriHost, getEffectivePort(uri), sslSocketFactory,
+ hostnameVerifier, policy.requestedProxy);
routeSelector =
new RouteSelector(address, uri, policy.proxySelector, policy.connectionPool, Dns.DEFAULT);
}
@@ -391,11 +396,7 @@ public class HttpEngine {
}
// Offer this request to the cache.
- cacheRequest = policy.responseCache.put(uri, getHttpConnectionToCache());
- }
-
- protected HttpURLConnection getHttpConnectionToCache() {
- return policy;
+ cacheRequest = policy.responseCache.put(uri, policy.getHttpConnectionToCache());
}
/**
@@ -576,22 +577,6 @@ public class HttpEngine {
: connection.getProxy().type() == Proxy.Type.HTTP; // A proxy was selected.
}
- /**
- * Returns the SSL configuration for connections created by this engine.
- * We cannot reuse HTTPS connections if the socket factory has changed.
- */
- protected SSLSocketFactory getSslSocketFactory() {
- return null;
- }
-
- /**
- * Returns the hostname verifier for connections created by this engine. We
- * cannot reuse HTTPS connections if the hostname verifier has changed.
- */
- protected HostnameVerifier getHostnameVerifier() {
- return null;
- }
-
public static String getDefaultUserAgent() {
String agent = System.getProperty("http.agent");
return agent != null ? agent : ("Java" + System.getProperty("java.version"));
@@ -651,7 +636,7 @@ public class HttpEngine {
if (policy.responseCache instanceof OkResponseCache) {
OkResponseCache httpResponseCache = (OkResponseCache) policy.responseCache;
httpResponseCache.trackConditionalCacheHit();
- httpResponseCache.update(cacheResponse, getHttpConnectionToCache());
+ httpResponseCache.update(cacheResponse, policy.getHttpConnectionToCache());
}
return;
} else {
diff --git a/src/main/java/com/squareup/okhttp/internal/http/HttpURLConnectionImpl.java b/src/main/java/com/squareup/okhttp/internal/http/HttpURLConnectionImpl.java
index 051869d28..ff0a2c421 100644
--- a/src/main/java/com/squareup/okhttp/internal/http/HttpURLConnectionImpl.java
+++ b/src/main/java/com/squareup/okhttp/internal/http/HttpURLConnectionImpl.java
@@ -19,6 +19,7 @@ package com.squareup.okhttp.internal.http;
import com.squareup.okhttp.Connection;
import com.squareup.okhttp.ConnectionPool;
+import com.squareup.okhttp.OkHttpClient;
import com.squareup.okhttp.internal.Util;
import java.io.FileNotFoundException;
import java.io.IOException;
@@ -38,7 +39,9 @@ import java.security.Permission;
import java.security.cert.CertificateException;
import java.util.List;
import java.util.Map;
+import javax.net.ssl.HostnameVerifier;
import javax.net.ssl.SSLHandshakeException;
+import javax.net.ssl.SSLSocketFactory;
import static com.squareup.okhttp.internal.Util.getEffectivePort;
@@ -63,7 +66,7 @@ public class HttpURLConnectionImpl extends HttpURLConnection {
*/
private static final int MAX_REDIRECTS = 20;
- private final int defaultPort;
+ private final boolean followProtocolRedirects;
/** The proxy requested by the client, or null for a proxy to be selected automatically. */
final Proxy requestedProxy;
@@ -72,6 +75,9 @@ public class HttpURLConnectionImpl extends HttpURLConnection {
final CookieHandler cookieHandler;
final ResponseCache responseCache;
final ConnectionPool connectionPool;
+ /* SSL configuration; necessary for HTTP requests that get redirected to HTTPS. */
+ SSLSocketFactory sslSocketFactory;
+ HostnameVerifier hostnameVerifier;
private final RawHeaders rawRequestHeaders = new RawHeaders();
@@ -80,15 +86,16 @@ public class HttpURLConnectionImpl extends HttpURLConnection {
protected IOException httpEngineFailure;
protected HttpEngine httpEngine;
- public HttpURLConnectionImpl(URL url, int defaultPort, Proxy proxy, ProxySelector proxySelector,
- CookieHandler cookieHandler, ResponseCache responseCache, ConnectionPool connectionPool) {
+ public HttpURLConnectionImpl(URL url, OkHttpClient client) {
super(url);
- this.defaultPort = defaultPort;
- this.requestedProxy = proxy;
- this.proxySelector = proxySelector;
- this.cookieHandler = cookieHandler;
- this.responseCache = responseCache;
- this.connectionPool = connectionPool;
+ this.followProtocolRedirects = client.getFollowProtocolRedirects();
+ this.requestedProxy = client.getProxy();
+ this.proxySelector = client.getProxySelector();
+ this.cookieHandler = client.getCookieHandler();
+ this.responseCache = client.getResponseCache();
+ this.connectionPool = client.getConnectionPool();
+ this.sslSocketFactory = client.getSslSocketFactory();
+ this.hostnameVerifier = client.getHostnameVerifier();
}
@Override public final void connect() throws IOException {
@@ -258,13 +265,20 @@ public class HttpURLConnectionImpl extends HttpURLConnection {
}
}
- /**
- * Create a new HTTP engine. This hook method is non-final so it can be
- * overridden by HttpsURLConnectionImpl.
- */
- protected HttpEngine newHttpEngine(String method, RawHeaders requestHeaders,
+ protected HttpURLConnection getHttpConnectionToCache() {
+ return this;
+ }
+
+ private HttpEngine newHttpEngine(String method, RawHeaders requestHeaders,
Connection connection, RetryableOutputStream requestBody) throws IOException {
- return new HttpEngine(this, method, requestHeaders, connection, requestBody);
+ if (url.getProtocol().equals("http")) {
+ return new HttpEngine(this, method, requestHeaders, connection, requestBody);
+ } else if (url.getProtocol().equals("https")) {
+ return new HttpsURLConnectionImpl.HttpsEngine(
+ this, method, requestHeaders, connection, requestBody);
+ } else {
+ throw new AssertionError();
+ }
}
/**
@@ -413,11 +427,16 @@ public class HttpURLConnectionImpl extends HttpURLConnection {
}
URL previousUrl = url;
url = new URL(previousUrl, location);
- if (!previousUrl.getProtocol().equals(url.getProtocol())) {
- return Retry.NONE; // the scheme changed; don't retry.
+ if (!url.getProtocol().equals("https") && !url.getProtocol().equals("http")) {
+ return Retry.NONE; // Don't follow redirects to unsupported protocols.
}
- if (previousUrl.getHost().equals(url.getHost())
- && getEffectivePort(previousUrl) == getEffectivePort(url)) {
+ boolean sameProtocol = previousUrl.getProtocol().equals(url.getProtocol());
+ if (!sameProtocol && !followProtocolRedirects) {
+ return Retry.NONE; // This client doesn't follow redirects across protocols.
+ }
+ boolean sameHost = previousUrl.getHost().equals(url.getHost());
+ boolean samePort = getEffectivePort(previousUrl) == getEffectivePort(url);
+ if (sameHost && samePort && sameProtocol) {
return Retry.SAME_CONNECTION;
} else {
return Retry.DIFFERENT_CONNECTION;
@@ -428,10 +447,6 @@ public class HttpURLConnectionImpl extends HttpURLConnection {
}
}
- final int getDefaultPort() {
- return defaultPort;
- }
-
/** @see java.net.HttpURLConnection#setFixedLengthStreamingMode(int) */
final int getFixedContentLength() {
return fixedContentLength;
diff --git a/src/main/java/com/squareup/okhttp/internal/http/HttpsURLConnectionImpl.java b/src/main/java/com/squareup/okhttp/internal/http/HttpsURLConnectionImpl.java
index 821290311..c224270b0 100644
--- a/src/main/java/com/squareup/okhttp/internal/http/HttpsURLConnectionImpl.java
+++ b/src/main/java/com/squareup/okhttp/internal/http/HttpsURLConnectionImpl.java
@@ -17,18 +17,14 @@
package com.squareup.okhttp.internal.http;
import com.squareup.okhttp.Connection;
-import com.squareup.okhttp.ConnectionPool;
+import com.squareup.okhttp.OkHttpClient;
import com.squareup.okhttp.TunnelRequest;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.CacheResponse;
-import java.net.CookieHandler;
import java.net.HttpURLConnection;
import java.net.ProtocolException;
-import java.net.Proxy;
-import java.net.ProxySelector;
-import java.net.ResponseCache;
import java.net.SecureCacheResponse;
import java.net.URL;
import java.security.Permission;
@@ -49,73 +45,84 @@ public final class HttpsURLConnectionImpl extends HttpsURLConnection {
/** HttpUrlConnectionDelegate allows reuse of HttpURLConnectionImpl. */
private final HttpUrlConnectionDelegate delegate;
- public HttpsURLConnectionImpl(URL url, int defaultPort, Proxy proxy, ProxySelector proxySelector,
- CookieHandler cookieHandler, ResponseCache responseCache, ConnectionPool connectionPool) {
+ public HttpsURLConnectionImpl(URL url, OkHttpClient client) {
super(url);
- delegate = new HttpUrlConnectionDelegate(url, defaultPort, proxy, proxySelector, cookieHandler,
- responseCache, connectionPool);
+ delegate = new HttpUrlConnectionDelegate(url, client);
}
- private void checkConnected() {
- if (delegate.getSSLSocket() == null) {
- throw new IllegalStateException("Connection has not yet been established");
+ @Override public String getCipherSuite() {
+ SecureCacheResponse cacheResponse = delegate.getSecureCacheResponse();
+ if (cacheResponse != null) {
+ return cacheResponse.getCipherSuite();
}
+ SSLSocket sslSocket = getSslSocket();
+ if (sslSocket != null) {
+ return sslSocket.getSession().getCipherSuite();
+ }
+ return null;
+ }
+
+ @Override public Certificate[] getLocalCertificates() {
+ SecureCacheResponse cacheResponse = delegate.getSecureCacheResponse();
+ if (cacheResponse != null) {
+ List