| /* |
| * 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.Util; |
| 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.OkResponseCacheAdapter; |
| import com.squareup.okhttp.internal.tls.OkHostnameVerifier; |
| import java.net.CookieHandler; |
| import java.net.HttpURLConnection; |
| import java.net.Proxy; |
| import java.net.ProxySelector; |
| import java.net.ResponseCache; |
| import java.net.URL; |
| import java.net.URLConnection; |
| import java.net.URLStreamHandler; |
| import java.net.URLStreamHandlerFactory; |
| import java.util.Arrays; |
| import java.util.List; |
| import java.util.concurrent.TimeUnit; |
| import javax.net.ssl.HostnameVerifier; |
| import javax.net.ssl.HttpsURLConnection; |
| import javax.net.ssl.SSLSocketFactory; |
| |
| /** Configures and creates HTTP connections. */ |
| 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 ProxySelector proxySelector; |
| private CookieHandler cookieHandler; |
| private ResponseCache responseCache; |
| private SSLSocketFactory sslSocketFactory; |
| private HostnameVerifier hostnameVerifier; |
| private OkAuthenticator authenticator; |
| private ConnectionPool connectionPool; |
| private boolean followProtocolRedirects = true; |
| private int connectTimeout; |
| private int readTimeout; |
| |
| public OkHttpClient() { |
| routeDatabase = new RouteDatabase(); |
| dispatcher = new Dispatcher(); |
| } |
| |
| private OkHttpClient(OkHttpClient copyFrom) { |
| routeDatabase = copyFrom.routeDatabase; |
| dispatcher = copyFrom.dispatcher; |
| } |
| |
| /** |
| * Sets the default connect timeout for new connections. A value of 0 means no timeout. |
| * |
| * @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."); |
| } |
| 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. |
| * |
| * @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."); |
| } |
| readTimeout = (int) millis; |
| } |
| |
| /** Default read timeout (in milliseconds). */ |
| public int getReadTimeout() { |
| return readTimeout; |
| } |
| |
| /** |
| * 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. |
| * |
| * <p>If unset, the {@link ResponseCache#getDefault() system-wide default} |
| * response cache will be used. |
| */ |
| public OkHttpClient setResponseCache(ResponseCache responseCache) { |
| this.responseCache = responseCache; |
| return this; |
| } |
| |
| public ResponseCache getResponseCache() { |
| return responseCache; |
| } |
| |
| public OkResponseCache getOkResponseCache() { |
| if (responseCache instanceof HttpResponseCache) { |
| return ((HttpResponseCache) responseCache).okResponseCache; |
| } else if (responseCache != null) { |
| return new OkResponseCacheAdapter(responseCache); |
| } else { |
| return null; |
| } |
| } |
| |
| /** |
| * Sets the socket factory used to secure HTTPS connections. |
| * |
| * <p>If unset, the {@link HttpsURLConnection#getDefaultSSLSocketFactory() |
| * system-wide default} 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, the {@link HttpsURLConnection#getDefaultHostnameVerifier() |
| * system-wide default} hostname verifier will be used. |
| */ |
| public OkHttpClient setHostnameVerifier(HostnameVerifier hostnameVerifier) { |
| this.hostnameVerifier = hostnameVerifier; |
| return this; |
| } |
| |
| public HostnameVerifier getHostnameVerifier() { |
| return hostnameVerifier; |
| } |
| |
| /** |
| * 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(OkAuthenticator authenticator) { |
| this.authenticator = authenticator; |
| return this; |
| } |
| |
| public OkAuthenticator 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 setFollowProtocolRedirects(boolean followProtocolRedirects) { |
| this.followProtocolRedirects = followProtocolRedirects; |
| return this; |
| } |
| |
| public boolean getFollowProtocolRedirects() { |
| 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 |
| * 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"); |
| } |
| if (transports.contains("")) { |
| throw new IllegalArgumentException("transports contains an empty string"); |
| } |
| this.transports = transports; |
| return this; |
| } |
| |
| public List<String> getTransports() { |
| return transports; |
| } |
| |
| /** |
| * Schedules {@code request} to be executed. |
| */ |
| /* OkHttp 2.0: public */ void enqueue(Request request, Response.Receiver responseReceiver) { |
| // Create the HttpURLConnection immediately so the enqueued job gets the current settings of |
| // this client. Otherwise changes to this client (socket factory, redirect policy, etc.) may |
| // incorrectly be reflected in the request when it is dispatched later. |
| dispatcher.enqueue(copyWithDefaults(), request, responseReceiver); |
| } |
| |
| /** |
| * Cancels all scheduled tasks tagged with {@code tag}. Requests that are already |
| * in flight might not be canceled. |
| */ |
| /* OkHttp 2.0: public */ void cancel(Object tag) { |
| dispatcher.cancel(tag); |
| } |
| |
| public HttpURLConnection open(URL url) { |
| return open(url, proxy); |
| } |
| |
| HttpURLConnection open(URL url, Proxy proxy) { |
| String protocol = url.getProtocol(); |
| OkHttpClient copy = copyWithDefaults(); |
| copy.proxy = proxy; |
| |
| if (protocol.equals("http")) return new HttpURLConnectionImpl(url, copy); |
| if (protocol.equals("https")) return new HttpsURLConnectionImpl(url, copy); |
| throw new IllegalArgumentException("Unexpected protocol: " + protocol); |
| } |
| |
| /** |
| * Returns a shallow 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(this); |
| 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 |
| : OkHostnameVerifier.INSTANCE; |
| result.authenticator = authenticator != null |
| ? authenticator |
| : HttpAuthenticator.SYSTEM_DEFAULT; |
| result.connectionPool = connectionPool != null ? connectionPool : ConnectionPool.getDefault(); |
| result.followProtocolRedirects = followProtocolRedirects; |
| result.transports = transports != null ? transports : DEFAULT_TRANSPORTS; |
| result.connectTimeout = connectTimeout; |
| result.readTimeout = readTimeout; |
| return result; |
| } |
| |
| /** |
| * Creates a URLStreamHandler as a {@link URL#setURLStreamHandlerFactory}. |
| * |
| * <p>This code configures OkHttp to handle all HTTP and HTTPS connections |
| * created with {@link URL#openConnection()}: <pre> {@code |
| * |
| * OkHttpClient okHttpClient = new OkHttpClient(); |
| * URL.setURLStreamHandlerFactory(okHttpClient); |
| * }</pre> |
| */ |
| public URLStreamHandler createURLStreamHandler(final String protocol) { |
| if (!protocol.equals("http") && !protocol.equals("https")) return null; |
| |
| return new URLStreamHandler() { |
| @Override protected URLConnection openConnection(URL url) { |
| return open(url); |
| } |
| |
| @Override protected URLConnection openConnection(URL url, Proxy proxy) { |
| return open(url, proxy); |
| } |
| |
| @Override protected int getDefaultPort() { |
| if (protocol.equals("http")) return 80; |
| if (protocol.equals("https")) return 443; |
| throw new AssertionError(); |
| } |
| }; |
| } |
| } |