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