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.Internal; 19 import com.squareup.okhttp.internal.InternalCache; 20 import com.squareup.okhttp.internal.Network; 21 import com.squareup.okhttp.internal.RouteDatabase; 22 import com.squareup.okhttp.internal.Util; 23 import com.squareup.okhttp.internal.http.AuthenticatorAdapter; 24 import com.squareup.okhttp.internal.http.HttpEngine; 25 import com.squareup.okhttp.internal.http.RouteException; 26 import com.squareup.okhttp.internal.http.Transport; 27 import com.squareup.okhttp.internal.tls.OkHostnameVerifier; 28 import java.io.IOException; 29 import java.net.CookieHandler; 30 import java.net.Proxy; 31 import java.net.ProxySelector; 32 import java.net.URLConnection; 33 import java.security.GeneralSecurityException; 34 import java.util.ArrayList; 35 import java.util.List; 36 import java.util.concurrent.TimeUnit; 37 import javax.net.SocketFactory; 38 import javax.net.ssl.HostnameVerifier; 39 import javax.net.ssl.SSLContext; 40 import javax.net.ssl.SSLSocket; 41 import javax.net.ssl.SSLSocketFactory; 42 import okio.BufferedSink; 43 import okio.BufferedSource; 44 45 /** 46 * Configures and creates HTTP connections. Most applications can use a single 47 * OkHttpClient for all of their HTTP requests - benefiting from a shared 48 * response cache, thread pool, connection re-use, etc. 49 * 50 * <p>Instances of OkHttpClient are intended to be fully configured before they're 51 * shared - once shared they should be treated as immutable and can safely be used 52 * to concurrently open new connections. If required, threads can call 53 * {@link #clone()} to make a shallow copy of the OkHttpClient that can be 54 * safely modified with further configuration changes. 55 */ 56 public class OkHttpClient implements Cloneable { 57 private static final List<Protocol> DEFAULT_PROTOCOLS = Util.immutableList( 58 Protocol.HTTP_2, Protocol.SPDY_3, Protocol.HTTP_1_1); 59 60 private static final List<ConnectionSpec> DEFAULT_CONNECTION_SPECS = Util.immutableList( 61 ConnectionSpec.MODERN_TLS, ConnectionSpec.COMPATIBLE_TLS, ConnectionSpec.CLEARTEXT); 62 63 static { 64 Internal.instance = new Internal() { 65 @Override public Transport newTransport( 66 Connection connection, HttpEngine httpEngine) throws IOException { 67 return connection.newTransport(httpEngine); 68 } 69 70 @Override public boolean clearOwner(Connection connection) { 71 return connection.clearOwner(); 72 } 73 74 @Override public void closeIfOwnedBy(Connection connection, Object owner) throws IOException { 75 connection.closeIfOwnedBy(owner); 76 } 77 78 @Override public int recycleCount(Connection connection) { 79 return connection.recycleCount(); 80 } 81 82 @Override public void setProtocol(Connection connection, Protocol protocol) { 83 connection.setProtocol(protocol); 84 } 85 86 @Override public void setOwner(Connection connection, HttpEngine httpEngine) { 87 connection.setOwner(httpEngine); 88 } 89 90 @Override public boolean isReadable(Connection pooled) { 91 return pooled.isReadable(); 92 } 93 94 @Override public void addLenient(Headers.Builder builder, String line) { 95 builder.addLenient(line); 96 } 97 98 @Override public void addLenient(Headers.Builder builder, String name, String value) { 99 builder.addLenient(name, value); 100 } 101 102 @Override public void setCache(OkHttpClient client, InternalCache internalCache) { 103 client.setInternalCache(internalCache); 104 } 105 106 @Override public InternalCache internalCache(OkHttpClient client) { 107 return client.internalCache(); 108 } 109 110 @Override public void recycle(ConnectionPool pool, Connection connection) { 111 pool.recycle(connection); 112 } 113 114 @Override public RouteDatabase routeDatabase(OkHttpClient client) { 115 return client.routeDatabase(); 116 } 117 118 @Override public Network network(OkHttpClient client) { 119 return client.network; 120 } 121 122 @Override public void setNetwork(OkHttpClient client, Network network) { 123 client.network = network; 124 } 125 126 @Override public void connectAndSetOwner(OkHttpClient client, Connection connection, 127 HttpEngine owner, Request request) throws RouteException { 128 connection.connectAndSetOwner(client, owner, request); 129 } 130 131 @Override 132 public void callEnqueue(Call call, Callback responseCallback, boolean forWebSocket) { 133 call.enqueue(responseCallback, forWebSocket); 134 } 135 136 @Override public void callEngineReleaseConnection(Call call) throws IOException { 137 call.engine.releaseConnection(); 138 } 139 140 @Override public Connection callEngineGetConnection(Call call) { 141 return call.engine.getConnection(); 142 } 143 144 @Override public BufferedSource connectionRawSource(Connection connection) { 145 return connection.rawSource(); 146 } 147 148 @Override public BufferedSink connectionRawSink(Connection connection) { 149 return connection.rawSink(); 150 } 151 152 @Override public void connectionSetOwner(Connection connection, Object owner) { 153 connection.setOwner(owner); 154 } 155 156 @Override 157 public void apply(ConnectionSpec tlsConfiguration, SSLSocket sslSocket, boolean isFallback) { 158 tlsConfiguration.apply(sslSocket, isFallback); 159 } 160 }; 161 } 162 163 /** Lazily-initialized. */ 164 private static SSLSocketFactory defaultSslSocketFactory; 165 166 private final RouteDatabase routeDatabase; 167 private Dispatcher dispatcher; 168 private Proxy proxy; 169 private List<Protocol> protocols; 170 private List<ConnectionSpec> connectionSpecs; 171 private final List<Interceptor> interceptors = new ArrayList<>(); 172 private final List<Interceptor> networkInterceptors = new ArrayList<>(); 173 private ProxySelector proxySelector; 174 private CookieHandler cookieHandler; 175 176 /** Non-null if this client is caching; possibly by {@code cache}. */ 177 private InternalCache internalCache; 178 private Cache cache; 179 180 private SocketFactory socketFactory; 181 private SSLSocketFactory sslSocketFactory; 182 private HostnameVerifier hostnameVerifier; 183 private CertificatePinner certificatePinner; 184 private Authenticator authenticator; 185 private ConnectionPool connectionPool; 186 private Network network; 187 private boolean followSslRedirects = true; 188 private boolean followRedirects = true; 189 private boolean retryOnConnectionFailure = true; 190 private int connectTimeout; 191 private int readTimeout; 192 private int writeTimeout; 193 194 public OkHttpClient() { 195 routeDatabase = new RouteDatabase(); 196 dispatcher = new Dispatcher(); 197 } 198 199 private OkHttpClient(OkHttpClient okHttpClient) { 200 this.routeDatabase = okHttpClient.routeDatabase; 201 this.dispatcher = okHttpClient.dispatcher; 202 this.proxy = okHttpClient.proxy; 203 this.protocols = okHttpClient.protocols; 204 this.connectionSpecs = okHttpClient.connectionSpecs; 205 this.interceptors.addAll(okHttpClient.interceptors); 206 this.networkInterceptors.addAll(okHttpClient.networkInterceptors); 207 this.proxySelector = okHttpClient.proxySelector; 208 this.cookieHandler = okHttpClient.cookieHandler; 209 this.cache = okHttpClient.cache; 210 this.internalCache = cache != null ? cache.internalCache : okHttpClient.internalCache; 211 this.socketFactory = okHttpClient.socketFactory; 212 this.sslSocketFactory = okHttpClient.sslSocketFactory; 213 this.hostnameVerifier = okHttpClient.hostnameVerifier; 214 this.certificatePinner = okHttpClient.certificatePinner; 215 this.authenticator = okHttpClient.authenticator; 216 this.connectionPool = okHttpClient.connectionPool; 217 this.network = okHttpClient.network; 218 this.followSslRedirects = okHttpClient.followSslRedirects; 219 this.followRedirects = okHttpClient.followRedirects; 220 this.retryOnConnectionFailure = okHttpClient.retryOnConnectionFailure; 221 this.connectTimeout = okHttpClient.connectTimeout; 222 this.readTimeout = okHttpClient.readTimeout; 223 this.writeTimeout = okHttpClient.writeTimeout; 224 } 225 226 /** 227 * Sets the default connect timeout for new connections. A value of 0 means no timeout, otherwise 228 * values must be between 1 and {@link Integer#MAX_VALUE} when converted to milliseconds. 229 * 230 * @see URLConnection#setConnectTimeout(int) 231 */ 232 public void setConnectTimeout(long timeout, TimeUnit unit) { 233 if (timeout < 0) throw new IllegalArgumentException("timeout < 0"); 234 if (unit == null) throw new IllegalArgumentException("unit == null"); 235 long millis = unit.toMillis(timeout); 236 if (millis > Integer.MAX_VALUE) throw new IllegalArgumentException("Timeout too large."); 237 if (millis == 0 && timeout > 0) throw new IllegalArgumentException("Timeout too small."); 238 connectTimeout = (int) millis; 239 } 240 241 /** Default connect timeout (in milliseconds). */ 242 public int getConnectTimeout() { 243 return connectTimeout; 244 } 245 246 /** 247 * Sets the default read timeout for new connections. A value of 0 means no timeout, otherwise 248 * values must be between 1 and {@link Integer#MAX_VALUE} when converted to milliseconds. 249 * 250 * @see URLConnection#setReadTimeout(int) 251 */ 252 public void setReadTimeout(long timeout, TimeUnit unit) { 253 if (timeout < 0) throw new IllegalArgumentException("timeout < 0"); 254 if (unit == null) throw new IllegalArgumentException("unit == null"); 255 long millis = unit.toMillis(timeout); 256 if (millis > Integer.MAX_VALUE) throw new IllegalArgumentException("Timeout too large."); 257 if (millis == 0 && timeout > 0) throw new IllegalArgumentException("Timeout too small."); 258 readTimeout = (int) millis; 259 } 260 261 /** Default read timeout (in milliseconds). */ 262 public int getReadTimeout() { 263 return readTimeout; 264 } 265 266 /** 267 * Sets the default write timeout for new connections. A value of 0 means no timeout, otherwise 268 * values must be between 1 and {@link Integer#MAX_VALUE} when converted to milliseconds. 269 */ 270 public void setWriteTimeout(long timeout, TimeUnit unit) { 271 if (timeout < 0) throw new IllegalArgumentException("timeout < 0"); 272 if (unit == null) throw new IllegalArgumentException("unit == null"); 273 long millis = unit.toMillis(timeout); 274 if (millis > Integer.MAX_VALUE) throw new IllegalArgumentException("Timeout too large."); 275 if (millis == 0 && timeout > 0) throw new IllegalArgumentException("Timeout too small."); 276 writeTimeout = (int) millis; 277 } 278 279 /** Default write timeout (in milliseconds). */ 280 public int getWriteTimeout() { 281 return writeTimeout; 282 } 283 284 /** 285 * Sets the HTTP proxy that will be used by connections created by this 286 * client. This takes precedence over {@link #setProxySelector}, which is 287 * only honored when this proxy is null (which it is by default). To disable 288 * proxy use completely, call {@code setProxy(Proxy.NO_PROXY)}. 289 */ 290 public OkHttpClient setProxy(Proxy proxy) { 291 this.proxy = proxy; 292 return this; 293 } 294 295 public Proxy getProxy() { 296 return proxy; 297 } 298 299 /** 300 * Sets the proxy selection policy to be used if no {@link #setProxy proxy} 301 * is specified explicitly. The proxy selector may return multiple proxies; 302 * in that case they will be tried in sequence until a successful connection 303 * is established. 304 * 305 * <p>If unset, the {@link ProxySelector#getDefault() system-wide default} 306 * proxy selector will be used. 307 */ 308 public OkHttpClient setProxySelector(ProxySelector proxySelector) { 309 this.proxySelector = proxySelector; 310 return this; 311 } 312 313 public ProxySelector getProxySelector() { 314 return proxySelector; 315 } 316 317 /** 318 * Sets the cookie handler to be used to read outgoing cookies and write 319 * incoming cookies. 320 * 321 * <p>If unset, the {@link CookieHandler#getDefault() system-wide default} 322 * cookie handler will be used. 323 */ 324 public OkHttpClient setCookieHandler(CookieHandler cookieHandler) { 325 this.cookieHandler = cookieHandler; 326 return this; 327 } 328 329 public CookieHandler getCookieHandler() { 330 return cookieHandler; 331 } 332 333 /** Sets the response cache to be used to read and write cached responses. */ 334 void setInternalCache(InternalCache internalCache) { 335 this.internalCache = internalCache; 336 this.cache = null; 337 } 338 339 InternalCache internalCache() { 340 return internalCache; 341 } 342 343 public OkHttpClient setCache(Cache cache) { 344 this.cache = cache; 345 this.internalCache = null; 346 return this; 347 } 348 349 public Cache getCache() { 350 return cache; 351 } 352 353 /** 354 * Sets the socket factory used to create connections. 355 * 356 * <p>If unset, the {@link SocketFactory#getDefault() system-wide default} 357 * socket factory will be used. 358 */ 359 public OkHttpClient setSocketFactory(SocketFactory socketFactory) { 360 this.socketFactory = socketFactory; 361 return this; 362 } 363 364 public SocketFactory getSocketFactory() { 365 return socketFactory; 366 } 367 368 /** 369 * Sets the socket factory used to secure HTTPS connections. 370 * 371 * <p>If unset, a lazily created SSL socket factory will be used. 372 */ 373 public OkHttpClient setSslSocketFactory(SSLSocketFactory sslSocketFactory) { 374 this.sslSocketFactory = sslSocketFactory; 375 return this; 376 } 377 378 public SSLSocketFactory getSslSocketFactory() { 379 return sslSocketFactory; 380 } 381 382 /** 383 * Sets the verifier used to confirm that response certificates apply to 384 * requested hostnames for HTTPS connections. 385 * 386 * <p>If unset, a default hostname verifier will be used. 387 */ 388 public OkHttpClient setHostnameVerifier(HostnameVerifier hostnameVerifier) { 389 this.hostnameVerifier = hostnameVerifier; 390 return this; 391 } 392 393 public HostnameVerifier getHostnameVerifier() { 394 return hostnameVerifier; 395 } 396 397 /** 398 * Sets the certificate pinner that constrains which certificates are trusted. 399 * By default HTTPS connections rely on only the {@link #setSslSocketFactory 400 * SSL socket factory} to establish trust. Pinning certificates avoids the 401 * need to trust certificate authorities. 402 */ 403 public OkHttpClient setCertificatePinner(CertificatePinner certificatePinner) { 404 this.certificatePinner = certificatePinner; 405 return this; 406 } 407 408 public CertificatePinner getCertificatePinner() { 409 return certificatePinner; 410 } 411 412 /** 413 * Sets the authenticator used to respond to challenges from the remote web 414 * server or proxy server. 415 * 416 * <p>If unset, the {@link java.net.Authenticator#setDefault system-wide default} 417 * authenticator will be used. 418 */ 419 public OkHttpClient setAuthenticator(Authenticator authenticator) { 420 this.authenticator = authenticator; 421 return this; 422 } 423 424 public Authenticator getAuthenticator() { 425 return authenticator; 426 } 427 428 /** 429 * Sets the connection pool used to recycle HTTP and HTTPS connections. 430 * 431 * <p>If unset, the {@link ConnectionPool#getDefault() system-wide 432 * default} connection pool will be used. 433 */ 434 public OkHttpClient setConnectionPool(ConnectionPool connectionPool) { 435 this.connectionPool = connectionPool; 436 return this; 437 } 438 439 public ConnectionPool getConnectionPool() { 440 return connectionPool; 441 } 442 443 /** 444 * Configure this client to follow redirects from HTTPS to HTTP and from HTTP 445 * to HTTPS. 446 * 447 * <p>If unset, protocol redirects will be followed. This is different than 448 * the built-in {@code HttpURLConnection}'s default. 449 */ 450 public OkHttpClient setFollowSslRedirects(boolean followProtocolRedirects) { 451 this.followSslRedirects = followProtocolRedirects; 452 return this; 453 } 454 455 public boolean getFollowSslRedirects() { 456 return followSslRedirects; 457 } 458 459 /** Configure this client to follow redirects. If unset, redirects be followed. */ 460 public void setFollowRedirects(boolean followRedirects) { 461 this.followRedirects = followRedirects; 462 } 463 464 public boolean getFollowRedirects() { 465 return followRedirects; 466 } 467 468 /** 469 * Configure this client to retry or not when a connectivity problem is encountered. By default, 470 * this client silently recovers from the following problems: 471 * 472 * <ul> 473 * <li><strong>Unreachable IP addresses.</strong> If the URL's host has multiple IP addresses, 474 * failure to reach any individual IP address doesn't fail the overall request. This can 475 * increase availability of multi-homed services. 476 * <li><strong>Stale pooled connections.</strong> The {@link ConnectionPool} reuses sockets 477 * to decrease request latency, but these connections will occasionally time out. 478 * <li><strong>Unreachable proxy servers.</strong> A {@link ProxySelector} can be used to 479 * attempt multiple proxy servers in sequence, eventually falling back to a direct 480 * connection. 481 * </ul> 482 * 483 * Set this to false to avoid retrying requests when doing so is destructive. In this case the 484 * calling application should do its own recovery of connectivity failures. 485 */ 486 public void setRetryOnConnectionFailure(boolean retryOnConnectionFailure) { 487 this.retryOnConnectionFailure = retryOnConnectionFailure; 488 } 489 490 public boolean getRetryOnConnectionFailure() { 491 return retryOnConnectionFailure; 492 } 493 494 RouteDatabase routeDatabase() { 495 return routeDatabase; 496 } 497 498 /** 499 * Sets the dispatcher used to set policy and execute asynchronous requests. 500 * Must not be null. 501 */ 502 public OkHttpClient setDispatcher(Dispatcher dispatcher) { 503 if (dispatcher == null) throw new IllegalArgumentException("dispatcher == null"); 504 this.dispatcher = dispatcher; 505 return this; 506 } 507 508 public Dispatcher getDispatcher() { 509 return dispatcher; 510 } 511 512 /** 513 * Configure the protocols used by this client to communicate with remote 514 * servers. By default this client will prefer the most efficient transport 515 * available, falling back to more ubiquitous protocols. Applications should 516 * only call this method to avoid specific compatibility problems, such as web 517 * servers that behave incorrectly when SPDY is enabled. 518 * 519 * <p>The following protocols are currently supported: 520 * <ul> 521 * <li><a href="http://www.w3.org/Protocols/rfc2616/rfc2616.html">http/1.1</a> 522 * <li><a href="http://www.chromium.org/spdy/spdy-protocol/spdy-protocol-draft3-1">spdy/3.1</a> 523 * <li><a href="http://tools.ietf.org/html/draft-ietf-httpbis-http2-17">h2</a> 524 * </ul> 525 * 526 * <p><strong>This is an evolving set.</strong> Future releases include 527 * support for transitional protocols. The http/1.1 transport will never be 528 * dropped. 529 * 530 * <p>If multiple protocols are specified, <a 531 * href="http://tools.ietf.org/html/draft-ietf-tls-applayerprotoneg">ALPN</a> 532 * will be used to negotiate a transport. 533 * 534 * <p>{@link Protocol#HTTP_1_0} is not supported in this set. Requests are 535 * initiated with {@code HTTP/1.1} only. If the server responds with {@code 536 * HTTP/1.0}, that will be exposed by {@link Response#protocol()}. 537 * 538 * @param protocols the protocols to use, in order of preference. The list 539 * must contain {@link Protocol#HTTP_1_1}. It must not contain null or 540 * {@link Protocol#HTTP_1_0}. 541 */ 542 public OkHttpClient setProtocols(List<Protocol> protocols) { 543 protocols = Util.immutableList(protocols); 544 if (!protocols.contains(Protocol.HTTP_1_1)) { 545 throw new IllegalArgumentException("protocols doesn't contain http/1.1: " + protocols); 546 } 547 if (protocols.contains(Protocol.HTTP_1_0)) { 548 throw new IllegalArgumentException("protocols must not contain http/1.0: " + protocols); 549 } 550 if (protocols.contains(null)) { 551 throw new IllegalArgumentException("protocols must not contain null"); 552 } 553 this.protocols = Util.immutableList(protocols); 554 return this; 555 } 556 557 public List<Protocol> getProtocols() { 558 return protocols; 559 } 560 561 public OkHttpClient setConnectionSpecs(List<ConnectionSpec> connectionSpecs) { 562 this.connectionSpecs = Util.immutableList(connectionSpecs); 563 return this; 564 } 565 566 public List<ConnectionSpec> getConnectionSpecs() { 567 return connectionSpecs; 568 } 569 570 /** 571 * Returns a modifiable list of interceptors that observe the full span of each call: from before 572 * the connection is established (if any) until after the response source is selected (either the 573 * origin server, cache, or both). 574 */ 575 public List<Interceptor> interceptors() { 576 return interceptors; 577 } 578 579 /** 580 * Returns a modifiable list of interceptors that observe a single network request and response. 581 * These interceptors must call {@link Interceptor.Chain#proceed} exactly once: it is an error for 582 * a network interceptor to short-circuit or repeat a network request. 583 */ 584 public List<Interceptor> networkInterceptors() { 585 return networkInterceptors; 586 } 587 588 /** 589 * Prepares the {@code request} to be executed at some point in the future. 590 */ 591 public Call newCall(Request request) { 592 return new Call(this, request); 593 } 594 595 /** 596 * Cancels all scheduled or in-flight calls tagged with {@code tag}. Requests 597 * that are already complete cannot be canceled. 598 */ 599 public OkHttpClient cancel(Object tag) { 600 getDispatcher().cancel(tag); 601 return this; 602 } 603 604 /** 605 * Returns a shallow copy of this OkHttpClient that uses the system-wide 606 * default for each field that hasn't been explicitly configured. 607 */ 608 OkHttpClient copyWithDefaults() { 609 OkHttpClient result = new OkHttpClient(this); 610 if (result.proxySelector == null) { 611 result.proxySelector = ProxySelector.getDefault(); 612 } 613 if (result.cookieHandler == null) { 614 result.cookieHandler = CookieHandler.getDefault(); 615 } 616 if (result.socketFactory == null) { 617 result.socketFactory = SocketFactory.getDefault(); 618 } 619 if (result.sslSocketFactory == null) { 620 result.sslSocketFactory = getDefaultSSLSocketFactory(); 621 } 622 if (result.hostnameVerifier == null) { 623 result.hostnameVerifier = OkHostnameVerifier.INSTANCE; 624 } 625 if (result.certificatePinner == null) { 626 result.certificatePinner = CertificatePinner.DEFAULT; 627 } 628 if (result.authenticator == null) { 629 result.authenticator = AuthenticatorAdapter.INSTANCE; 630 } 631 if (result.connectionPool == null) { 632 result.connectionPool = ConnectionPool.getDefault(); 633 } 634 if (result.protocols == null) { 635 result.protocols = DEFAULT_PROTOCOLS; 636 } 637 if (result.connectionSpecs == null) { 638 result.connectionSpecs = DEFAULT_CONNECTION_SPECS; 639 } 640 if (result.network == null) { 641 result.network = Network.DEFAULT; 642 } 643 return result; 644 } 645 646 /** 647 * Java and Android programs default to using a single global SSL context, 648 * accessible to HTTP clients as {@link SSLSocketFactory#getDefault()}. If we 649 * used the shared SSL context, when OkHttp enables ALPN for its SPDY-related 650 * stuff, it would also enable ALPN for other usages, which might crash them 651 * because ALPN is enabled when it isn't expected to be. 652 * 653 * <p>This code avoids that by defaulting to an OkHttp-created SSL context. 654 * The drawback of this approach is that apps that customize the global SSL 655 * context will lose these customizations. 656 */ 657 private synchronized SSLSocketFactory getDefaultSSLSocketFactory() { 658 if (defaultSslSocketFactory == null) { 659 try { 660 SSLContext sslContext = SSLContext.getInstance("TLS"); 661 sslContext.init(null, null, null); 662 defaultSslSocketFactory = sslContext.getSocketFactory(); 663 } catch (GeneralSecurityException e) { 664 throw new AssertionError(); // The system has no TLS. Just give up. 665 } 666 } 667 return defaultSslSocketFactory; 668 } 669 670 /** Returns a shallow copy of this OkHttpClient. */ 671 @Override public OkHttpClient clone() { 672 return new OkHttpClient(this); 673 } 674 } 675