Home | History | Annotate | Download | only in okhttp
      1 /*
      2  * Copyright (C) 2012 Square, Inc.
      3  *
      4  * Licensed under the Apache License, Version 2.0 (the "License");
      5  * you may not use this file except in compliance with the License.
      6  * You may obtain a copy of the License at
      7  *
      8  *      http://www.apache.org/licenses/LICENSE-2.0
      9  *
     10  * Unless required by applicable law or agreed to in writing, software
     11  * distributed under the License is distributed on an "AS IS" BASIS,
     12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     13  * See the License for the specific language governing permissions and
     14  * limitations under the License.
     15  */
     16 package com.squareup.okhttp;
     17 
     18 import com.squareup.okhttp.internal.Util;
     19 import com.squareup.okhttp.internal.http.HttpAuthenticator;
     20 import com.squareup.okhttp.internal.http.HttpURLConnectionImpl;
     21 import com.squareup.okhttp.internal.http.HttpsURLConnectionImpl;
     22 import com.squareup.okhttp.internal.http.ResponseCacheAdapter;
     23 import com.squareup.okhttp.internal.tls.OkHostnameVerifier;
     24 import java.io.IOException;
     25 import java.net.CookieHandler;
     26 import java.net.HttpURLConnection;
     27 import java.net.Proxy;
     28 import java.net.ProxySelector;
     29 import java.net.ResponseCache;
     30 import java.net.URL;
     31 import java.net.URLConnection;
     32 import java.net.URLStreamHandler;
     33 import java.net.URLStreamHandlerFactory;
     34 import java.security.GeneralSecurityException;
     35 import java.util.ArrayList;
     36 import java.util.List;
     37 import java.util.concurrent.TimeUnit;
     38 import javax.net.SocketFactory;
     39 import javax.net.ssl.HostnameVerifier;
     40 import javax.net.ssl.SSLContext;
     41 import javax.net.ssl.SSLSocketFactory;
     42 import okio.ByteString;
     43 
     44 /**
     45  * Configures and creates HTTP connections. Most applications can use a single
     46  * OkHttpClient for all of their HTTP requests - benefiting from a shared
     47  * response cache, thread pool, connection re-use, etc.
     48  *
     49  * Instances of OkHttpClient are intended to be fully configured before they're
     50  * shared - once shared they should be treated as immutable and can safely be used
     51  * to concurrently open new connections. If required, threads can call
     52  * {@link #clone()} to make a shallow copy of the OkHttpClient that can be
     53  * safely modified with further configuration changes.
     54  */
     55 public final class OkHttpClient implements URLStreamHandlerFactory, Cloneable {
     56 
     57   private final RouteDatabase routeDatabase;
     58   private Dispatcher dispatcher;
     59   private Proxy proxy;
     60   private List<Protocol> protocols;
     61   private ProxySelector proxySelector;
     62   private CookieHandler cookieHandler;
     63   private OkResponseCache responseCache;
     64   private SocketFactory socketFactory;
     65   private SSLSocketFactory sslSocketFactory;
     66   private HostnameVerifier hostnameVerifier;
     67   private OkAuthenticator authenticator;
     68   private ConnectionPool connectionPool;
     69   private HostResolver hostResolver;
     70   private boolean followProtocolRedirects = true;
     71   private int connectTimeout;
     72   private int readTimeout;
     73 
     74   public OkHttpClient() {
     75     routeDatabase = new RouteDatabase();
     76     dispatcher = new Dispatcher();
     77   }
     78 
     79   /**
     80    * Sets the default connect timeout for new connections. A value of 0 means no timeout.
     81    *
     82    * @see URLConnection#setConnectTimeout(int)
     83    */
     84   public void setConnectTimeout(long timeout, TimeUnit unit) {
     85     if (timeout < 0) {
     86       throw new IllegalArgumentException("timeout < 0");
     87     }
     88     if (unit == null) {
     89       throw new IllegalArgumentException("unit == null");
     90     }
     91     long millis = unit.toMillis(timeout);
     92     if (millis > Integer.MAX_VALUE) {
     93       throw new IllegalArgumentException("Timeout too large.");
     94     }
     95     connectTimeout = (int) millis;
     96   }
     97 
     98   /** Default connect timeout (in milliseconds). */
     99   public int getConnectTimeout() {
    100     return connectTimeout;
    101   }
    102 
    103   /**
    104    * Sets the default read timeout for new connections. A value of 0 means no timeout.
    105    *
    106    * @see URLConnection#setReadTimeout(int)
    107    */
    108   public void setReadTimeout(long timeout, TimeUnit unit) {
    109     if (timeout < 0) {
    110       throw new IllegalArgumentException("timeout < 0");
    111     }
    112     if (unit == null) {
    113       throw new IllegalArgumentException("unit == null");
    114     }
    115     long millis = unit.toMillis(timeout);
    116     if (millis > Integer.MAX_VALUE) {
    117       throw new IllegalArgumentException("Timeout too large.");
    118     }
    119     readTimeout = (int) millis;
    120   }
    121 
    122   /** Default read timeout (in milliseconds). */
    123   public int getReadTimeout() {
    124     return readTimeout;
    125   }
    126 
    127   /**
    128    * Sets the HTTP proxy that will be used by connections created by this
    129    * client. This takes precedence over {@link #setProxySelector}, which is
    130    * only honored when this proxy is null (which it is by default). To disable
    131    * proxy use completely, call {@code setProxy(Proxy.NO_PROXY)}.
    132    */
    133   public OkHttpClient setProxy(Proxy proxy) {
    134     this.proxy = proxy;
    135     return this;
    136   }
    137 
    138   public Proxy getProxy() {
    139     return proxy;
    140   }
    141 
    142   /**
    143    * Sets the proxy selection policy to be used if no {@link #setProxy proxy}
    144    * is specified explicitly. The proxy selector may return multiple proxies;
    145    * in that case they will be tried in sequence until a successful connection
    146    * is established.
    147    *
    148    * <p>If unset, the {@link ProxySelector#getDefault() system-wide default}
    149    * proxy selector will be used.
    150    */
    151   public OkHttpClient setProxySelector(ProxySelector proxySelector) {
    152     this.proxySelector = proxySelector;
    153     return this;
    154   }
    155 
    156   public ProxySelector getProxySelector() {
    157     return proxySelector;
    158   }
    159 
    160   /**
    161    * Sets the cookie handler to be used to read outgoing cookies and write
    162    * incoming cookies.
    163    *
    164    * <p>If unset, the {@link CookieHandler#getDefault() system-wide default}
    165    * cookie handler will be used.
    166    */
    167   public OkHttpClient setCookieHandler(CookieHandler cookieHandler) {
    168     this.cookieHandler = cookieHandler;
    169     return this;
    170   }
    171 
    172   public CookieHandler getCookieHandler() {
    173     return cookieHandler;
    174   }
    175 
    176   /**
    177    * Sets the response cache to be used to read and write cached responses.
    178    */
    179   public OkHttpClient setResponseCache(ResponseCache responseCache) {
    180     return setOkResponseCache(toOkResponseCache(responseCache));
    181   }
    182 
    183   public ResponseCache getResponseCache() {
    184     return responseCache instanceof ResponseCacheAdapter
    185         ? ((ResponseCacheAdapter) responseCache).getDelegate()
    186         : null;
    187   }
    188 
    189   public OkHttpClient setOkResponseCache(OkResponseCache responseCache) {
    190     this.responseCache = responseCache;
    191     return this;
    192   }
    193 
    194   public OkResponseCache getOkResponseCache() {
    195     return responseCache;
    196   }
    197 
    198   /**
    199    * Sets the socket factory used to create connections.
    200    *
    201    * <p>If unset, the {@link SocketFactory#getDefault() system-wide default}
    202    * socket factory will be used.
    203    */
    204   public OkHttpClient setSocketFactory(SocketFactory socketFactory) {
    205     this.socketFactory = socketFactory;
    206     return this;
    207   }
    208 
    209   public SocketFactory getSocketFactory() {
    210     return socketFactory;
    211   }
    212 
    213   /**
    214    * Sets the socket factory used to secure HTTPS connections.
    215    *
    216    * <p>If unset, a lazily created SSL socket factory will be used.
    217    */
    218   public OkHttpClient setSslSocketFactory(SSLSocketFactory sslSocketFactory) {
    219     this.sslSocketFactory = sslSocketFactory;
    220     return this;
    221   }
    222 
    223   public SSLSocketFactory getSslSocketFactory() {
    224     return sslSocketFactory;
    225   }
    226 
    227   /**
    228    * Sets the verifier used to confirm that response certificates apply to
    229    * requested hostnames for HTTPS connections.
    230    *
    231    * <p>If unset, the
    232    * {@link javax.net.ssl.HttpsURLConnection#getDefaultHostnameVerifier()
    233    * system-wide default} hostname verifier will be used.
    234    */
    235   public OkHttpClient setHostnameVerifier(HostnameVerifier hostnameVerifier) {
    236     this.hostnameVerifier = hostnameVerifier;
    237     return this;
    238   }
    239 
    240   public HostnameVerifier getHostnameVerifier() {
    241     return hostnameVerifier;
    242   }
    243 
    244   /**
    245    * Sets the authenticator used to respond to challenges from the remote web
    246    * server or proxy server.
    247    *
    248    * <p>If unset, the {@link java.net.Authenticator#setDefault system-wide default}
    249    * authenticator will be used.
    250    */
    251   public OkHttpClient setAuthenticator(OkAuthenticator authenticator) {
    252     this.authenticator = authenticator;
    253     return this;
    254   }
    255 
    256   public OkAuthenticator getAuthenticator() {
    257     return authenticator;
    258   }
    259 
    260   /**
    261    * Sets the connection pool used to recycle HTTP and HTTPS connections.
    262    *
    263    * <p>If unset, the {@link ConnectionPool#getDefault() system-wide
    264    * default} connection pool will be used.
    265    */
    266   public OkHttpClient setConnectionPool(ConnectionPool connectionPool) {
    267     this.connectionPool = connectionPool;
    268     return this;
    269   }
    270 
    271   public ConnectionPool getConnectionPool() {
    272     return connectionPool;
    273   }
    274 
    275   /**
    276    * Configure this client to follow redirects from HTTPS to HTTP and from HTTP
    277    * to HTTPS.
    278    *
    279    * <p>If unset, protocol redirects will be followed. This is different than
    280    * the built-in {@code HttpURLConnection}'s default.
    281    */
    282   public OkHttpClient setFollowProtocolRedirects(boolean followProtocolRedirects) {
    283     this.followProtocolRedirects = followProtocolRedirects;
    284     return this;
    285   }
    286 
    287   public boolean getFollowProtocolRedirects() {
    288     return followProtocolRedirects;
    289   }
    290 
    291   public RouteDatabase getRoutesDatabase() {
    292     return routeDatabase;
    293   }
    294 
    295   /**
    296    * Sets the dispatcher used to set policy and execute asynchronous requests.
    297    * Must not be null.
    298    */
    299   public OkHttpClient setDispatcher(Dispatcher dispatcher) {
    300     if (dispatcher == null) throw new IllegalArgumentException("dispatcher == null");
    301     this.dispatcher = dispatcher;
    302     return this;
    303   }
    304 
    305   public Dispatcher getDispatcher() {
    306     return dispatcher;
    307   }
    308 
    309   /**
    310    * @deprecated OkHttp 1.5 enforces an enumeration of {@link Protocol
    311    *     protocols} that can be selected. Please switch to {@link
    312    *     #setProtocols(java.util.List)}.
    313    */
    314   @Deprecated
    315   public OkHttpClient setTransports(List<String> transports) {
    316     List<Protocol> protocols = new ArrayList<Protocol>(transports.size());
    317     for (int i = 0, size = transports.size(); i < size; i++) {
    318       try {
    319         Protocol protocol = Protocol.find(ByteString.encodeUtf8(transports.get(i)));
    320         protocols.add(protocol);
    321       } catch (IOException e) {
    322         throw new IllegalArgumentException(e);
    323       }
    324     }
    325     return setProtocols(protocols);
    326   }
    327 
    328   /**
    329    * Configure the protocols used by this client to communicate with remote
    330    * servers. By default this client will prefer the most efficient transport
    331    * available, falling back to more ubiquitous protocols. Applications should
    332    * only call this method to avoid specific compatibility problems, such as web
    333    * servers that behave incorrectly when SPDY is enabled.
    334    *
    335    * <p>The following protocols are currently supported:
    336    * <ul>
    337    *   <li><a href="http://www.w3.org/Protocols/rfc2616/rfc2616.html">http/1.1</a>
    338    *   <li><a href="http://www.chromium.org/spdy/spdy-protocol/spdy-protocol-draft3-1">spdy/3.1</a>
    339    *   <li><a href="http://tools.ietf.org/html/draft-ietf-httpbis-http2-09">HTTP-draft-09/2.0</a>
    340    * </ul>
    341    *
    342    * <p><strong>This is an evolving set.</strong> Future releases may drop
    343    * support for transitional protocols (like spdy/3.1), in favor of their
    344    * successors (spdy/4 or http/2.0). The http/1.1 transport will never be
    345    * dropped.
    346    *
    347    * <p>If multiple protocols are specified, <a
    348    * href="https://technotes.googlecode.com/git/nextprotoneg.html">NPN</a> will
    349    * be used to negotiate a transport. Future releases may use another mechanism
    350    * (such as <a href="http://tools.ietf.org/html/draft-friedl-tls-applayerprotoneg-02">ALPN</a>)
    351    * to negotiate a transport.
    352    *
    353    * @param protocols the protocols to use, in order of preference. The list
    354    *     must contain "http/1.1". It must not contain null.
    355    */
    356   public OkHttpClient setProtocols(List<Protocol> protocols) {
    357     protocols = Util.immutableList(protocols);
    358     if (!protocols.contains(Protocol.HTTP_11)) {
    359       throw new IllegalArgumentException("protocols doesn't contain http/1.1: " + protocols);
    360     }
    361     if (protocols.contains(null)) {
    362       throw new IllegalArgumentException("protocols must not contain null");
    363     }
    364     this.protocols = Util.immutableList(protocols);
    365     return this;
    366   }
    367 
    368   /**
    369    * @deprecated OkHttp 1.5 enforces an enumeration of {@link Protocol
    370    *     protocols} that can be selected. Please switch to {@link
    371    *     #getProtocols()}.
    372    */
    373   @Deprecated
    374   public List<String> getTransports() {
    375     List<String> transports = new ArrayList<String>(protocols.size());
    376     for (int i = 0, size = protocols.size(); i < size; i++) {
    377       transports.add(protocols.get(i).name.utf8());
    378     }
    379     return transports;
    380   }
    381 
    382   public List<Protocol> getProtocols() {
    383     return protocols;
    384   }
    385 
    386   /*
    387    * Sets the {@code HostResolver} that will be used by this client to resolve
    388    * hostnames to IP addresses.
    389    */
    390   public OkHttpClient setHostResolver(HostResolver hostResolver) {
    391     this.hostResolver = hostResolver;
    392     return this;
    393   }
    394 
    395   public HostResolver getHostResolver() {
    396     return hostResolver;
    397   }
    398 
    399   /**
    400    * Invokes {@code request} immediately, and blocks until the response can be
    401    * processed or is in error.
    402    *
    403    * <p>The caller may read the response body with the response's
    404    * {@link Response#body} method.  To facilitate connection recycling, callers
    405    * should always {@link Response.Body#close() close the response body}.
    406    *
    407    * <p>Note that transport-layer success (receiving a HTTP response code,
    408    * headers and body) does not necessarily indicate application-layer
    409    * success: {@code response} may still indicate an unhappy HTTP response
    410    * code like 404 or 500.
    411    *
    412    * <h3>Non-blocking responses</h3>
    413    *
    414    * <p>Receivers do not need to block while waiting for the response body to
    415    * download. Instead, they can get called back as data arrives. Use {@link
    416    * Response.Body#ready} to check if bytes should be read immediately. While
    417    * there is data ready, read it.
    418    *
    419    * <p>The current implementation of {@link Response.Body#ready} always
    420    * returns true when the underlying transport is HTTP/1. This results in
    421    * blocking on that transport. For effective non-blocking your server must
    422    * support {@link Protocol#SPDY_3} or {@link Protocol#HTTP_2}.
    423    *
    424    * @throws IOException when the request could not be executed due to a
    425    * connectivity problem or timeout. Because networks can fail during an
    426    * exchange, it is possible that the remote server accepted the request
    427    * before the failure.
    428    */
    429   public Response execute(Request request) throws IOException {
    430     // Copy the client. Otherwise changes (socket factory, redirect policy,
    431     // etc.) may incorrectly be reflected in the request when it is executed.
    432     OkHttpClient client = copyWithDefaults();
    433     Job job = new Job(dispatcher, client, request, null);
    434     Response result = job.getResponse(); // Since we don't cancel, this won't be null.
    435     job.engine.releaseConnection(); // Transfer ownership of the body to the caller.
    436     return result;
    437   }
    438 
    439   /**
    440    * Schedules {@code request} to be executed at some point in the future. The
    441    * {@link #getDispatcher dispatcher} defines when the request will run:
    442    * usually immediately unless there are several other requests currently being
    443    * executed.
    444    *
    445    * <p>This client will later call back {@code responseReceiver} with either an
    446    * HTTP response or a failure exception. If you {@link #cancel} a request
    447    * before it completes the receiver will not be called back.
    448    */
    449   public void enqueue(Request request, Response.Receiver responseReceiver) {
    450     dispatcher.enqueue(this, request, responseReceiver);
    451   }
    452 
    453   /**
    454    * Cancels all scheduled tasks tagged with {@code tag}. Requests that are already
    455    * complete cannot be canceled.
    456    */
    457   public void cancel(Object tag) {
    458     dispatcher.cancel(tag);
    459   }
    460 
    461   public HttpURLConnection open(URL url) {
    462     return open(url, proxy);
    463   }
    464 
    465   HttpURLConnection open(URL url, Proxy proxy) {
    466     String protocol = url.getProtocol();
    467     OkHttpClient copy = copyWithDefaults();
    468     copy.proxy = proxy;
    469 
    470     if (protocol.equals("http")) return new HttpURLConnectionImpl(url, copy);
    471     if (protocol.equals("https")) return new HttpsURLConnectionImpl(url, copy);
    472     throw new IllegalArgumentException("Unexpected protocol: " + protocol);
    473   }
    474 
    475   /**
    476    * Returns a shallow copy of this OkHttpClient that uses the system-wide
    477    * default for each field that hasn't been explicitly configured.
    478    */
    479   OkHttpClient copyWithDefaults() {
    480     OkHttpClient result = clone();
    481     if (result.proxySelector == null) {
    482       result.proxySelector = ProxySelector.getDefault();
    483     }
    484     if (result.cookieHandler == null) {
    485       result.cookieHandler = CookieHandler.getDefault();
    486     }
    487     if (result.responseCache == null) {
    488       result.responseCache = toOkResponseCache(ResponseCache.getDefault());
    489     }
    490     if (result.socketFactory == null) {
    491       result.socketFactory = SocketFactory.getDefault();
    492     }
    493     if (result.sslSocketFactory == null) {
    494       result.sslSocketFactory = getDefaultSSLSocketFactory();
    495     }
    496     if (result.hostnameVerifier == null) {
    497       result.hostnameVerifier = OkHostnameVerifier.INSTANCE;
    498     }
    499     if (result.authenticator == null) {
    500       result.authenticator = HttpAuthenticator.SYSTEM_DEFAULT;
    501     }
    502     if (result.connectionPool == null) {
    503       result.connectionPool = ConnectionPool.getDefault();
    504     }
    505     if (result.protocols == null) {
    506       result.protocols = Protocol.HTTP2_SPDY3_AND_HTTP;
    507     }
    508     if (result.hostResolver == null) {
    509       result.hostResolver = HostResolver.DEFAULT;
    510     }
    511     return result;
    512   }
    513 
    514   /**
    515    * Java and Android programs default to using a single global SSL context,
    516    * accessible to HTTP clients as {@link SSLSocketFactory#getDefault()}. If we
    517    * used the shared SSL context, when OkHttp enables NPN for its SPDY-related
    518    * stuff, it would also enable NPN for other usages, which might crash them
    519    * because NPN is enabled when it isn't expected to be.
    520    * <p>
    521    * This code avoids that by defaulting to an OkHttp created SSL context. The
    522    * significant drawback of this approach is that apps that customize the
    523    * global SSL context will lose these customizations.
    524    */
    525   private synchronized SSLSocketFactory getDefaultSSLSocketFactory() {
    526     if (sslSocketFactory == null) {
    527       try {
    528         SSLContext sslContext = SSLContext.getInstance("TLS");
    529         sslContext.init(null, null, null);
    530         sslSocketFactory = sslContext.getSocketFactory();
    531       } catch (GeneralSecurityException e) {
    532         throw new AssertionError(); // The system has no TLS. Just give up.
    533       }
    534     }
    535     return sslSocketFactory;
    536   }
    537 
    538   /** Returns a shallow copy of this OkHttpClient. */
    539   @Override public OkHttpClient clone() {
    540     try {
    541       return (OkHttpClient) super.clone();
    542     } catch (CloneNotSupportedException e) {
    543       throw new AssertionError();
    544     }
    545   }
    546 
    547   private OkResponseCache toOkResponseCache(ResponseCache responseCache) {
    548     return responseCache == null || responseCache instanceof OkResponseCache
    549         ? (OkResponseCache) responseCache
    550         : new ResponseCacheAdapter(responseCache);
    551   }
    552 
    553   /**
    554    * Creates a URLStreamHandler as a {@link URL#setURLStreamHandlerFactory}.
    555    *
    556    * <p>This code configures OkHttp to handle all HTTP and HTTPS connections
    557    * created with {@link URL#openConnection()}: <pre>   {@code
    558    *
    559    *   OkHttpClient okHttpClient = new OkHttpClient();
    560    *   URL.setURLStreamHandlerFactory(okHttpClient);
    561    * }</pre>
    562    */
    563   public URLStreamHandler createURLStreamHandler(final String protocol) {
    564     if (!protocol.equals("http") && !protocol.equals("https")) return null;
    565 
    566     return new URLStreamHandler() {
    567       @Override protected URLConnection openConnection(URL url) {
    568         return open(url);
    569       }
    570 
    571       @Override protected URLConnection openConnection(URL url, Proxy proxy) {
    572         return open(url, proxy);
    573       }
    574 
    575       @Override protected int getDefaultPort() {
    576         if (protocol.equals("http")) return 80;
    577         if (protocol.equals("https")) return 443;
    578         throw new AssertionError();
    579       }
    580     };
    581   }
    582 }
    583