All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.facebook.presto.jdbc.internal.okhttp3.OkHttpClient Maven / Gradle / Ivy

The newest version!
/*
 * 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.facebook.presto.jdbc.internal.okhttp3;

import java.net.MalformedURLException;
import java.net.Proxy;
import java.net.ProxySelector;
import java.net.Socket;
import java.net.UnknownHostException;
import java.security.GeneralSecurityException;
import java.security.KeyStore;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;
import java.util.Random;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.TimeUnit;
import com.facebook.presto.jdbc.internal.javax.annotation.Nullable;
import javax.net.SocketFactory;
import javax.net.ssl.HostnameVerifier;
import javax.net.ssl.SSLContext;
import javax.net.ssl.SSLSocket;
import javax.net.ssl.SSLSocketFactory;
import javax.net.ssl.TrustManager;
import javax.net.ssl.TrustManagerFactory;
import javax.net.ssl.X509TrustManager;
import com.facebook.presto.jdbc.internal.okhttp3.internal.Internal;
import com.facebook.presto.jdbc.internal.okhttp3.internal.Util;
import com.facebook.presto.jdbc.internal.okhttp3.internal.cache.InternalCache;
import com.facebook.presto.jdbc.internal.okhttp3.internal.connection.RealConnection;
import com.facebook.presto.jdbc.internal.okhttp3.internal.connection.RouteDatabase;
import com.facebook.presto.jdbc.internal.okhttp3.internal.connection.StreamAllocation;
import com.facebook.presto.jdbc.internal.okhttp3.internal.platform.Platform;
import com.facebook.presto.jdbc.internal.okhttp3.internal.tls.CertificateChainCleaner;
import com.facebook.presto.jdbc.internal.okhttp3.internal.tls.OkHostnameVerifier;
import com.facebook.presto.jdbc.internal.okhttp3.internal.ws.RealWebSocket;

import static com.facebook.presto.jdbc.internal.okhttp3.internal.Util.assertionError;
import static com.facebook.presto.jdbc.internal.okhttp3.internal.Util.checkDuration;

/**
 * Factory for {@linkplain Call calls}, which can be used to send HTTP requests and read their
 * responses.
 *
 * 

OkHttpClients should be shared

* *

OkHttp performs best when you create a single {@code OkHttpClient} instance and reuse it for * all of your HTTP calls. This is because each client holds its own connection pool and thread * pools. Reusing connections and threads reduces latency and saves memory. Conversely, creating a * client for each request wastes resources on idle pools. * *

Use {@code new OkHttpClient()} to create a shared instance with the default settings: *

   {@code
 *
 *   // The singleton HTTP client.
 *   public final OkHttpClient client = new OkHttpClient();
 * }
* *

Or use {@code new OkHttpClient.Builder()} to create a shared instance with custom settings: *

   {@code
 *
 *   // The singleton HTTP client.
 *   public final OkHttpClient client = new OkHttpClient.Builder()
 *       .addInterceptor(new HttpLoggingInterceptor())
 *       .cache(new Cache(cacheDir, cacheSize))
 *       .build();
 * }
* *

Customize your client with newBuilder()

* *

You can customize a shared OkHttpClient instance with {@link #newBuilder()}. This builds a * client that shares the same connection pool, thread pools, and configuration. Use the builder * methods to configure the derived client for a specific purpose. * *

This example shows a call with a short 500 millisecond timeout:

   {@code
 *
 *   OkHttpClient eagerClient = client.newBuilder()
 *       .readTimeout(500, TimeUnit.MILLISECONDS)
 *       .build();
 *   Response response = eagerClient.newCall(request).execute();
 * }
* *

Shutdown isn't necessary

* *

The threads and connections that are held will be released automatically if they remain idle. * But if you are writing a application that needs to aggressively release unused resources you may * do so. * *

Shutdown the dispatcher's executor service with {@link ExecutorService#shutdown shutdown()}. * This will also cause future calls to the client to be rejected.

   {@code
 *
 *     client.dispatcher().executorService().shutdown();
 * }
* *

Clear the connection pool with {@link ConnectionPool#evictAll() evictAll()}. Note that the * connection pool's daemon thread may not exit immediately.

   {@code
 *
 *     client.connectionPool().evictAll();
 * }
* *

If your client has a cache, call {@link Cache#close close()}. Note that it is an error to * create calls against a cache that is closed, and doing so will cause the call to crash. *

   {@code
 *
 *     client.cache().close();
 * }
* *

OkHttp also uses daemon threads for HTTP/2 connections. These will exit automatically if they * remain idle. */ public class OkHttpClient implements Cloneable, Call.Factory, WebSocket.Factory { static final List DEFAULT_PROTOCOLS = Util.immutableList( Protocol.HTTP_2, Protocol.HTTP_1_1); static final List DEFAULT_CONNECTION_SPECS = Util.immutableList( ConnectionSpec.MODERN_TLS, ConnectionSpec.CLEARTEXT); static { Internal.instance = new Internal() { @Override public void addLenient(Headers.Builder builder, String line) { builder.addLenient(line); } @Override public void addLenient(Headers.Builder builder, String name, String value) { builder.addLenient(name, value); } @Override public void setCache(OkHttpClient.Builder builder, InternalCache internalCache) { builder.setInternalCache(internalCache); } @Override public boolean connectionBecameIdle( ConnectionPool pool, RealConnection connection) { return pool.connectionBecameIdle(connection); } @Override public RealConnection get(ConnectionPool pool, Address address, StreamAllocation streamAllocation, Route route) { return pool.get(address, streamAllocation, route); } @Override public boolean equalsNonHost(Address a, Address b) { return a.equalsNonHost(b); } @Override public Socket deduplicate( ConnectionPool pool, Address address, StreamAllocation streamAllocation) { return pool.deduplicate(address, streamAllocation); } @Override public void put(ConnectionPool pool, RealConnection connection) { pool.put(connection); } @Override public RouteDatabase routeDatabase(ConnectionPool connectionPool) { return connectionPool.routeDatabase; } @Override public int code(Response.Builder responseBuilder) { return responseBuilder.code; } @Override public void apply(ConnectionSpec tlsConfiguration, SSLSocket sslSocket, boolean isFallback) { tlsConfiguration.apply(sslSocket, isFallback); } @Override public HttpUrl getHttpUrlChecked(String url) throws MalformedURLException, UnknownHostException { return HttpUrl.getChecked(url); } @Override public StreamAllocation streamAllocation(Call call) { return ((RealCall) call).streamAllocation(); } @Override public Call newWebSocketCall(OkHttpClient client, Request originalRequest) { return RealCall.newRealCall(client, originalRequest, true); } }; } final Dispatcher dispatcher; final @Nullable Proxy proxy; final List protocols; final List connectionSpecs; final List interceptors; final List networkInterceptors; final EventListener.Factory eventListenerFactory; final ProxySelector proxySelector; final CookieJar cookieJar; final @Nullable Cache cache; final @Nullable InternalCache internalCache; final SocketFactory socketFactory; final @Nullable SSLSocketFactory sslSocketFactory; final @Nullable CertificateChainCleaner certificateChainCleaner; final HostnameVerifier hostnameVerifier; final CertificatePinner certificatePinner; final Authenticator proxyAuthenticator; final Authenticator authenticator; final ConnectionPool connectionPool; final Dns dns; final boolean followSslRedirects; final boolean followRedirects; final boolean retryOnConnectionFailure; final int connectTimeout; final int readTimeout; final int writeTimeout; final int pingInterval; public OkHttpClient() { this(new Builder()); } OkHttpClient(Builder builder) { this.dispatcher = builder.dispatcher; this.proxy = builder.proxy; this.protocols = builder.protocols; this.connectionSpecs = builder.connectionSpecs; this.interceptors = Util.immutableList(builder.interceptors); this.networkInterceptors = Util.immutableList(builder.networkInterceptors); this.eventListenerFactory = builder.eventListenerFactory; this.proxySelector = builder.proxySelector; this.cookieJar = builder.cookieJar; this.cache = builder.cache; this.internalCache = builder.internalCache; this.socketFactory = builder.socketFactory; boolean isTLS = false; for (ConnectionSpec spec : connectionSpecs) { isTLS = isTLS || spec.isTls(); } if (builder.sslSocketFactory != null || !isTLS) { this.sslSocketFactory = builder.sslSocketFactory; this.certificateChainCleaner = builder.certificateChainCleaner; } else { X509TrustManager trustManager = systemDefaultTrustManager(); this.sslSocketFactory = systemDefaultSslSocketFactory(trustManager); this.certificateChainCleaner = CertificateChainCleaner.get(trustManager); } this.hostnameVerifier = builder.hostnameVerifier; this.certificatePinner = builder.certificatePinner.withCertificateChainCleaner( certificateChainCleaner); this.proxyAuthenticator = builder.proxyAuthenticator; this.authenticator = builder.authenticator; this.connectionPool = builder.connectionPool; this.dns = builder.dns; this.followSslRedirects = builder.followSslRedirects; this.followRedirects = builder.followRedirects; this.retryOnConnectionFailure = builder.retryOnConnectionFailure; this.connectTimeout = builder.connectTimeout; this.readTimeout = builder.readTimeout; this.writeTimeout = builder.writeTimeout; this.pingInterval = builder.pingInterval; if (interceptors.contains(null)) { throw new IllegalStateException("Null interceptor: " + interceptors); } if (networkInterceptors.contains(null)) { throw new IllegalStateException("Null network interceptor: " + networkInterceptors); } } private X509TrustManager systemDefaultTrustManager() { try { TrustManagerFactory trustManagerFactory = TrustManagerFactory.getInstance( TrustManagerFactory.getDefaultAlgorithm()); trustManagerFactory.init((KeyStore) null); TrustManager[] trustManagers = trustManagerFactory.getTrustManagers(); if (trustManagers.length != 1 || !(trustManagers[0] instanceof X509TrustManager)) { throw new IllegalStateException("Unexpected default trust managers:" + Arrays.toString(trustManagers)); } return (X509TrustManager) trustManagers[0]; } catch (GeneralSecurityException e) { throw assertionError("No System TLS", e); // The system has no TLS. Just give up. } } private SSLSocketFactory systemDefaultSslSocketFactory(X509TrustManager trustManager) { try { SSLContext sslContext = SSLContext.getInstance("TLS"); sslContext.init(null, new TrustManager[] { trustManager }, null); return sslContext.getSocketFactory(); } catch (GeneralSecurityException e) { throw assertionError("No System TLS", e); // The system has no TLS. Just give up. } } /** Default connect timeout (in milliseconds). */ public int connectTimeoutMillis() { return connectTimeout; } /** Default read timeout (in milliseconds). */ public int readTimeoutMillis() { return readTimeout; } /** Default write timeout (in milliseconds). */ public int writeTimeoutMillis() { return writeTimeout; } /** Web socket ping interval (in milliseconds). */ public int pingIntervalMillis() { return pingInterval; } public Proxy proxy() { return proxy; } public ProxySelector proxySelector() { return proxySelector; } public CookieJar cookieJar() { return cookieJar; } public Cache cache() { return cache; } InternalCache internalCache() { return cache != null ? cache.internalCache : internalCache; } public Dns dns() { return dns; } public SocketFactory socketFactory() { return socketFactory; } public SSLSocketFactory sslSocketFactory() { return sslSocketFactory; } public HostnameVerifier hostnameVerifier() { return hostnameVerifier; } public CertificatePinner certificatePinner() { return certificatePinner; } public Authenticator authenticator() { return authenticator; } public Authenticator proxyAuthenticator() { return proxyAuthenticator; } public ConnectionPool connectionPool() { return connectionPool; } public boolean followSslRedirects() { return followSslRedirects; } public boolean followRedirects() { return followRedirects; } public boolean retryOnConnectionFailure() { return retryOnConnectionFailure; } public Dispatcher dispatcher() { return dispatcher; } public List protocols() { return protocols; } public List connectionSpecs() { return connectionSpecs; } /** * Returns an immutable list of interceptors that observe the full span of each call: from before * the connection is established (if any) until after the response source is selected (either the * origin server, cache, or both). */ public List interceptors() { return interceptors; } /** * Returns an immutable list of interceptors that observe a single network request and response. * These interceptors must call {@link Interceptor.Chain#proceed} exactly once: it is an error for * a network interceptor to short-circuit or repeat a network request. */ public List networkInterceptors() { return networkInterceptors; } public EventListener.Factory eventListenerFactory() { return eventListenerFactory; } /** * Prepares the {@code request} to be executed at some point in the future. */ @Override public Call newCall(Request request) { return RealCall.newRealCall(this, request, false /* for web socket */); } /** * Uses {@code request} to connect a new web socket. */ @Override public WebSocket newWebSocket(Request request, WebSocketListener listener) { RealWebSocket webSocket = new RealWebSocket(request, listener, new Random()); webSocket.connect(this); return webSocket; } public Builder newBuilder() { return new Builder(this); } public static final class Builder { Dispatcher dispatcher; @Nullable Proxy proxy; List protocols; List connectionSpecs; final List interceptors = new ArrayList<>(); final List networkInterceptors = new ArrayList<>(); EventListener.Factory eventListenerFactory; ProxySelector proxySelector; CookieJar cookieJar; @Nullable Cache cache; @Nullable InternalCache internalCache; SocketFactory socketFactory; @Nullable SSLSocketFactory sslSocketFactory; @Nullable CertificateChainCleaner certificateChainCleaner; HostnameVerifier hostnameVerifier; CertificatePinner certificatePinner; Authenticator proxyAuthenticator; Authenticator authenticator; ConnectionPool connectionPool; Dns dns; boolean followSslRedirects; boolean followRedirects; boolean retryOnConnectionFailure; int connectTimeout; int readTimeout; int writeTimeout; int pingInterval; public Builder() { dispatcher = new Dispatcher(); protocols = DEFAULT_PROTOCOLS; connectionSpecs = DEFAULT_CONNECTION_SPECS; eventListenerFactory = EventListener.factory(EventListener.NONE); proxySelector = ProxySelector.getDefault(); cookieJar = CookieJar.NO_COOKIES; socketFactory = SocketFactory.getDefault(); hostnameVerifier = OkHostnameVerifier.INSTANCE; certificatePinner = CertificatePinner.DEFAULT; proxyAuthenticator = Authenticator.NONE; authenticator = Authenticator.NONE; connectionPool = new ConnectionPool(); dns = Dns.SYSTEM; followSslRedirects = true; followRedirects = true; retryOnConnectionFailure = true; connectTimeout = 10_000; readTimeout = 10_000; writeTimeout = 10_000; pingInterval = 0; } Builder(OkHttpClient okHttpClient) { this.dispatcher = okHttpClient.dispatcher; this.proxy = okHttpClient.proxy; this.protocols = okHttpClient.protocols; this.connectionSpecs = okHttpClient.connectionSpecs; this.interceptors.addAll(okHttpClient.interceptors); this.networkInterceptors.addAll(okHttpClient.networkInterceptors); this.eventListenerFactory = okHttpClient.eventListenerFactory; this.proxySelector = okHttpClient.proxySelector; this.cookieJar = okHttpClient.cookieJar; this.internalCache = okHttpClient.internalCache; this.cache = okHttpClient.cache; this.socketFactory = okHttpClient.socketFactory; this.sslSocketFactory = okHttpClient.sslSocketFactory; this.certificateChainCleaner = okHttpClient.certificateChainCleaner; this.hostnameVerifier = okHttpClient.hostnameVerifier; this.certificatePinner = okHttpClient.certificatePinner; this.proxyAuthenticator = okHttpClient.proxyAuthenticator; this.authenticator = okHttpClient.authenticator; this.connectionPool = okHttpClient.connectionPool; this.dns = okHttpClient.dns; this.followSslRedirects = okHttpClient.followSslRedirects; this.followRedirects = okHttpClient.followRedirects; this.retryOnConnectionFailure = okHttpClient.retryOnConnectionFailure; this.connectTimeout = okHttpClient.connectTimeout; this.readTimeout = okHttpClient.readTimeout; this.writeTimeout = okHttpClient.writeTimeout; this.pingInterval = okHttpClient.pingInterval; } /** * Sets the default connect timeout for new connections. A value of 0 means no timeout, * otherwise values must be between 1 and {@link Integer#MAX_VALUE} when converted to * milliseconds. */ public Builder connectTimeout(long timeout, TimeUnit unit) { connectTimeout = checkDuration("timeout", timeout, unit); return this; } /** * Sets the default read timeout for new connections. A value of 0 means no timeout, otherwise * values must be between 1 and {@link Integer#MAX_VALUE} when converted to milliseconds. */ public Builder readTimeout(long timeout, TimeUnit unit) { readTimeout = checkDuration("timeout", timeout, unit); return this; } /** * Sets the default write timeout for new connections. A value of 0 means no timeout, otherwise * values must be between 1 and {@link Integer#MAX_VALUE} when converted to milliseconds. */ public Builder writeTimeout(long timeout, TimeUnit unit) { writeTimeout = checkDuration("timeout", timeout, unit); return this; } /** * Sets the interval between web socket pings initiated by this client. Use this to * automatically send web socket ping frames until either the web socket fails or it is closed. * This keeps the connection alive and may detect connectivity failures early. No timeouts are * enforced on the acknowledging pongs. * *

The default value of 0 disables client-initiated pings. */ public Builder pingInterval(long interval, TimeUnit unit) { pingInterval = checkDuration("interval", interval, unit); return this; } /** * Sets the HTTP proxy that will be used by connections created by this client. This takes * precedence over {@link #proxySelector}, 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 Builder proxy(@Nullable Proxy proxy) { this.proxy = proxy; return this; } /** * Sets the proxy selection policy to be used if no {@link #proxy 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. * *

If unset, the {@link ProxySelector#getDefault() system-wide default} proxy selector will * be used. */ public Builder proxySelector(ProxySelector proxySelector) { this.proxySelector = proxySelector; return this; } /** * Sets the handler that can accept cookies from incoming HTTP responses and provides cookies to * outgoing HTTP requests. * *

If unset, {@linkplain CookieJar#NO_COOKIES no cookies} will be accepted nor provided. */ public Builder cookieJar(CookieJar cookieJar) { if (cookieJar == null) throw new NullPointerException("cookieJar == null"); this.cookieJar = cookieJar; return this; } /** Sets the response cache to be used to read and write cached responses. */ void setInternalCache(@Nullable InternalCache internalCache) { this.internalCache = internalCache; this.cache = null; } /** Sets the response cache to be used to read and write cached responses. */ public Builder cache(@Nullable Cache cache) { this.cache = cache; this.internalCache = null; return this; } /** * Sets the DNS service used to lookup IP addresses for hostnames. * *

If unset, the {@link Dns#SYSTEM system-wide default} DNS will be used. */ public Builder dns(Dns dns) { if (dns == null) throw new NullPointerException("dns == null"); this.dns = dns; return this; } /** * Sets the socket factory used to create connections. OkHttp only uses the parameterless {@link * SocketFactory#createSocket() createSocket()} method to create unconnected sockets. Overriding * this method, e. g., allows the socket to be bound to a specific local address. * *

If unset, the {@link SocketFactory#getDefault() system-wide default} socket factory will * be used. */ public Builder socketFactory(SocketFactory socketFactory) { if (socketFactory == null) throw new NullPointerException("socketFactory == null"); this.socketFactory = socketFactory; return this; } /** * Sets the socket factory used to secure HTTPS connections. If unset, the system default will * be used. * * @deprecated {@code SSLSocketFactory} does not expose its {@link X509TrustManager}, which is * a field that OkHttp needs to build a clean certificate chain. This method instead must * use reflection to extract the trust manager. Applications should prefer to call {@link * #sslSocketFactory(SSLSocketFactory, X509TrustManager)}, which avoids such reflection. */ public Builder sslSocketFactory(SSLSocketFactory sslSocketFactory) { if (sslSocketFactory == null) throw new NullPointerException("sslSocketFactory == null"); X509TrustManager trustManager = Platform.get().trustManager(sslSocketFactory); if (trustManager == null) { throw new IllegalStateException("Unable to extract the trust manager on " + Platform.get() + ", sslSocketFactory is " + sslSocketFactory.getClass()); } this.sslSocketFactory = sslSocketFactory; this.certificateChainCleaner = CertificateChainCleaner.get(trustManager); return this; } /** * Sets the socket factory and trust manager used to secure HTTPS connections. If unset, the * system defaults will be used. * *

Most applications should not call this method, and instead use the system defaults. Those * classes include special optimizations that can be lost if the implementations are decorated. * *

If necessary, you can create and configure the defaults yourself with the following code: * *

   {@code
     *
     *   TrustManagerFactory trustManagerFactory = TrustManagerFactory.getInstance(
     *       TrustManagerFactory.getDefaultAlgorithm());
     *   trustManagerFactory.init((KeyStore) null);
     *   TrustManager[] trustManagers = trustManagerFactory.getTrustManagers();
     *   if (trustManagers.length != 1 || !(trustManagers[0] instanceof X509TrustManager)) {
     *     throw new IllegalStateException("Unexpected default trust managers:"
     *         + Arrays.toString(trustManagers));
     *   }
     *   X509TrustManager trustManager = (X509TrustManager) trustManagers[0];
     *
     *   SSLContext sslContext = SSLContext.getInstance("TLS");
     *   sslContext.init(null, new TrustManager[] { trustManager }, null);
     *   SSLSocketFactory sslSocketFactory = sslContext.getSocketFactory();
     *
     *   OkHttpClient client = new OkHttpClient.Builder()
     *       .sslSocketFactory(sslSocketFactory, trustManager);
     *       .build();
     * }
*/ public Builder sslSocketFactory( SSLSocketFactory sslSocketFactory, X509TrustManager trustManager) { if (sslSocketFactory == null) throw new NullPointerException("sslSocketFactory == null"); if (trustManager == null) throw new NullPointerException("trustManager == null"); this.sslSocketFactory = sslSocketFactory; this.certificateChainCleaner = CertificateChainCleaner.get(trustManager); return this; } /** * Sets the verifier used to confirm that response certificates apply to requested hostnames for * HTTPS connections. * *

If unset, a default hostname verifier will be used. */ public Builder hostnameVerifier(HostnameVerifier hostnameVerifier) { if (hostnameVerifier == null) throw new NullPointerException("hostnameVerifier == null"); this.hostnameVerifier = hostnameVerifier; return this; } /** * Sets the certificate pinner that constrains which certificates are trusted. By default HTTPS * connections rely on only the {@link #sslSocketFactory SSL socket factory} to establish trust. * Pinning certificates avoids the need to trust certificate authorities. */ public Builder certificatePinner(CertificatePinner certificatePinner) { if (certificatePinner == null) throw new NullPointerException("certificatePinner == null"); this.certificatePinner = certificatePinner; return this; } /** * Sets the authenticator used to respond to challenges from origin servers. Use {@link * #proxyAuthenticator} to set the authenticator for proxy servers. * *

If unset, the {@linkplain Authenticator#NONE no authentication will be attempted}. */ public Builder authenticator(Authenticator authenticator) { if (authenticator == null) throw new NullPointerException("authenticator == null"); this.authenticator = authenticator; return this; } /** * Sets the authenticator used to respond to challenges from proxy servers. Use {@link * #authenticator} to set the authenticator for origin servers. * *

If unset, the {@linkplain Authenticator#NONE no authentication will be attempted}. */ public Builder proxyAuthenticator(Authenticator proxyAuthenticator) { if (proxyAuthenticator == null) throw new NullPointerException("proxyAuthenticator == null"); this.proxyAuthenticator = proxyAuthenticator; return this; } /** * Sets the connection pool used to recycle HTTP and HTTPS connections. * *

If unset, a new connection pool will be used. */ public Builder connectionPool(ConnectionPool connectionPool) { if (connectionPool == null) throw new NullPointerException("connectionPool == null"); this.connectionPool = connectionPool; return this; } /** * Configure this client to follow redirects from HTTPS to HTTP and from HTTP to HTTPS. * *

If unset, protocol redirects will be followed. This is different than the built-in {@code * HttpURLConnection}'s default. */ public Builder followSslRedirects(boolean followProtocolRedirects) { this.followSslRedirects = followProtocolRedirects; return this; } /** Configure this client to follow redirects. If unset, redirects will be followed. */ public Builder followRedirects(boolean followRedirects) { this.followRedirects = followRedirects; return this; } /** * Configure this client to retry or not when a connectivity problem is encountered. By default, * this client silently recovers from the following problems: * *

    *
  • Unreachable IP addresses. If the URL's host has multiple IP addresses, * failure to reach any individual IP address doesn't fail the overall request. This can * increase availability of multi-homed services. *
  • Stale pooled connections. The {@link ConnectionPool} reuses sockets * to decrease request latency, but these connections will occasionally time out. *
  • Unreachable proxy servers. A {@link ProxySelector} can be used to * attempt multiple proxy servers in sequence, eventually falling back to a direct * connection. *
* * Set this to false to avoid retrying requests when doing so is destructive. In this case the * calling application should do its own recovery of connectivity failures. */ public Builder retryOnConnectionFailure(boolean retryOnConnectionFailure) { this.retryOnConnectionFailure = retryOnConnectionFailure; return this; } /** * Sets the dispatcher used to set policy and execute asynchronous requests. Must not be null. */ public Builder dispatcher(Dispatcher dispatcher) { if (dispatcher == null) throw new IllegalArgumentException("dispatcher == null"); this.dispatcher = dispatcher; return this; } /** * Configure the protocols 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 protocols. Applications should only call this method to avoid specific * compatibility problems, such as web servers that behave incorrectly when HTTP/2 is enabled. * *

The following protocols are currently supported: * *

* *

This is an evolving set. Future releases include support for transitional * protocols. The http/1.1 transport will never be dropped. * *

If multiple protocols are specified, ALPN will be used to * negotiate a transport. * *

{@link Protocol#HTTP_1_0} is not supported in this set. Requests are initiated with {@code * HTTP/1.1} only. If the server responds with {@code HTTP/1.0}, that will be exposed by {@link * Response#protocol()}. * * @param protocols the protocols to use, in order of preference. The list must contain {@link * Protocol#HTTP_1_1}. It must not contain null or {@link Protocol#HTTP_1_0}. */ public Builder protocols(List protocols) { // Create a private copy of the list. protocols = new ArrayList<>(protocols); // Validate that the list has everything we require and nothing we forbid. if (!protocols.contains(Protocol.HTTP_1_1)) { throw new IllegalArgumentException("protocols doesn't contain http/1.1: " + protocols); } if (protocols.contains(Protocol.HTTP_1_0)) { throw new IllegalArgumentException("protocols must not contain http/1.0: " + protocols); } if (protocols.contains(null)) { throw new IllegalArgumentException("protocols must not contain null"); } // Remove protocols that we no longer support. protocols.remove(Protocol.SPDY_3); // Assign as an unmodifiable list. This is effectively immutable. this.protocols = Collections.unmodifiableList(protocols); return this; } public Builder connectionSpecs(List connectionSpecs) { this.connectionSpecs = Util.immutableList(connectionSpecs); return this; } /** * Returns a modifiable list of interceptors that observe the full span of each call: from * before the connection is established (if any) until after the response source is selected * (either the origin server, cache, or both). */ public List interceptors() { return interceptors; } public Builder addInterceptor(Interceptor interceptor) { if (interceptor == null) throw new IllegalArgumentException("interceptor == null"); interceptors.add(interceptor); return this; } /** * Returns a modifiable list of interceptors that observe a single network request and response. * These interceptors must call {@link Interceptor.Chain#proceed} exactly once: it is an error * for a network interceptor to short-circuit or repeat a network request. */ public List networkInterceptors() { return networkInterceptors; } public Builder addNetworkInterceptor(Interceptor interceptor) { if (interceptor == null) throw new IllegalArgumentException("interceptor == null"); networkInterceptors.add(interceptor); return this; } /** * Configure a single client scoped listener that will receive all analytic events * for this client. * * @see EventListener for semantics and restrictions on listener implementations. */ public Builder eventListener(EventListener eventListener) { if (eventListener == null) throw new NullPointerException("eventListener == null"); this.eventListenerFactory = EventListener.factory(eventListener); return this; } /** * Configure a factory to provide per-call scoped listeners that will receive analytic events * for this client. * * @see EventListener for semantics and restrictions on listener implementations. */ public Builder eventListenerFactory(EventListener.Factory eventListenerFactory) { if (eventListenerFactory == null) { throw new NullPointerException("eventListenerFactory == null"); } this.eventListenerFactory = eventListenerFactory; return this; } public OkHttpClient build() { return new OkHttpClient(this); } } }





© 2015 - 2024 Weber Informatics LLC | Privacy Policy