mirror of
https://github.com/square/okhttp.git
synced 2026-01-25 16:01:38 +03:00
Optionally follow redirects from HTTPS to HTTP and vice versa.
The API is imperfect because HttpURLConnection doesn't expose any SSL information, and because HttpsURLConnection won't necessarily have a secure final request.
This commit is contained in:
@@ -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.
|
||||
*
|
||||
* <p>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;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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 {
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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<Certificate> result = cacheResponse.getLocalCertificateChain();
|
||||
return result != null ? result.toArray(new Certificate[result.size()]) : null;
|
||||
}
|
||||
SSLSocket sslSocket = getSslSocket();
|
||||
if (sslSocket != null) {
|
||||
return sslSocket.getSession().getLocalCertificates();
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override public Certificate[] getServerCertificates() throws SSLPeerUnverifiedException {
|
||||
SecureCacheResponse cacheResponse = delegate.getSecureCacheResponse();
|
||||
if (cacheResponse != null) {
|
||||
List<Certificate> result = cacheResponse.getServerCertificateChain();
|
||||
return result != null ? result.toArray(new Certificate[result.size()]) : null;
|
||||
}
|
||||
SSLSocket sslSocket = getSslSocket();
|
||||
if (sslSocket != null) {
|
||||
return sslSocket.getSession().getPeerCertificates();
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override public Principal getPeerPrincipal() throws SSLPeerUnverifiedException {
|
||||
SecureCacheResponse cacheResponse = delegate.getSecureCacheResponse();
|
||||
if (cacheResponse != null) {
|
||||
return cacheResponse.getPeerPrincipal();
|
||||
}
|
||||
SSLSocket sslSocket = getSslSocket();
|
||||
if (sslSocket != null) {
|
||||
return sslSocket.getSession().getPeerPrincipal();
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override public Principal getLocalPrincipal() {
|
||||
SecureCacheResponse cacheResponse = delegate.getSecureCacheResponse();
|
||||
if (cacheResponse != null) {
|
||||
return cacheResponse.getLocalPrincipal();
|
||||
}
|
||||
SSLSocket sslSocket = getSslSocket();
|
||||
if (sslSocket != null) {
|
||||
return sslSocket.getSession().getLocalPrincipal();
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
HttpEngine getHttpEngine() {
|
||||
return delegate.getHttpEngine();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getCipherSuite() {
|
||||
SecureCacheResponse cacheResponse = delegate.getCacheResponse();
|
||||
if (cacheResponse != null) {
|
||||
return cacheResponse.getCipherSuite();
|
||||
private SSLSocket getSslSocket() {
|
||||
if (delegate.httpEngine == null || delegate.httpEngine.sentRequestMillis == -1) {
|
||||
throw new IllegalStateException("Connection has not yet been established");
|
||||
}
|
||||
checkConnected();
|
||||
return delegate.getSSLSocket().getSession().getCipherSuite();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Certificate[] getLocalCertificates() {
|
||||
SecureCacheResponse cacheResponse = delegate.getCacheResponse();
|
||||
if (cacheResponse != null) {
|
||||
List<Certificate> result = cacheResponse.getLocalCertificateChain();
|
||||
return result != null ? result.toArray(new Certificate[result.size()]) : null;
|
||||
}
|
||||
checkConnected();
|
||||
return delegate.getSSLSocket().getSession().getLocalCertificates();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Certificate[] getServerCertificates() throws SSLPeerUnverifiedException {
|
||||
SecureCacheResponse cacheResponse = delegate.getCacheResponse();
|
||||
if (cacheResponse != null) {
|
||||
List<Certificate> result = cacheResponse.getServerCertificateChain();
|
||||
return result != null ? result.toArray(new Certificate[result.size()]) : null;
|
||||
}
|
||||
checkConnected();
|
||||
return delegate.getSSLSocket().getSession().getPeerCertificates();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Principal getPeerPrincipal() throws SSLPeerUnverifiedException {
|
||||
SecureCacheResponse cacheResponse = delegate.getCacheResponse();
|
||||
if (cacheResponse != null) {
|
||||
return cacheResponse.getPeerPrincipal();
|
||||
}
|
||||
checkConnected();
|
||||
return delegate.getSSLSocket().getSession().getPeerPrincipal();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Principal getLocalPrincipal() {
|
||||
SecureCacheResponse cacheResponse = delegate.getCacheResponse();
|
||||
if (cacheResponse != null) {
|
||||
return cacheResponse.getLocalPrincipal();
|
||||
}
|
||||
checkConnected();
|
||||
return delegate.getSSLSocket().getSession().getLocalPrincipal();
|
||||
return delegate.httpEngine instanceof HttpsEngine
|
||||
? ((HttpsEngine) delegate.httpEngine).sslSocket
|
||||
: null; // Not HTTPS! Probably an https:// to http:// redirect.
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -375,49 +382,53 @@ public final class HttpsURLConnectionImpl extends HttpsURLConnection {
|
||||
delegate.setChunkedStreamingMode(chunkLength);
|
||||
}
|
||||
|
||||
@Override public void setHostnameVerifier(HostnameVerifier hostnameVerifier) {
|
||||
delegate.hostnameVerifier = hostnameVerifier;
|
||||
}
|
||||
|
||||
@Override public HostnameVerifier getHostnameVerifier() {
|
||||
return delegate.hostnameVerifier;
|
||||
}
|
||||
|
||||
@Override public void setSSLSocketFactory(SSLSocketFactory sslSocketFactory) {
|
||||
delegate.sslSocketFactory = sslSocketFactory;
|
||||
}
|
||||
|
||||
@Override public SSLSocketFactory getSSLSocketFactory() {
|
||||
return delegate.sslSocketFactory;
|
||||
}
|
||||
|
||||
private final class HttpUrlConnectionDelegate extends HttpURLConnectionImpl {
|
||||
private HttpUrlConnectionDelegate(URL url, int defaultPort, Proxy proxy,
|
||||
ProxySelector proxySelector, CookieHandler cookieHandler, ResponseCache responseCache,
|
||||
ConnectionPool connectionPool) {
|
||||
super(url, defaultPort, proxy, proxySelector, cookieHandler, responseCache, connectionPool);
|
||||
private HttpUrlConnectionDelegate(URL url, OkHttpClient client) {
|
||||
super(url, client);
|
||||
}
|
||||
|
||||
@Override protected HttpEngine newHttpEngine(String method, RawHeaders requestHeaders,
|
||||
Connection connection, RetryableOutputStream requestBody) throws IOException {
|
||||
return new HttpsEngine(this, method, requestHeaders, connection, requestBody,
|
||||
HttpsURLConnectionImpl.this);
|
||||
@Override protected HttpURLConnection getHttpConnectionToCache() {
|
||||
return HttpsURLConnectionImpl.this;
|
||||
}
|
||||
|
||||
public SecureCacheResponse getCacheResponse() {
|
||||
HttpsEngine engine = (HttpsEngine) httpEngine;
|
||||
return engine != null ? (SecureCacheResponse) engine.getCacheResponse() : null;
|
||||
}
|
||||
|
||||
public SSLSocket getSSLSocket() {
|
||||
HttpsEngine engine = (HttpsEngine) httpEngine;
|
||||
return engine != null ? engine.sslSocket : null;
|
||||
public SecureCacheResponse getSecureCacheResponse() {
|
||||
return httpEngine instanceof HttpsEngine
|
||||
? (SecureCacheResponse) httpEngine.getCacheResponse()
|
||||
: null;
|
||||
}
|
||||
}
|
||||
|
||||
private static final class HttpsEngine extends HttpEngine {
|
||||
public static final class HttpsEngine extends HttpEngine {
|
||||
/**
|
||||
* Stash of HttpsEngine.connection.socket to implement requests like
|
||||
* {@link #getCipherSuite} even after the connection has been recycled.
|
||||
*/
|
||||
private SSLSocket sslSocket;
|
||||
|
||||
private final HttpsURLConnectionImpl enclosing;
|
||||
|
||||
/**
|
||||
* @param policy the HttpURLConnectionImpl with connection configuration
|
||||
* @param enclosing the HttpsURLConnection with HTTPS features
|
||||
*/
|
||||
private HttpsEngine(HttpURLConnectionImpl policy, String method, RawHeaders requestHeaders,
|
||||
Connection connection, RetryableOutputStream requestBody, HttpsURLConnectionImpl enclosing)
|
||||
public HttpsEngine(HttpURLConnectionImpl policy, String method, RawHeaders requestHeaders,
|
||||
Connection connection, RetryableOutputStream requestBody)
|
||||
throws IOException {
|
||||
super(policy, method, requestHeaders, connection, requestBody);
|
||||
this.sslSocket = connection != null ? (SSLSocket) connection.getSocket() : null;
|
||||
this.enclosing = enclosing;
|
||||
}
|
||||
|
||||
@Override protected void connected(Connection connection) {
|
||||
@@ -433,18 +444,6 @@ public final class HttpsURLConnectionImpl extends HttpsURLConnection {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override protected SSLSocketFactory getSslSocketFactory() {
|
||||
return enclosing.getSSLSocketFactory();
|
||||
}
|
||||
|
||||
@Override protected HostnameVerifier getHostnameVerifier() {
|
||||
return enclosing.getHostnameVerifier();
|
||||
}
|
||||
|
||||
@Override protected HttpURLConnection getHttpConnectionToCache() {
|
||||
return enclosing;
|
||||
}
|
||||
|
||||
@Override protected TunnelRequest getTunnelConfig() {
|
||||
String userAgent = requestHeaders.getUserAgent();
|
||||
if (userAgent == null) {
|
||||
|
||||
@@ -61,6 +61,7 @@ import java.util.UUID;
|
||||
import java.util.concurrent.atomic.AtomicBoolean;
|
||||
import java.util.zip.GZIPInputStream;
|
||||
import java.util.zip.GZIPOutputStream;
|
||||
import javax.net.ssl.HttpsURLConnection;
|
||||
import javax.net.ssl.SSLContext;
|
||||
import javax.net.ssl.SSLException;
|
||||
import javax.net.ssl.SSLHandshakeException;
|
||||
@@ -1540,6 +1541,7 @@ public final class URLConnectionTest {
|
||||
.setBody("This page has moved!"));
|
||||
server.play();
|
||||
|
||||
client.setFollowProtocolRedirects(false);
|
||||
client.setSSLSocketFactory(sslContext.getSocketFactory());
|
||||
client.setHostnameVerifier(new RecordingHostnameVerifier());
|
||||
HttpURLConnection connection = client.open(server.getUrl("/"));
|
||||
@@ -1552,10 +1554,53 @@ public final class URLConnectionTest {
|
||||
.setBody("This page has moved!"));
|
||||
server.play();
|
||||
|
||||
client.setFollowProtocolRedirects(false);
|
||||
HttpURLConnection connection = client.open(server.getUrl("/"));
|
||||
assertEquals("This page has moved!", readAscii(connection.getInputStream(), Integer.MAX_VALUE));
|
||||
}
|
||||
|
||||
@Test public void redirectedFromHttpsToHttpFollowingProtocolRedirects() throws Exception {
|
||||
server2 = new MockWebServer();
|
||||
server2.enqueue(new MockResponse().setBody("This is insecure HTTP!"));
|
||||
server2.play();
|
||||
|
||||
server.useHttps(sslContext.getSocketFactory(), false);
|
||||
server.enqueue(new MockResponse().setResponseCode(HttpURLConnection.HTTP_MOVED_TEMP)
|
||||
.addHeader("Location: " + server2.getUrl("/"))
|
||||
.setBody("This page has moved!"));
|
||||
server.play();
|
||||
|
||||
client.setSSLSocketFactory(sslContext.getSocketFactory());
|
||||
client.setHostnameVerifier(new RecordingHostnameVerifier());
|
||||
client.setFollowProtocolRedirects(true);
|
||||
HttpsURLConnection connection = (HttpsURLConnection) client.open(server.getUrl("/"));
|
||||
assertContent("This is insecure HTTP!", connection);
|
||||
assertNull(connection.getCipherSuite());
|
||||
assertNull(connection.getLocalCertificates());
|
||||
assertNull(connection.getServerCertificates());
|
||||
assertNull(connection.getPeerPrincipal());
|
||||
assertNull(connection.getLocalPrincipal());
|
||||
}
|
||||
|
||||
@Test public void redirectedFromHttpToHttpsFollowingProtocolRedirects() throws Exception {
|
||||
server2 = new MockWebServer();
|
||||
server2.useHttps(sslContext.getSocketFactory(), false);
|
||||
server2.enqueue(new MockResponse().setBody("This is secure HTTPS!"));
|
||||
server2.play();
|
||||
|
||||
server.enqueue(new MockResponse().setResponseCode(HttpURLConnection.HTTP_MOVED_TEMP)
|
||||
.addHeader("Location: " + server2.getUrl("/"))
|
||||
.setBody("This page has moved!"));
|
||||
server.play();
|
||||
|
||||
client.setSSLSocketFactory(sslContext.getSocketFactory());
|
||||
client.setHostnameVerifier(new RecordingHostnameVerifier());
|
||||
client.setFollowProtocolRedirects(true);
|
||||
HttpURLConnection connection = client.open(server.getUrl("/"));
|
||||
assertContent("This is secure HTTPS!", connection);
|
||||
assertFalse(connection instanceof HttpsURLConnection);
|
||||
}
|
||||
|
||||
@Test public void redirectToAnotherOriginServer() throws Exception {
|
||||
redirectToAnotherOriginServer(false);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user