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.Dispatcher;
     20 import com.squareup.okhttp.internal.http.HttpAuthenticator;
     21 import com.squareup.okhttp.internal.http.HttpURLConnectionImpl;
     22 import com.squareup.okhttp.internal.http.HttpsURLConnectionImpl;
     23 import com.squareup.okhttp.internal.http.OkResponseCacheAdapter;
     24 import com.squareup.okhttp.internal.tls.OkHostnameVerifier;
     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.util.Arrays;
     35 import java.util.List;
     36 import java.util.concurrent.TimeUnit;
     37 import javax.net.ssl.HostnameVerifier;
     38 import javax.net.ssl.HttpsURLConnection;
     39 import javax.net.ssl.SSLSocketFactory;
     40 
     41 /** Configures and creates HTTP connections. */
     42 public final class OkHttpClient implements URLStreamHandlerFactory {
     43   private static final List<String> DEFAULT_TRANSPORTS
     44       = Util.immutableList(Arrays.asList("spdy/3", "http/1.1"));
     45 
     46   private final RouteDatabase routeDatabase;
     47   private final Dispatcher dispatcher;
     48   private Proxy proxy;
     49   private List<String> transports;
     50   private ProxySelector proxySelector;
     51   private CookieHandler cookieHandler;
     52   private ResponseCache responseCache;
     53   private SSLSocketFactory sslSocketFactory;
     54   private HostnameVerifier hostnameVerifier;
     55   private OkAuthenticator authenticator;
     56   private ConnectionPool connectionPool;
     57   private boolean followProtocolRedirects = true;
     58   private int connectTimeout;
     59   private int readTimeout;
     60 
     61   public OkHttpClient() {
     62     routeDatabase = new RouteDatabase();
     63     dispatcher = new Dispatcher();
     64   }
     65 
     66   private OkHttpClient(OkHttpClient copyFrom) {
     67     routeDatabase = copyFrom.routeDatabase;
     68     dispatcher = copyFrom.dispatcher;
     69   }
     70 
     71   /**
     72    * Sets the default connect timeout for new connections. A value of 0 means no timeout.
     73    *
     74    * @see URLConnection#setConnectTimeout(int)
     75    */
     76   public void setConnectTimeout(long timeout, TimeUnit unit) {
     77     if (timeout < 0) {
     78       throw new IllegalArgumentException("timeout < 0");
     79     }
     80     if (unit == null) {
     81       throw new IllegalArgumentException("unit == null");
     82     }
     83     long millis = unit.toMillis(timeout);
     84     if (millis > Integer.MAX_VALUE) {
     85       throw new IllegalArgumentException("Timeout too large.");
     86     }
     87     connectTimeout = (int) millis;
     88   }
     89 
     90   /** Default connect timeout (in milliseconds). */
     91   public int getConnectTimeout() {
     92     return connectTimeout;
     93   }
     94 
     95   /**
     96    * Sets the default read timeout for new connections. A value of 0 means no timeout.
     97    *
     98    * @see URLConnection#setReadTimeout(int)
     99    */
    100   public void setReadTimeout(long timeout, TimeUnit unit) {
    101     if (timeout < 0) {
    102       throw new IllegalArgumentException("timeout < 0");
    103     }
    104     if (unit == null) {
    105       throw new IllegalArgumentException("unit == null");
    106     }
    107     long millis = unit.toMillis(timeout);
    108     if (millis > Integer.MAX_VALUE) {
    109       throw new IllegalArgumentException("Timeout too large.");
    110     }
    111     readTimeout = (int) millis;
    112   }
    113 
    114   /** Default read timeout (in milliseconds). */
    115   public int getReadTimeout() {
    116     return readTimeout;
    117   }
    118 
    119   /**
    120    * Sets the HTTP proxy that will be used by connections created by this
    121    * client. This takes precedence over {@link #setProxySelector}, which is
    122    * only honored when this proxy is null (which it is by default). To disable
    123    * proxy use completely, call {@code setProxy(Proxy.NO_PROXY)}.
    124    */
    125   public OkHttpClient setProxy(Proxy proxy) {
    126     this.proxy = proxy;
    127     return this;
    128   }
    129 
    130   public Proxy getProxy() {
    131     return proxy;
    132   }
    133 
    134   /**
    135    * Sets the proxy selection policy to be used if no {@link #setProxy proxy}
    136    * is specified explicitly. The proxy selector may return multiple proxies;
    137    * in that case they will be tried in sequence until a successful connection
    138    * is established.
    139    *
    140    * <p>If unset, the {@link ProxySelector#getDefault() system-wide default}
    141    * proxy selector will be used.
    142    */
    143   public OkHttpClient setProxySelector(ProxySelector proxySelector) {
    144     this.proxySelector = proxySelector;
    145     return this;
    146   }
    147 
    148   public ProxySelector getProxySelector() {
    149     return proxySelector;
    150   }
    151 
    152   /**
    153    * Sets the cookie handler to be used to read outgoing cookies and write
    154    * incoming cookies.
    155    *
    156    * <p>If unset, the {@link CookieHandler#getDefault() system-wide default}
    157    * cookie handler will be used.
    158    */
    159   public OkHttpClient setCookieHandler(CookieHandler cookieHandler) {
    160     this.cookieHandler = cookieHandler;
    161     return this;
    162   }
    163 
    164   public CookieHandler getCookieHandler() {
    165     return cookieHandler;
    166   }
    167 
    168   /**
    169    * Sets the response cache to be used to read and write cached responses.
    170    *
    171    * <p>If unset, the {@link ResponseCache#getDefault() system-wide default}
    172    * response cache will be used.
    173    */
    174   public OkHttpClient setResponseCache(ResponseCache responseCache) {
    175     this.responseCache = responseCache;
    176     return this;
    177   }
    178 
    179   public ResponseCache getResponseCache() {
    180     return responseCache;
    181   }
    182 
    183   public OkResponseCache getOkResponseCache() {
    184     if (responseCache instanceof HttpResponseCache) {
    185       return ((HttpResponseCache) responseCache).okResponseCache;
    186     } else if (responseCache != null) {
    187       return new OkResponseCacheAdapter(responseCache);
    188     } else {
    189       return null;
    190     }
    191   }
    192 
    193   /**
    194    * Sets the socket factory used to secure HTTPS connections.
    195    *
    196    * <p>If unset, the {@link HttpsURLConnection#getDefaultSSLSocketFactory()
    197    * system-wide default} SSL socket factory will be used.
    198    */
    199   public OkHttpClient setSslSocketFactory(SSLSocketFactory sslSocketFactory) {
    200     this.sslSocketFactory = sslSocketFactory;
    201     return this;
    202   }
    203 
    204   public SSLSocketFactory getSslSocketFactory() {
    205     return sslSocketFactory;
    206   }
    207 
    208   /**
    209    * Sets the verifier used to confirm that response certificates apply to
    210    * requested hostnames for HTTPS connections.
    211    *
    212    * <p>If unset, the {@link HttpsURLConnection#getDefaultHostnameVerifier()
    213    * system-wide default} hostname verifier will be used.
    214    */
    215   public OkHttpClient setHostnameVerifier(HostnameVerifier hostnameVerifier) {
    216     this.hostnameVerifier = hostnameVerifier;
    217     return this;
    218   }
    219 
    220   public HostnameVerifier getHostnameVerifier() {
    221     return hostnameVerifier;
    222   }
    223 
    224   /**
    225    * Sets the authenticator used to respond to challenges from the remote web
    226    * server or proxy server.
    227    *
    228    * <p>If unset, the {@link java.net.Authenticator#setDefault system-wide default}
    229    * authenticator will be used.
    230    */
    231   public OkHttpClient setAuthenticator(OkAuthenticator authenticator) {
    232     this.authenticator = authenticator;
    233     return this;
    234   }
    235 
    236   public OkAuthenticator getAuthenticator() {
    237     return authenticator;
    238   }
    239 
    240   /**
    241    * Sets the connection pool used to recycle HTTP and HTTPS connections.
    242    *
    243    * <p>If unset, the {@link ConnectionPool#getDefault() system-wide
    244    * default} connection pool will be used.
    245    */
    246   public OkHttpClient setConnectionPool(ConnectionPool connectionPool) {
    247     this.connectionPool = connectionPool;
    248     return this;
    249   }
    250 
    251   public ConnectionPool getConnectionPool() {
    252     return connectionPool;
    253   }
    254 
    255   /**
    256    * Configure this client to follow redirects from HTTPS to HTTP and from HTTP
    257    * to HTTPS.
    258    *
    259    * <p>If unset, protocol redirects will be followed. This is different than
    260    * the built-in {@code HttpURLConnection}'s default.
    261    */
    262   public OkHttpClient setFollowProtocolRedirects(boolean followProtocolRedirects) {
    263     this.followProtocolRedirects = followProtocolRedirects;
    264     return this;
    265   }
    266 
    267   public boolean getFollowProtocolRedirects() {
    268     return followProtocolRedirects;
    269   }
    270 
    271   public RouteDatabase getRoutesDatabase() {
    272     return routeDatabase;
    273   }
    274 
    275   /**
    276    * Configure the transports used by this client to communicate with remote
    277    * servers. By default this client will prefer the most efficient transport
    278    * available, falling back to more ubiquitous transports. Applications should
    279    * only call this method to avoid specific compatibility problems, such as web
    280    * servers that behave incorrectly when SPDY is enabled.
    281    *
    282    * <p>The following transports are currently supported:
    283    * <ul>
    284    *   <li><a href="http://www.w3.org/Protocols/rfc2616/rfc2616.html">http/1.1</a>
    285    *   <li><a href="http://www.chromium.org/spdy/spdy-protocol/spdy-protocol-draft3">spdy/3</a>
    286    * </ul>
    287    *
    288    * <p><strong>This is an evolving set.</strong> Future releases may drop
    289    * support for transitional transports (like spdy/3), in favor of their
    290    * successors (spdy/4 or http/2.0). The http/1.1 transport will never be
    291    * dropped.
    292    *
    293    * <p>If multiple protocols are specified, <a
    294    * href="https://technotes.googlecode.com/git/nextprotoneg.html">NPN</a> will
    295    * be used to negotiate a transport. Future releases may use another mechanism
    296    * (such as <a href="http://tools.ietf.org/html/draft-friedl-tls-applayerprotoneg-02">ALPN</a>)
    297    * to negotiate a transport.
    298    *
    299    * @param transports the transports to use, in order of preference. The list
    300    *     must contain "http/1.1". It must not contain null.
    301    */
    302   public OkHttpClient setTransports(List<String> transports) {
    303     transports = Util.immutableList(transports);
    304     if (!transports.contains("http/1.1")) {
    305       throw new IllegalArgumentException("transports doesn't contain http/1.1: " + transports);
    306     }
    307     if (transports.contains(null)) {
    308       throw new IllegalArgumentException("transports must not contain null");
    309     }
    310     if (transports.contains("")) {
    311       throw new IllegalArgumentException("transports contains an empty string");
    312     }
    313     this.transports = transports;
    314     return this;
    315   }
    316 
    317   public List<String> getTransports() {
    318     return transports;
    319   }
    320 
    321   /**
    322    * Schedules {@code request} to be executed.
    323    */
    324   public void enqueue(Request request, Response.Receiver responseReceiver) {
    325     // Create the HttpURLConnection immediately so the enqueued job gets the current settings of
    326     // this client. Otherwise changes to this client (socket factory, redirect policy, etc.) may
    327     // incorrectly be reflected in the request when it is dispatched later.
    328     dispatcher.enqueue(open(request.url()), request, responseReceiver);
    329   }
    330 
    331   /**
    332    * Cancels all scheduled tasks tagged with {@code tag}. Requests that are already
    333    * in flight might not be canceled.
    334    */
    335   public void cancel(Object tag) {
    336     dispatcher.cancel(tag);
    337   }
    338 
    339   public HttpURLConnection open(URL url) {
    340     return open(url, proxy);
    341   }
    342 
    343   HttpURLConnection open(URL url, Proxy proxy) {
    344     String protocol = url.getProtocol();
    345     OkHttpClient copy = copyWithDefaults();
    346     copy.proxy = proxy;
    347 
    348     if (protocol.equals("http")) return new HttpURLConnectionImpl(url, copy);
    349     if (protocol.equals("https")) return new HttpsURLConnectionImpl(url, copy);
    350     throw new IllegalArgumentException("Unexpected protocol: " + protocol);
    351   }
    352 
    353   /**
    354    * Returns a shallow copy of this OkHttpClient that uses the system-wide default for
    355    * each field that hasn't been explicitly configured.
    356    */
    357   private OkHttpClient copyWithDefaults() {
    358     OkHttpClient result = new OkHttpClient(this);
    359     result.proxy = proxy;
    360     result.proxySelector = proxySelector != null ? proxySelector : ProxySelector.getDefault();
    361     result.cookieHandler = cookieHandler != null ? cookieHandler : CookieHandler.getDefault();
    362     result.responseCache = responseCache != null ? responseCache : ResponseCache.getDefault();
    363     result.sslSocketFactory = sslSocketFactory != null
    364         ? sslSocketFactory
    365         : HttpsURLConnection.getDefaultSSLSocketFactory();
    366     result.hostnameVerifier = hostnameVerifier != null
    367         ? hostnameVerifier
    368         : OkHostnameVerifier.INSTANCE;
    369     result.authenticator = authenticator != null
    370         ? authenticator
    371         : HttpAuthenticator.SYSTEM_DEFAULT;
    372     result.connectionPool = connectionPool != null ? connectionPool : ConnectionPool.getDefault();
    373     result.followProtocolRedirects = followProtocolRedirects;
    374     result.transports = transports != null ? transports : DEFAULT_TRANSPORTS;
    375     result.connectTimeout = connectTimeout;
    376     result.readTimeout = readTimeout;
    377     return result;
    378   }
    379 
    380   /**
    381    * Creates a URLStreamHandler as a {@link URL#setURLStreamHandlerFactory}.
    382    *
    383    * <p>This code configures OkHttp to handle all HTTP and HTTPS connections
    384    * created with {@link URL#openConnection()}: <pre>   {@code
    385    *
    386    *   OkHttpClient okHttpClient = new OkHttpClient();
    387    *   URL.setURLStreamHandlerFactory(okHttpClient);
    388    * }</pre>
    389    */
    390   public URLStreamHandler createURLStreamHandler(final String protocol) {
    391     if (!protocol.equals("http") && !protocol.equals("https")) return null;
    392 
    393     return new URLStreamHandler() {
    394       @Override protected URLConnection openConnection(URL url) {
    395         return open(url);
    396       }
    397 
    398       @Override protected URLConnection openConnection(URL url, Proxy proxy) {
    399         return open(url, proxy);
    400       }
    401 
    402       @Override protected int getDefaultPort() {
    403         if (protocol.equals("http")) return 80;
    404         if (protocol.equals("https")) return 443;
    405         throw new AssertionError();
    406       }
    407     };
    408   }
    409 }
    410