mirror of
https://github.com/square/okhttp.git
synced 2026-01-27 04:22:07 +03:00
Merge remote-tracking branch 'origin/master'
This commit is contained in:
@@ -15,8 +15,10 @@
|
||||
*/
|
||||
package com.squareup.okhttp;
|
||||
|
||||
import com.squareup.okhttp.internal.Util;
|
||||
import java.net.Proxy;
|
||||
import java.net.UnknownHostException;
|
||||
import java.util.List;
|
||||
import javax.net.ssl.HostnameVerifier;
|
||||
import javax.net.ssl.SSLSocketFactory;
|
||||
|
||||
@@ -39,19 +41,22 @@ public final class Address {
|
||||
final SSLSocketFactory sslSocketFactory;
|
||||
final HostnameVerifier hostnameVerifier;
|
||||
final OkAuthenticator authenticator;
|
||||
final List<String> transports;
|
||||
|
||||
public Address(String uriHost, int uriPort, SSLSocketFactory sslSocketFactory,
|
||||
HostnameVerifier hostnameVerifier, OkAuthenticator authenticator, Proxy proxy)
|
||||
throws UnknownHostException {
|
||||
HostnameVerifier hostnameVerifier, OkAuthenticator authenticator, Proxy proxy,
|
||||
List<String> transports) throws UnknownHostException {
|
||||
if (uriHost == null) throw new NullPointerException("uriHost == null");
|
||||
if (uriPort <= 0) throw new IllegalArgumentException("uriPort <= 0: " + uriPort);
|
||||
if (authenticator == null) throw new IllegalArgumentException("authenticator == null");
|
||||
if (transports == null) throw new IllegalArgumentException("transports == null");
|
||||
this.proxy = proxy;
|
||||
this.uriHost = uriHost;
|
||||
this.uriPort = uriPort;
|
||||
this.sslSocketFactory = sslSocketFactory;
|
||||
this.hostnameVerifier = hostnameVerifier;
|
||||
this.authenticator = authenticator;
|
||||
this.transports = Util.immutableList(transports);
|
||||
}
|
||||
|
||||
/** Returns the hostname of the origin server. */
|
||||
@@ -91,6 +96,14 @@ public final class Address {
|
||||
return authenticator;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the client's transports. This method always returns a non-null list
|
||||
* that contains "http/1.1", possibly among other transports.
|
||||
*/
|
||||
public List<String> getTransports() {
|
||||
return transports;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns this address's explicitly-specified HTTP proxy, or null to
|
||||
* delegate to the HTTP client's proxy selector.
|
||||
@@ -107,7 +120,8 @@ public final class Address {
|
||||
&& this.uriPort == that.uriPort
|
||||
&& equal(this.sslSocketFactory, that.sslSocketFactory)
|
||||
&& equal(this.hostnameVerifier, that.hostnameVerifier)
|
||||
&& equal(this.authenticator, that.authenticator);
|
||||
&& equal(this.authenticator, that.authenticator)
|
||||
&& equal(this.transports, that.transports);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
@@ -120,6 +134,7 @@ public final class Address {
|
||||
result = 31 * result + (hostnameVerifier != null ? hostnameVerifier.hashCode() : 0);
|
||||
result = 31 * result + (authenticator != null ? authenticator.hashCode() : 0);
|
||||
result = 31 * result + (proxy != null ? proxy.hashCode() : 0);
|
||||
result = 31 * result + transports.hashCode();
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -134,7 +134,8 @@ public final class Connection implements Closeable {
|
||||
platform.supportTlsIntolerantServer(sslSocket);
|
||||
}
|
||||
|
||||
if (route.modernTls) {
|
||||
boolean useNpn = route.modernTls && route.address.transports.contains("spdy/3");
|
||||
if (useNpn) {
|
||||
platform.setNpnProtocols(sslSocket, NPN_PROTOCOLS);
|
||||
}
|
||||
|
||||
@@ -150,8 +151,7 @@ public final class Connection implements Closeable {
|
||||
in = sslSocket.getInputStream();
|
||||
|
||||
byte[] selectedProtocol;
|
||||
if (route.modernTls
|
||||
&& (selectedProtocol = platform.getNpnSelectedProtocol(sslSocket)) != null) {
|
||||
if (useNpn && (selectedProtocol = platform.getNpnSelectedProtocol(sslSocket)) != null) {
|
||||
if (Arrays.equals(selectedProtocol, SPDY3)) {
|
||||
sslSocket.setSoTimeout(0); // SPDY timeouts are set per-stream.
|
||||
spdyConnection = new SpdyConnection.Builder(route.address.getUriHost(), true, in, out)
|
||||
|
||||
@@ -15,6 +15,7 @@
|
||||
*/
|
||||
package com.squareup.okhttp;
|
||||
|
||||
import com.squareup.okhttp.internal.Util;
|
||||
import com.squareup.okhttp.internal.http.HttpAuthenticator;
|
||||
import com.squareup.okhttp.internal.http.HttpURLConnectionImpl;
|
||||
import com.squareup.okhttp.internal.http.HttpsURLConnectionImpl;
|
||||
@@ -26,8 +27,10 @@ import java.net.Proxy;
|
||||
import java.net.ProxySelector;
|
||||
import java.net.ResponseCache;
|
||||
import java.net.URL;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collections;
|
||||
import java.util.LinkedHashSet;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
import javax.net.ssl.HostnameVerifier;
|
||||
import javax.net.ssl.HttpsURLConnection;
|
||||
@@ -35,8 +38,12 @@ import javax.net.ssl.SSLSocketFactory;
|
||||
|
||||
/** Configures and creates HTTP connections. */
|
||||
public final class OkHttpClient {
|
||||
private static final List<String> DEFAULT_TRANSPORTS
|
||||
= Util.immutableList(Arrays.asList("spdy/3", "http/1.1"));
|
||||
|
||||
private Proxy proxy;
|
||||
private Set<Route> failedRoutes = Collections.synchronizedSet(new LinkedHashSet<Route>());
|
||||
private List<String> transports;
|
||||
private final Set<Route> failedRoutes;
|
||||
private ProxySelector proxySelector;
|
||||
private CookieHandler cookieHandler;
|
||||
private ResponseCache responseCache;
|
||||
@@ -46,6 +53,14 @@ public final class OkHttpClient {
|
||||
private ConnectionPool connectionPool;
|
||||
private boolean followProtocolRedirects = true;
|
||||
|
||||
public OkHttpClient() {
|
||||
this.failedRoutes = Collections.synchronizedSet(new LinkedHashSet<Route>());
|
||||
}
|
||||
|
||||
private OkHttpClient(OkHttpClient copyFrom) {
|
||||
this.failedRoutes = copyFrom.failedRoutes; // Avoid allocating an unnecessary LinkedHashSet.
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the HTTP proxy that will be used by connections created by this
|
||||
* client. This takes precedence over {@link #setProxySelector}, which is
|
||||
@@ -198,6 +213,49 @@ public final class OkHttpClient {
|
||||
return followProtocolRedirects;
|
||||
}
|
||||
|
||||
/**
|
||||
* Configure the transports used by this client to communicate with remote
|
||||
* servers. By default this client will prefer the most efficient transport
|
||||
* available, falling back to more ubiquitous transports. Applications should
|
||||
* only call this method to avoid specific compatibility problems, such as web
|
||||
* servers that behave incorrectly when SPDY is enabled.
|
||||
*
|
||||
* <p>The following transports are currently supported:
|
||||
* <ul>
|
||||
* <li><a href="http://www.w3.org/Protocols/rfc2616/rfc2616.html">http/1.1</a>
|
||||
* <li><a href="http://www.chromium.org/spdy/spdy-protocol/spdy-protocol-draft3">spdy/3</a>
|
||||
* </ul>
|
||||
*
|
||||
* <p><strong>This is an evolving set.</strong> Future releases may drop
|
||||
* support for transitional transports (like spdy/3), in favor of their
|
||||
* successors (spdy/4 or http/2.0). The http/1.1 transport will never be
|
||||
* dropped.
|
||||
*
|
||||
* <p>If multiple protocols are specified, <a
|
||||
* href="https://technotes.googlecode.com/git/nextprotoneg.html">NPN</a> will
|
||||
* be used to negotiate a transport. Future releases may use another mechanism
|
||||
* (such as <a href="http://tools.ietf.org/html/draft-friedl-tls-applayerprotoneg-02">ALPN</a>)
|
||||
* to negotiate a transport.
|
||||
*
|
||||
* @param transports the transports to use, in order of preference. The list
|
||||
* must contain "http/1.1". It must not contain null.
|
||||
*/
|
||||
public OkHttpClient setTransports(List<String> transports) {
|
||||
transports = Util.immutableList(transports);
|
||||
if (!transports.contains("http/1.1")) {
|
||||
throw new IllegalArgumentException("transports doesn't contain http/1.1: " + transports);
|
||||
}
|
||||
if (transports.contains(null)) {
|
||||
throw new IllegalArgumentException("transports must not contain null");
|
||||
}
|
||||
this.transports = transports;
|
||||
return this;
|
||||
}
|
||||
|
||||
public List<String> getTransports() {
|
||||
return transports;
|
||||
}
|
||||
|
||||
public HttpURLConnection open(URL url) {
|
||||
String protocol = url.getProtocol();
|
||||
OkHttpClient copy = copyWithDefaults();
|
||||
@@ -215,9 +273,8 @@ public final class OkHttpClient {
|
||||
* each field that hasn't been explicitly configured.
|
||||
*/
|
||||
private OkHttpClient copyWithDefaults() {
|
||||
OkHttpClient result = new OkHttpClient();
|
||||
OkHttpClient result = new OkHttpClient(this);
|
||||
result.proxy = proxy;
|
||||
result.failedRoutes = failedRoutes;
|
||||
result.proxySelector = proxySelector != null ? proxySelector : ProxySelector.getDefault();
|
||||
result.cookieHandler = cookieHandler != null ? cookieHandler : CookieHandler.getDefault();
|
||||
result.responseCache = responseCache != null ? responseCache : ResponseCache.getDefault();
|
||||
@@ -232,6 +289,7 @@ public final class OkHttpClient {
|
||||
: HttpAuthenticator.SYSTEM_DEFAULT;
|
||||
result.connectionPool = connectionPool != null ? connectionPool : ConnectionPool.getDefault();
|
||||
result.followProtocolRedirects = followProtocolRedirects;
|
||||
result.transports = transports != null ? transports : DEFAULT_TRANSPORTS;
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -29,6 +29,9 @@ import java.net.URI;
|
||||
import java.net.URL;
|
||||
import java.nio.ByteOrder;
|
||||
import java.nio.charset.Charset;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.concurrent.atomic.AtomicReference;
|
||||
|
||||
/** Junk drawer of utility methods. */
|
||||
@@ -324,4 +327,9 @@ public final class Util {
|
||||
}
|
||||
return result.toString();
|
||||
}
|
||||
|
||||
/** Returns an immutable copy of {@code list}. */
|
||||
public static <T> List<T> immutableList(List<T> list) {
|
||||
return Collections.unmodifiableList(new ArrayList<T>(list));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -278,7 +278,7 @@ public class HttpEngine {
|
||||
hostnameVerifier = policy.hostnameVerifier;
|
||||
}
|
||||
Address address = new Address(uriHost, getEffectivePort(uri), sslSocketFactory,
|
||||
hostnameVerifier, policy.authenticator, policy.requestedProxy);
|
||||
hostnameVerifier, policy.authenticator, policy.requestedProxy, policy.transports);
|
||||
routeSelector = new RouteSelector(address, uri, policy.proxySelector, policy.connectionPool,
|
||||
Dns.DEFAULT, policy.getFailedRoutes());
|
||||
}
|
||||
|
||||
@@ -93,6 +93,7 @@ public class HttpURLConnectionImpl extends HttpURLConnection {
|
||||
/* SSL configuration; necessary for HTTP requests that get redirected to HTTPS. */
|
||||
SSLSocketFactory sslSocketFactory;
|
||||
HostnameVerifier hostnameVerifier;
|
||||
List<String> transports;
|
||||
OkAuthenticator authenticator;
|
||||
final Set<Route> failedRoutes;
|
||||
|
||||
@@ -115,6 +116,7 @@ public class HttpURLConnectionImpl extends HttpURLConnection {
|
||||
this.connectionPool = client.getConnectionPool();
|
||||
this.sslSocketFactory = client.getSslSocketFactory();
|
||||
this.hostnameVerifier = client.getHostnameVerifier();
|
||||
this.transports = client.getTransports();
|
||||
this.authenticator = client.getAuthenticator();
|
||||
this.responseCache = responseCache;
|
||||
}
|
||||
|
||||
@@ -72,14 +72,14 @@ public final class ConnectionPoolTest {
|
||||
@Before public void setUp() throws Exception {
|
||||
httpServer.play();
|
||||
httpAddress = new Address(httpServer.getHostName(), httpServer.getPort(), null, null,
|
||||
HttpAuthenticator.SYSTEM_DEFAULT, null);
|
||||
HttpAuthenticator.SYSTEM_DEFAULT, null, Arrays.asList("spdy/3", "http/1.1"));
|
||||
httpSocketAddress = new InetSocketAddress(InetAddress.getByName(httpServer.getHostName()),
|
||||
httpServer.getPort());
|
||||
|
||||
spdyServer.play();
|
||||
spdyAddress =
|
||||
new Address(spdyServer.getHostName(), spdyServer.getPort(), sslContext.getSocketFactory(),
|
||||
new RecordingHostnameVerifier(), HttpAuthenticator.SYSTEM_DEFAULT, null);
|
||||
spdyAddress = new Address(spdyServer.getHostName(), spdyServer.getPort(),
|
||||
sslContext.getSocketFactory(), new RecordingHostnameVerifier(),
|
||||
HttpAuthenticator.SYSTEM_DEFAULT, null, Arrays.asList("spdy/3", "http/1.1"));
|
||||
spdySocketAddress = new InetSocketAddress(InetAddress.getByName(spdyServer.getHostName()),
|
||||
spdyServer.getPort());
|
||||
|
||||
|
||||
@@ -80,11 +80,12 @@ public final class RouteSelectorTest {
|
||||
}
|
||||
|
||||
private final OkAuthenticator authenticator = HttpAuthenticator.SYSTEM_DEFAULT;
|
||||
private final List<String> transports = Arrays.asList("http/1.1");
|
||||
private final FakeDns dns = new FakeDns();
|
||||
private final FakeProxySelector proxySelector = new FakeProxySelector();
|
||||
|
||||
@Test public void singleRoute() throws Exception {
|
||||
Address address = new Address(uriHost, uriPort, null, null, authenticator, null);
|
||||
Address address = new Address(uriHost, uriPort, null, null, authenticator, null, transports);
|
||||
RouteSelector routeSelector = new RouteSelector(address, uri, proxySelector, pool, dns,
|
||||
Collections.EMPTY_SET);
|
||||
|
||||
@@ -102,7 +103,7 @@ public final class RouteSelectorTest {
|
||||
}
|
||||
|
||||
@Test public void singleRouteReturnsFailedRoute() throws Exception {
|
||||
Address address = new Address(uriHost, uriPort, null, null, authenticator, null);
|
||||
Address address = new Address(uriHost, uriPort, null, null, authenticator, null, transports);
|
||||
RouteSelector routeSelector = new RouteSelector(address, uri, proxySelector, pool, dns,
|
||||
Collections.EMPTY_SET);
|
||||
|
||||
@@ -123,7 +124,7 @@ public final class RouteSelectorTest {
|
||||
}
|
||||
|
||||
@Test public void explicitProxyTriesThatProxiesAddressesOnly() throws Exception {
|
||||
Address address = new Address(uriHost, uriPort, null, null, authenticator, proxyA);
|
||||
Address address = new Address(uriHost, uriPort, null, null, authenticator, proxyA, transports);
|
||||
RouteSelector routeSelector = new RouteSelector(address, uri, proxySelector, pool, dns,
|
||||
Collections.EMPTY_SET);
|
||||
|
||||
@@ -140,7 +141,8 @@ public final class RouteSelectorTest {
|
||||
}
|
||||
|
||||
@Test public void explicitDirectProxy() throws Exception {
|
||||
Address address = new Address(uriHost, uriPort, null, null, authenticator, NO_PROXY);
|
||||
Address address = new Address(uriHost, uriPort, null, null, authenticator, NO_PROXY,
|
||||
transports);
|
||||
RouteSelector routeSelector = new RouteSelector(address, uri, proxySelector, pool, dns,
|
||||
Collections.EMPTY_SET);
|
||||
|
||||
@@ -155,7 +157,7 @@ public final class RouteSelectorTest {
|
||||
}
|
||||
|
||||
@Test public void proxySelectorReturnsNull() throws Exception {
|
||||
Address address = new Address(uriHost, uriPort, null, null, authenticator, null);
|
||||
Address address = new Address(uriHost, uriPort, null, null, authenticator, null, transports);
|
||||
|
||||
proxySelector.proxies = null;
|
||||
RouteSelector routeSelector = new RouteSelector(address, uri, proxySelector, pool, dns,
|
||||
@@ -171,7 +173,7 @@ public final class RouteSelectorTest {
|
||||
}
|
||||
|
||||
@Test public void proxySelectorReturnsNoProxies() throws Exception {
|
||||
Address address = new Address(uriHost, uriPort, null, null, authenticator, null);
|
||||
Address address = new Address(uriHost, uriPort, null, null, authenticator, null, transports);
|
||||
RouteSelector routeSelector = new RouteSelector(address, uri, proxySelector, pool, dns,
|
||||
Collections.EMPTY_SET);
|
||||
|
||||
@@ -186,7 +188,7 @@ public final class RouteSelectorTest {
|
||||
}
|
||||
|
||||
@Test public void proxySelectorReturnsMultipleProxies() throws Exception {
|
||||
Address address = new Address(uriHost, uriPort, null, null, authenticator, null);
|
||||
Address address = new Address(uriHost, uriPort, null, null, authenticator, null, transports);
|
||||
|
||||
proxySelector.proxies.add(proxyA);
|
||||
proxySelector.proxies.add(proxyB);
|
||||
@@ -220,7 +222,7 @@ public final class RouteSelectorTest {
|
||||
}
|
||||
|
||||
@Test public void proxySelectorDirectConnectionsAreSkipped() throws Exception {
|
||||
Address address = new Address(uriHost, uriPort, null, null, authenticator, null);
|
||||
Address address = new Address(uriHost, uriPort, null, null, authenticator, null, transports);
|
||||
|
||||
proxySelector.proxies.add(NO_PROXY);
|
||||
RouteSelector routeSelector = new RouteSelector(address, uri, proxySelector, pool, dns,
|
||||
@@ -237,7 +239,7 @@ public final class RouteSelectorTest {
|
||||
}
|
||||
|
||||
@Test public void proxyDnsFailureContinuesToNextProxy() throws Exception {
|
||||
Address address = new Address(uriHost, uriPort, null, null, authenticator, null);
|
||||
Address address = new Address(uriHost, uriPort, null, null, authenticator, null, transports);
|
||||
|
||||
proxySelector.proxies.add(proxyA);
|
||||
proxySelector.proxies.add(proxyB);
|
||||
@@ -277,7 +279,7 @@ public final class RouteSelectorTest {
|
||||
|
||||
@Test public void nonSslErrorAddsAllTlsModesToFailedRoute() throws Exception {
|
||||
Address address = new Address(uriHost, uriPort, socketFactory, hostnameVerifier, authenticator,
|
||||
Proxy.NO_PROXY);
|
||||
Proxy.NO_PROXY, transports);
|
||||
Set<Route> failedRoutes = new LinkedHashSet<Route>();
|
||||
RouteSelector routeSelector = new RouteSelector(address, uri, proxySelector, pool, dns,
|
||||
failedRoutes);
|
||||
@@ -290,7 +292,7 @@ public final class RouteSelectorTest {
|
||||
|
||||
@Test public void sslErrorAddsOnlyFailedTlsModeToFailedRoute() throws Exception {
|
||||
Address address = new Address(uriHost, uriPort, socketFactory, hostnameVerifier, authenticator,
|
||||
Proxy.NO_PROXY);
|
||||
Proxy.NO_PROXY, transports);
|
||||
Set<Route> failedRoutes = new LinkedHashSet<Route>();
|
||||
RouteSelector routeSelector = new RouteSelector(address, uri, proxySelector, pool, dns,
|
||||
failedRoutes);
|
||||
@@ -303,7 +305,7 @@ public final class RouteSelectorTest {
|
||||
|
||||
@Test public void multipleProxiesMultipleInetAddressesMultipleTlsModes() throws Exception {
|
||||
Address address = new Address(uriHost, uriPort, socketFactory, hostnameVerifier, authenticator,
|
||||
null);
|
||||
null, transports);
|
||||
proxySelector.proxies.add(proxyA);
|
||||
proxySelector.proxies.add(proxyB);
|
||||
RouteSelector routeSelector = new RouteSelector(address, uri, proxySelector, pool, dns,
|
||||
@@ -342,7 +344,7 @@ public final class RouteSelectorTest {
|
||||
|
||||
@Test public void failedRoutesAreLast() throws Exception {
|
||||
Address address = new Address(uriHost, uriPort, socketFactory, hostnameVerifier, authenticator,
|
||||
Proxy.NO_PROXY);
|
||||
Proxy.NO_PROXY, transports);
|
||||
|
||||
Set<Route> failedRoutes = new LinkedHashSet<Route>(1);
|
||||
RouteSelector routeSelector = new RouteSelector(address, uri, proxySelector, pool, dns,
|
||||
|
||||
@@ -2476,6 +2476,29 @@ public final class URLConnectionTest {
|
||||
assertTrue(call, call.contains("challenges=[Basic realm=\"protected area\"]"));
|
||||
}
|
||||
|
||||
@Test public void setTransports() throws Exception {
|
||||
server.enqueue(new MockResponse().setBody("A"));
|
||||
server.play();
|
||||
client.setTransports(Arrays.asList("http/1.1"));
|
||||
assertContent("A", client.open(server.getUrl("/")));
|
||||
}
|
||||
|
||||
@Test public void setTransportsWithoutHttp11() throws Exception {
|
||||
try {
|
||||
client.setTransports(Arrays.asList("spdy/3"));
|
||||
fail();
|
||||
} catch (IllegalArgumentException expected) {
|
||||
}
|
||||
}
|
||||
|
||||
@Test public void setTransportsWithNull() throws Exception {
|
||||
try {
|
||||
client.setTransports(Arrays.asList("http/1.1", null));
|
||||
fail();
|
||||
} catch (IllegalArgumentException expected) {
|
||||
}
|
||||
}
|
||||
|
||||
/** Returns a gzipped copy of {@code bytes}. */
|
||||
public byte[] gzip(byte[] bytes) throws IOException {
|
||||
ByteArrayOutputStream bytesOut = new ByteArrayOutputStream();
|
||||
|
||||
Reference in New Issue
Block a user