| /* |
| * Copyright (C) 2012 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 com.squareup.okhttp.internal.Internal; |
| import com.squareup.okhttp.internal.InternalCache; |
| import com.squareup.okhttp.internal.RouteDatabase; |
| import com.squareup.okhttp.internal.Util; |
| import com.squareup.okhttp.internal.http.AuthenticatorAdapter; |
| import com.squareup.okhttp.internal.http.StreamAllocation; |
| import com.squareup.okhttp.internal.io.RealConnection; |
| import com.squareup.okhttp.internal.tls.OkHostnameVerifier; |
| import java.net.CookieHandler; |
| import java.net.MalformedURLException; |
| import java.net.Proxy; |
| import java.net.ProxySelector; |
| import java.net.URLConnection; |
| import java.net.UnknownHostException; |
| import java.security.GeneralSecurityException; |
| import java.util.ArrayList; |
| import java.util.List; |
| import java.util.concurrent.TimeUnit; |
| import javax.net.SocketFactory; |
| import javax.net.ssl.HostnameVerifier; |
| import javax.net.ssl.SSLContext; |
| import javax.net.ssl.SSLSocket; |
| import javax.net.ssl.SSLSocketFactory; |
| |
| /** |
| * Configures and creates HTTP connections. Most applications can use a single |
| * OkHttpClient for all of their HTTP requests - benefiting from a shared |
| * response cache, thread pool, connection re-use, etc. |
| * |
| * <p>Instances of OkHttpClient are intended to be fully configured before they're |
| * shared - once shared they should be treated as immutable and can safely be used |
| * to concurrently open new connections. If required, threads can call |
| * {@link #clone()} to make a shallow copy of the OkHttpClient that can be |
| * safely modified with further configuration changes. |
| */ |
| public class OkHttpClient implements Cloneable { |
| private static final List<Protocol> DEFAULT_PROTOCOLS = Util.immutableList( |
| Protocol.HTTP_2, Protocol.SPDY_3, Protocol.HTTP_1_1); |
| |
| private static final List<ConnectionSpec> DEFAULT_CONNECTION_SPECS = Util.immutableList( |
| ConnectionSpec.MODERN_TLS, ConnectionSpec.COMPATIBLE_TLS, ConnectionSpec.CLEARTEXT); |
| |
| static { |
| Internal.instance = new Internal() { |
| @Override public void addLenient(Headers.Builder builder, String line) { |
| builder.addLenient(line); |
| } |
| |
| @Override public void addLenient(Headers.Builder builder, String name, String value) { |
| builder.addLenient(name, value); |
| } |
| |
| @Override public void setCache(OkHttpClient client, InternalCache internalCache) { |
| client.setInternalCache(internalCache); |
| } |
| |
| @Override public InternalCache internalCache(OkHttpClient client) { |
| return client.internalCache(); |
| } |
| |
| @Override public boolean connectionBecameIdle( |
| ConnectionPool pool, RealConnection connection) { |
| return pool.connectionBecameIdle(connection); |
| } |
| |
| @Override public RealConnection get( |
| ConnectionPool pool, Address address, StreamAllocation streamAllocation) { |
| return pool.get(address, streamAllocation); |
| } |
| |
| @Override public void put(ConnectionPool pool, RealConnection connection) { |
| pool.put(connection); |
| } |
| |
| @Override public RouteDatabase routeDatabase(ConnectionPool connectionPool) { |
| return connectionPool.routeDatabase; |
| } |
| |
| @Override |
| public void callEnqueue(Call call, Callback responseCallback, boolean forWebSocket) { |
| call.enqueue(responseCallback, forWebSocket); |
| } |
| |
| @Override public StreamAllocation callEngineGetStreamAllocation(Call call) { |
| return call.engine.streamAllocation; |
| } |
| |
| @Override |
| public void apply(ConnectionSpec tlsConfiguration, SSLSocket sslSocket, boolean isFallback) { |
| tlsConfiguration.apply(sslSocket, isFallback); |
| } |
| |
| @Override public HttpUrl getHttpUrlChecked(String url) |
| throws MalformedURLException, UnknownHostException { |
| return HttpUrl.getChecked(url); |
| } |
| }; |
| } |
| |
| /** Lazily-initialized. */ |
| private static SSLSocketFactory defaultSslSocketFactory; |
| |
| private final RouteDatabase routeDatabase; |
| private Dispatcher dispatcher; |
| private Proxy proxy; |
| private List<Protocol> protocols; |
| private List<ConnectionSpec> connectionSpecs; |
| private final List<Interceptor> interceptors = new ArrayList<>(); |
| private final List<Interceptor> networkInterceptors = new ArrayList<>(); |
| private ProxySelector proxySelector; |
| private CookieHandler cookieHandler; |
| |
| /** Non-null if this client is caching; possibly by {@code cache}. */ |
| private InternalCache internalCache; |
| private Cache cache; |
| |
| private SocketFactory socketFactory; |
| private SSLSocketFactory sslSocketFactory; |
| private HostnameVerifier hostnameVerifier; |
| private CertificatePinner certificatePinner; |
| private Authenticator authenticator; |
| private ConnectionPool connectionPool; |
| private Dns dns; |
| private boolean followSslRedirects = true; |
| private boolean followRedirects = true; |
| private boolean retryOnConnectionFailure = true; |
| private int connectTimeout = 10_000; |
| private int readTimeout = 10_000; |
| private int writeTimeout = 10_000; |
| |
| public OkHttpClient() { |
| routeDatabase = new RouteDatabase(); |
| dispatcher = new Dispatcher(); |
| } |
| |
| private OkHttpClient(OkHttpClient okHttpClient) { |
| this.routeDatabase = okHttpClient.routeDatabase; |
| this.dispatcher = okHttpClient.dispatcher; |
| this.proxy = okHttpClient.proxy; |
| this.protocols = okHttpClient.protocols; |
| this.connectionSpecs = okHttpClient.connectionSpecs; |
| this.interceptors.addAll(okHttpClient.interceptors); |
| this.networkInterceptors.addAll(okHttpClient.networkInterceptors); |
| this.proxySelector = okHttpClient.proxySelector; |
| this.cookieHandler = okHttpClient.cookieHandler; |
| this.cache = okHttpClient.cache; |
| this.internalCache = cache != null ? cache.internalCache : okHttpClient.internalCache; |
| this.socketFactory = okHttpClient.socketFactory; |
| this.sslSocketFactory = okHttpClient.sslSocketFactory; |
| this.hostnameVerifier = okHttpClient.hostnameVerifier; |
| this.certificatePinner = okHttpClient.certificatePinner; |
| this.authenticator = okHttpClient.authenticator; |
| this.connectionPool = okHttpClient.connectionPool; |
| this.dns = okHttpClient.dns; |
| this.followSslRedirects = okHttpClient.followSslRedirects; |
| this.followRedirects = okHttpClient.followRedirects; |
| this.retryOnConnectionFailure = okHttpClient.retryOnConnectionFailure; |
| this.connectTimeout = okHttpClient.connectTimeout; |
| this.readTimeout = okHttpClient.readTimeout; |
| this.writeTimeout = okHttpClient.writeTimeout; |
| } |
| |
| /** |
| * Sets the default connect timeout for new connections. A value of 0 means no timeout, otherwise |
| * values must be between 1 and {@link Integer#MAX_VALUE} when converted to milliseconds. |
| * |
| * @see URLConnection#setConnectTimeout(int) |
| */ |
| public void setConnectTimeout(long timeout, TimeUnit unit) { |
| if (timeout < 0) throw new IllegalArgumentException("timeout < 0"); |
| if (unit == null) throw new IllegalArgumentException("unit == null"); |
| long millis = unit.toMillis(timeout); |
| if (millis > Integer.MAX_VALUE) throw new IllegalArgumentException("Timeout too large."); |
| if (millis == 0 && timeout > 0) throw new IllegalArgumentException("Timeout too small."); |
| connectTimeout = (int) millis; |
| } |
| |
| /** Default connect timeout (in milliseconds). */ |
| public int getConnectTimeout() { |
| return connectTimeout; |
| } |
| |
| /** |
| * Sets the default read timeout for new connections. A value of 0 means no timeout, otherwise |
| * values must be between 1 and {@link Integer#MAX_VALUE} when converted to milliseconds. |
| * |
| * @see URLConnection#setReadTimeout(int) |
| */ |
| public void setReadTimeout(long timeout, TimeUnit unit) { |
| if (timeout < 0) throw new IllegalArgumentException("timeout < 0"); |
| if (unit == null) throw new IllegalArgumentException("unit == null"); |
| long millis = unit.toMillis(timeout); |
| if (millis > Integer.MAX_VALUE) throw new IllegalArgumentException("Timeout too large."); |
| if (millis == 0 && timeout > 0) throw new IllegalArgumentException("Timeout too small."); |
| readTimeout = (int) millis; |
| } |
| |
| /** Default read timeout (in milliseconds). */ |
| public int getReadTimeout() { |
| return readTimeout; |
| } |
| |
| /** |
| * Sets the default write timeout for new connections. A value of 0 means no timeout, otherwise |
| * values must be between 1 and {@link Integer#MAX_VALUE} when converted to milliseconds. |
| */ |
| public void setWriteTimeout(long timeout, TimeUnit unit) { |
| if (timeout < 0) throw new IllegalArgumentException("timeout < 0"); |
| if (unit == null) throw new IllegalArgumentException("unit == null"); |
| long millis = unit.toMillis(timeout); |
| if (millis > Integer.MAX_VALUE) throw new IllegalArgumentException("Timeout too large."); |
| if (millis == 0 && timeout > 0) throw new IllegalArgumentException("Timeout too small."); |
| writeTimeout = (int) millis; |
| } |
| |
| /** Default write timeout (in milliseconds). */ |
| public int getWriteTimeout() { |
| return writeTimeout; |
| } |
| |
| /** |
| * Sets the HTTP proxy that will be used by connections created by this |
| * client. This takes precedence over {@link #setProxySelector}, which is |
| * only honored when this proxy is null (which it is by default). To disable |
| * proxy use completely, call {@code setProxy(Proxy.NO_PROXY)}. |
| */ |
| public OkHttpClient setProxy(Proxy proxy) { |
| this.proxy = proxy; |
| 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; |
| * in that case they will be tried in sequence until a successful connection |
| * is established. |
| * |
| * <p>If unset, the {@link ProxySelector#getDefault() system-wide default} |
| * proxy selector will be used. |
| */ |
| public OkHttpClient setProxySelector(ProxySelector proxySelector) { |
| this.proxySelector = proxySelector; |
| return this; |
| } |
| |
| public ProxySelector getProxySelector() { |
| return proxySelector; |
| } |
| |
| /** |
| * Sets the cookie handler to be used to read outgoing cookies and write |
| * incoming cookies. |
| * |
| * <p>If unset, the {@link CookieHandler#getDefault() system-wide default} |
| * cookie handler will be used. |
| */ |
| public OkHttpClient setCookieHandler(CookieHandler cookieHandler) { |
| this.cookieHandler = cookieHandler; |
| return this; |
| } |
| |
| public CookieHandler getCookieHandler() { |
| return cookieHandler; |
| } |
| |
| /** Sets the response cache to be used to read and write cached responses. */ |
| void setInternalCache(InternalCache internalCache) { |
| this.internalCache = internalCache; |
| this.cache = null; |
| } |
| |
| InternalCache internalCache() { |
| return internalCache; |
| } |
| |
| public OkHttpClient setCache(Cache cache) { |
| this.cache = cache; |
| this.internalCache = null; |
| return this; |
| } |
| |
| public Cache getCache() { |
| return cache; |
| } |
| |
| /** |
| * Sets the DNS service used to lookup IP addresses for hostnames. |
| * |
| * <p>If unset, the {@link Dns#SYSTEM system-wide default} DNS will be used. |
| */ |
| public OkHttpClient setDns(Dns dns) { |
| this.dns = dns; |
| return this; |
| } |
| |
| public Dns getDns() { |
| return dns; |
| } |
| |
| /** |
| * Sets the socket factory used to create connections. OkHttp only uses |
| * the parameterless {@link SocketFactory#createSocket() createSocket()} |
| * method to create unconnected sockets. Overriding this method, |
| * e. g., allows the socket to be bound to a specific local address. |
| * |
| * <p>If unset, the {@link SocketFactory#getDefault() system-wide default} |
| * socket factory will be used. |
| */ |
| public OkHttpClient setSocketFactory(SocketFactory socketFactory) { |
| this.socketFactory = socketFactory; |
| return this; |
| } |
| |
| public SocketFactory getSocketFactory() { |
| return socketFactory; |
| } |
| |
| /** |
| * Sets the socket factory used to secure HTTPS connections. |
| * |
| * <p>If unset, a lazily created SSL socket factory will be used. |
| */ |
| public OkHttpClient setSslSocketFactory(SSLSocketFactory sslSocketFactory) { |
| this.sslSocketFactory = sslSocketFactory; |
| return this; |
| } |
| |
| public SSLSocketFactory getSslSocketFactory() { |
| return sslSocketFactory; |
| } |
| |
| /** |
| * Sets the verifier used to confirm that response certificates apply to |
| * requested hostnames for HTTPS connections. |
| * |
| * <p>If unset, a default hostname verifier will be used. |
| */ |
| public OkHttpClient setHostnameVerifier(HostnameVerifier hostnameVerifier) { |
| this.hostnameVerifier = hostnameVerifier; |
| return this; |
| } |
| |
| public HostnameVerifier getHostnameVerifier() { |
| return hostnameVerifier; |
| } |
| |
| /** |
| * Sets the certificate pinner that constrains which certificates are trusted. |
| * By default HTTPS connections rely on only the {@link #setSslSocketFactory |
| * SSL socket factory} to establish trust. Pinning certificates avoids the |
| * need to trust certificate authorities. |
| */ |
| public OkHttpClient setCertificatePinner(CertificatePinner certificatePinner) { |
| this.certificatePinner = certificatePinner; |
| return this; |
| } |
| |
| public CertificatePinner getCertificatePinner() { |
| return certificatePinner; |
| } |
| |
| /** |
| * Sets the authenticator used to respond to challenges from the remote web |
| * server or proxy server. |
| * |
| * <p>If unset, the {@link java.net.Authenticator#setDefault system-wide default} |
| * authenticator will be used. |
| */ |
| public OkHttpClient setAuthenticator(Authenticator authenticator) { |
| this.authenticator = authenticator; |
| return this; |
| } |
| |
| public Authenticator getAuthenticator() { |
| return authenticator; |
| } |
| |
| /** |
| * Sets the connection pool used to recycle HTTP and HTTPS connections. |
| * |
| * <p>If unset, the {@link ConnectionPool#getDefault() system-wide |
| * default} connection pool will be used. |
| */ |
| public OkHttpClient setConnectionPool(ConnectionPool connectionPool) { |
| this.connectionPool = connectionPool; |
| return this; |
| } |
| |
| 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 setFollowSslRedirects(boolean followProtocolRedirects) { |
| this.followSslRedirects = followProtocolRedirects; |
| return this; |
| } |
| |
| public boolean getFollowSslRedirects() { |
| return followSslRedirects; |
| } |
| |
| /** Configure this client to follow redirects. If unset, redirects be followed. */ |
| public void setFollowRedirects(boolean followRedirects) { |
| this.followRedirects = followRedirects; |
| } |
| |
| public boolean getFollowRedirects() { |
| return followRedirects; |
| } |
| |
| /** |
| * Configure this client to retry or not when a connectivity problem is encountered. By default, |
| * this client silently recovers from the following problems: |
| * |
| * <ul> |
| * <li><strong>Unreachable IP addresses.</strong> If the URL's host has multiple IP addresses, |
| * failure to reach any individual IP address doesn't fail the overall request. This can |
| * increase availability of multi-homed services. |
| * <li><strong>Stale pooled connections.</strong> The {@link ConnectionPool} reuses sockets |
| * to decrease request latency, but these connections will occasionally time out. |
| * <li><strong>Unreachable proxy servers.</strong> A {@link ProxySelector} can be used to |
| * attempt multiple proxy servers in sequence, eventually falling back to a direct |
| * connection. |
| * </ul> |
| * |
| * Set this to false to avoid retrying requests when doing so is destructive. In this case the |
| * calling application should do its own recovery of connectivity failures. |
| */ |
| public void setRetryOnConnectionFailure(boolean retryOnConnectionFailure) { |
| this.retryOnConnectionFailure = retryOnConnectionFailure; |
| } |
| |
| public boolean getRetryOnConnectionFailure() { |
| return retryOnConnectionFailure; |
| } |
| |
| RouteDatabase routeDatabase() { |
| return routeDatabase; |
| } |
| |
| /** |
| * Sets the dispatcher used to set policy and execute asynchronous requests. |
| * Must not be null. |
| */ |
| public OkHttpClient setDispatcher(Dispatcher dispatcher) { |
| if (dispatcher == null) throw new IllegalArgumentException("dispatcher == null"); |
| this.dispatcher = dispatcher; |
| return this; |
| } |
| |
| public Dispatcher getDispatcher() { |
| return dispatcher; |
| } |
| |
| /** |
| * Configure the protocols 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 protocols. 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 protocols 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-1">spdy/3.1</a> |
| * <li><a href="http://tools.ietf.org/html/draft-ietf-httpbis-http2-17">h2</a> |
| * </ul> |
| * |
| * <p><strong>This is an evolving set.</strong> Future releases include |
| * support for transitional protocols. The http/1.1 transport will never be |
| * dropped. |
| * |
| * <p>If multiple protocols are specified, <a |
| * href="http://tools.ietf.org/html/draft-ietf-tls-applayerprotoneg">ALPN</a> |
| * will be used to negotiate a transport. |
| * |
| * <p>{@link Protocol#HTTP_1_0} is not supported in this set. Requests are |
| * initiated with {@code HTTP/1.1} only. If the server responds with {@code |
| * HTTP/1.0}, that will be exposed by {@link Response#protocol()}. |
| * |
| * @param protocols the protocols to use, in order of preference. The list |
| * must contain {@link Protocol#HTTP_1_1}. It must not contain null or |
| * {@link Protocol#HTTP_1_0}. |
| */ |
| public OkHttpClient setProtocols(List<Protocol> protocols) { |
| protocols = Util.immutableList(protocols); |
| if (!protocols.contains(Protocol.HTTP_1_1)) { |
| throw new IllegalArgumentException("protocols doesn't contain http/1.1: " + protocols); |
| } |
| if (protocols.contains(Protocol.HTTP_1_0)) { |
| throw new IllegalArgumentException("protocols must not contain http/1.0: " + protocols); |
| } |
| if (protocols.contains(null)) { |
| throw new IllegalArgumentException("protocols must not contain null"); |
| } |
| this.protocols = Util.immutableList(protocols); |
| return this; |
| } |
| |
| public List<Protocol> getProtocols() { |
| return protocols; |
| } |
| |
| public OkHttpClient setConnectionSpecs(List<ConnectionSpec> connectionSpecs) { |
| this.connectionSpecs = Util.immutableList(connectionSpecs); |
| return this; |
| } |
| |
| public List<ConnectionSpec> getConnectionSpecs() { |
| return connectionSpecs; |
| } |
| |
| /** |
| * Returns a modifiable list of interceptors that observe the full span of each call: from before |
| * the connection is established (if any) until after the response source is selected (either the |
| * origin server, cache, or both). |
| */ |
| public List<Interceptor> interceptors() { |
| return interceptors; |
| } |
| |
| /** |
| * Returns a modifiable list of interceptors that observe a single network request and response. |
| * These interceptors must call {@link Interceptor.Chain#proceed} exactly once: it is an error for |
| * a network interceptor to short-circuit or repeat a network request. |
| */ |
| public List<Interceptor> networkInterceptors() { |
| return networkInterceptors; |
| } |
| |
| /** |
| * Prepares the {@code request} to be executed at some point in the future. |
| */ |
| public Call newCall(Request request) { |
| return new Call(this, request); |
| } |
| |
| /** |
| * Cancels all scheduled or in-flight calls tagged with {@code tag}. Requests |
| * that are already complete cannot be canceled. |
| */ |
| public OkHttpClient cancel(Object tag) { |
| getDispatcher().cancel(tag); |
| return this; |
| } |
| |
| /** |
| * Returns a shallow copy of this OkHttpClient that uses the system-wide |
| * default for each field that hasn't been explicitly configured. |
| */ |
| OkHttpClient copyWithDefaults() { |
| OkHttpClient result = new OkHttpClient(this); |
| if (result.proxySelector == null) { |
| result.proxySelector = ProxySelector.getDefault(); |
| } |
| if (result.cookieHandler == null) { |
| result.cookieHandler = CookieHandler.getDefault(); |
| } |
| if (result.socketFactory == null) { |
| result.socketFactory = SocketFactory.getDefault(); |
| } |
| if (result.sslSocketFactory == null) { |
| result.sslSocketFactory = getDefaultSSLSocketFactory(); |
| } |
| if (result.hostnameVerifier == null) { |
| result.hostnameVerifier = OkHostnameVerifier.INSTANCE; |
| } |
| if (result.certificatePinner == null) { |
| result.certificatePinner = CertificatePinner.DEFAULT; |
| } |
| if (result.authenticator == null) { |
| result.authenticator = AuthenticatorAdapter.INSTANCE; |
| } |
| if (result.connectionPool == null) { |
| result.connectionPool = ConnectionPool.getDefault(); |
| } |
| if (result.protocols == null) { |
| result.protocols = DEFAULT_PROTOCOLS; |
| } |
| if (result.connectionSpecs == null) { |
| result.connectionSpecs = DEFAULT_CONNECTION_SPECS; |
| } |
| if (result.dns == null) { |
| result.dns = Dns.SYSTEM; |
| } |
| return result; |
| } |
| |
| /** |
| * Java and Android programs default to using a single global SSL context, |
| * accessible to HTTP clients as {@link SSLSocketFactory#getDefault()}. If we |
| * used the shared SSL context, when OkHttp enables ALPN for its SPDY-related |
| * stuff, it would also enable ALPN for other usages, which might crash them |
| * because ALPN is enabled when it isn't expected to be. |
| * |
| * <p>This code avoids that by defaulting to an OkHttp-created SSL context. |
| * The drawback of this approach is that apps that customize the global SSL |
| * context will lose these customizations. |
| */ |
| private synchronized SSLSocketFactory getDefaultSSLSocketFactory() { |
| if (defaultSslSocketFactory == null) { |
| try { |
| SSLContext sslContext = SSLContext.getInstance("TLS"); |
| sslContext.init(null, null, null); |
| defaultSslSocketFactory = sslContext.getSocketFactory(); |
| } catch (GeneralSecurityException e) { |
| throw new AssertionError(); // The system has no TLS. Just give up. |
| } |
| } |
| return defaultSslSocketFactory; |
| } |
| |
| /** Returns a shallow copy of this OkHttpClient. */ |
| @Override public OkHttpClient clone() { |
| return new OkHttpClient(this); |
| } |
| } |