| /* |
| * ==================================================================== |
| * Licensed to the Apache Software Foundation (ASF) under one |
| * or more contributor license agreements. See the NOTICE file |
| * distributed with this work for additional information |
| * regarding copyright ownership. The ASF licenses this file |
| * to you 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. |
| * ==================================================================== |
| * |
| * This software consists of voluntary contributions made by many |
| * individuals on behalf of the Apache Software Foundation. For more |
| * information on the Apache Software Foundation, please see |
| * <http://www.apache.org/>. |
| * |
| */ |
| |
| package org.apache.hc.client5.http.impl.async; |
| |
| import java.io.Closeable; |
| import java.io.IOException; |
| import java.net.ProxySelector; |
| import java.util.ArrayList; |
| import java.util.Collection; |
| import java.util.LinkedList; |
| import java.util.List; |
| import java.util.concurrent.ThreadFactory; |
| |
| import org.apache.hc.client5.http.ConnectionKeepAliveStrategy; |
| import org.apache.hc.client5.http.SchemePortResolver; |
| import org.apache.hc.client5.http.SystemDefaultDnsResolver; |
| import org.apache.hc.client5.http.async.AsyncExecChainHandler; |
| import org.apache.hc.client5.http.auth.AuthSchemeProvider; |
| import org.apache.hc.client5.http.auth.CredentialsProvider; |
| import org.apache.hc.client5.http.config.AuthSchemes; |
| import org.apache.hc.client5.http.config.RequestConfig; |
| import org.apache.hc.client5.http.cookie.BasicCookieStore; |
| import org.apache.hc.client5.http.cookie.CookieSpecProvider; |
| import org.apache.hc.client5.http.cookie.CookieStore; |
| import org.apache.hc.client5.http.impl.DefaultConnectionKeepAliveStrategy; |
| import org.apache.hc.client5.http.impl.DefaultSchemePortResolver; |
| import org.apache.hc.client5.http.impl.DefaultUserTokenHandler; |
| import org.apache.hc.client5.http.impl.IdleConnectionEvictor; |
| import org.apache.hc.client5.http.impl.NamedElementChain; |
| import org.apache.hc.client5.http.impl.NoopUserTokenHandler; |
| import org.apache.hc.client5.http.impl.auth.BasicSchemeFactory; |
| import org.apache.hc.client5.http.impl.auth.CredSspSchemeFactory; |
| import org.apache.hc.client5.http.impl.auth.DigestSchemeFactory; |
| import org.apache.hc.client5.http.impl.auth.KerberosSchemeFactory; |
| import org.apache.hc.client5.http.impl.auth.NTLMSchemeFactory; |
| import org.apache.hc.client5.http.impl.auth.SPNegoSchemeFactory; |
| import org.apache.hc.client5.http.impl.auth.SystemDefaultCredentialsProvider; |
| import org.apache.hc.client5.http.impl.nio.PoolingAsyncClientConnectionManagerBuilder; |
| import org.apache.hc.client5.http.impl.protocol.DefaultAuthenticationStrategy; |
| import org.apache.hc.client5.http.impl.protocol.DefaultRedirectStrategy; |
| import org.apache.hc.client5.http.impl.routing.DefaultProxyRoutePlanner; |
| import org.apache.hc.client5.http.impl.routing.DefaultRoutePlanner; |
| import org.apache.hc.client5.http.impl.routing.SystemDefaultRoutePlanner; |
| import org.apache.hc.client5.http.impl.sync.BasicCredentialsProvider; |
| import org.apache.hc.client5.http.impl.sync.ChainElements; |
| import org.apache.hc.client5.http.impl.sync.CookieSpecRegistries; |
| import org.apache.hc.client5.http.impl.sync.DefaultHttpRequestRetryHandler; |
| import org.apache.hc.client5.http.nio.AsyncClientConnectionManager; |
| import org.apache.hc.client5.http.protocol.AuthenticationStrategy; |
| import org.apache.hc.client5.http.protocol.RedirectStrategy; |
| import org.apache.hc.client5.http.protocol.RequestAddCookies; |
| import org.apache.hc.client5.http.protocol.RequestAuthCache; |
| import org.apache.hc.client5.http.protocol.RequestDefaultHeaders; |
| import org.apache.hc.client5.http.protocol.RequestExpectContinue; |
| import org.apache.hc.client5.http.protocol.ResponseProcessCookies; |
| import org.apache.hc.client5.http.protocol.UserTokenHandler; |
| import org.apache.hc.client5.http.routing.HttpRoutePlanner; |
| import org.apache.hc.client5.http.sync.HttpRequestRetryHandler; |
| import org.apache.hc.core5.annotation.Internal; |
| import org.apache.hc.core5.concurrent.DefaultThreadFactory; |
| import org.apache.hc.core5.function.Callback; |
| import org.apache.hc.core5.http.ConnectionReuseStrategy; |
| import org.apache.hc.core5.http.Header; |
| import org.apache.hc.core5.http.HttpException; |
| import org.apache.hc.core5.http.HttpHost; |
| import org.apache.hc.core5.http.HttpRequest; |
| import org.apache.hc.core5.http.HttpRequestInterceptor; |
| import org.apache.hc.core5.http.HttpResponse; |
| import org.apache.hc.core5.http.HttpResponseInterceptor; |
| import org.apache.hc.core5.http.config.CharCodingConfig; |
| import org.apache.hc.core5.http.config.H1Config; |
| import org.apache.hc.core5.http.config.Lookup; |
| import org.apache.hc.core5.http.config.RegistryBuilder; |
| import org.apache.hc.core5.http.impl.DefaultConnectionReuseStrategy; |
| import org.apache.hc.core5.http.nio.AsyncPushConsumer; |
| import org.apache.hc.core5.http.nio.HandlerFactory; |
| import org.apache.hc.core5.http.nio.command.ShutdownCommand; |
| import org.apache.hc.core5.http.protocol.HttpContext; |
| import org.apache.hc.core5.http.protocol.HttpProcessor; |
| import org.apache.hc.core5.http.protocol.HttpProcessorBuilder; |
| import org.apache.hc.core5.http.protocol.RequestUserAgent; |
| import org.apache.hc.core5.http2.HttpVersionPolicy; |
| import org.apache.hc.core5.http2.config.H2Config; |
| import org.apache.hc.core5.http2.protocol.H2RequestConnControl; |
| import org.apache.hc.core5.http2.protocol.H2RequestContent; |
| import org.apache.hc.core5.http2.protocol.H2RequestTargetHost; |
| import org.apache.hc.core5.io.ShutdownType; |
| import org.apache.hc.core5.pool.ConnPoolControl; |
| import org.apache.hc.core5.reactor.DefaultConnectingIOReactor; |
| import org.apache.hc.core5.reactor.IOEventHandlerFactory; |
| import org.apache.hc.core5.reactor.IOReactorConfig; |
| import org.apache.hc.core5.reactor.IOReactorException; |
| import org.apache.hc.core5.reactor.IOSession; |
| import org.apache.hc.core5.util.Args; |
| import org.apache.hc.core5.util.TimeValue; |
| import org.apache.hc.core5.util.VersionInfo; |
| |
| /** |
| * Builder for {@link CloseableHttpAsyncClient} instances. |
| * <p> |
| * When a particular component is not explicitly set this class will |
| * use its default implementation. System properties will be taken |
| * into account when configuring the default implementations when |
| * {@link #useSystemProperties()} method is called prior to calling |
| * {@link #build()}. |
| * </p> |
| * <ul> |
| * <li>http.proxyHost</li> |
| * <li>http.proxyPort</li> |
| * <li>http.nonProxyHosts</li> |
| * <li>http.keepAlive</li> |
| * <li>http.agent</li> |
| * </ul> |
| * <p> |
| * Please note that some settings used by this class can be mutually |
| * exclusive and may not apply when building {@link CloseableHttpAsyncClient} |
| * instances. |
| * </p> |
| * |
| * @since 5.0 |
| */ |
| public class HttpAsyncClientBuilder { |
| |
| private static class RequestInterceptorEntry { |
| |
| enum Postion { FIRST, LAST } |
| |
| final RequestInterceptorEntry.Postion postion; |
| final HttpRequestInterceptor interceptor; |
| |
| private RequestInterceptorEntry(final RequestInterceptorEntry.Postion postion, final HttpRequestInterceptor interceptor) { |
| this.postion = postion; |
| this.interceptor = interceptor; |
| } |
| } |
| |
| private static class ResponseInterceptorEntry { |
| |
| enum Postion { FIRST, LAST } |
| |
| final ResponseInterceptorEntry.Postion postion; |
| final HttpResponseInterceptor interceptor; |
| |
| private ResponseInterceptorEntry(final ResponseInterceptorEntry.Postion postion, final HttpResponseInterceptor interceptor) { |
| this.postion = postion; |
| this.interceptor = interceptor; |
| } |
| } |
| |
| private static class ExecInterceptorEntry { |
| |
| enum Postion { BEFORE, AFTER, REPLACE } |
| |
| final ExecInterceptorEntry.Postion postion; |
| final String name; |
| final AsyncExecChainHandler interceptor; |
| final String existing; |
| |
| private ExecInterceptorEntry( |
| final ExecInterceptorEntry.Postion postion, |
| final String name, |
| final AsyncExecChainHandler interceptor, |
| final String existing) { |
| this.postion = postion; |
| this.name = name; |
| this.interceptor = interceptor; |
| this.existing = existing; |
| } |
| |
| } |
| |
| private HttpVersionPolicy versionPolicy; |
| private AsyncClientConnectionManager connManager; |
| private boolean connManagerShared; |
| private IOReactorConfig ioReactorConfig; |
| private H1Config h1Config; |
| private H2Config h2Config; |
| private CharCodingConfig charCodingConfig; |
| private SchemePortResolver schemePortResolver; |
| private ConnectionKeepAliveStrategy keepAliveStrategy; |
| private UserTokenHandler userTokenHandler; |
| private AuthenticationStrategy targetAuthStrategy; |
| private AuthenticationStrategy proxyAuthStrategy; |
| |
| private LinkedList<RequestInterceptorEntry> requestInterceptors; |
| private LinkedList<ResponseInterceptorEntry> responseInterceptors; |
| private LinkedList<ExecInterceptorEntry> execInterceptors; |
| |
| private HttpRoutePlanner routePlanner; |
| private RedirectStrategy redirectStrategy; |
| private HttpRequestRetryHandler retryHandler; |
| |
| private ConnectionReuseStrategy reuseStrategy; |
| |
| private Lookup<AuthSchemeProvider> authSchemeRegistry; |
| private Lookup<CookieSpecProvider> cookieSpecRegistry; |
| private CookieStore cookieStore; |
| private CredentialsProvider credentialsProvider; |
| |
| private String userAgent; |
| private HttpHost proxy; |
| private Collection<? extends Header> defaultHeaders; |
| private RequestConfig defaultRequestConfig; |
| private boolean evictExpiredConnections; |
| private boolean evictIdleConnections; |
| private TimeValue maxIdleTime; |
| |
| private boolean systemProperties; |
| private boolean automaticRetriesDisabled; |
| private boolean redirectHandlingDisabled; |
| private boolean cookieManagementDisabled; |
| private boolean authCachingDisabled; |
| private boolean connectionStateDisabled; |
| |
| private ThreadFactory threadFactory; |
| |
| private List<Closeable> closeables; |
| |
| public static HttpAsyncClientBuilder create() { |
| return new HttpAsyncClientBuilder(); |
| } |
| |
| protected HttpAsyncClientBuilder() { |
| super(); |
| } |
| |
| /** |
| * Sets HTTP protocol version policy. |
| */ |
| public final HttpAsyncClientBuilder setVersionPolicy(final HttpVersionPolicy versionPolicy) { |
| this.versionPolicy = versionPolicy; |
| return this; |
| } |
| |
| /** |
| * Sets {@link H1Config} configuration. |
| */ |
| public final HttpAsyncClientBuilder setH1Config(final H1Config h1Config) { |
| this.h1Config = h1Config; |
| return this; |
| } |
| |
| /** |
| * Sets {@link H2Config} configuration. |
| */ |
| public final HttpAsyncClientBuilder setH2Config(final H2Config h2Config) { |
| this.h2Config = h2Config; |
| return this; |
| } |
| |
| /** |
| * Assigns {@link AsyncClientConnectionManager} instance. |
| */ |
| public final HttpAsyncClientBuilder setConnectionManager(final AsyncClientConnectionManager connManager) { |
| this.connManager = connManager; |
| return this; |
| } |
| |
| /** |
| * Defines the connection manager is to be shared by multiple |
| * client instances. |
| * <p> |
| * If the connection manager is shared its life-cycle is expected |
| * to be managed by the caller and it will not be shut down |
| * if the client is closed. |
| * |
| * @param shared defines whether or not the connection manager can be shared |
| * by multiple clients. |
| */ |
| public final HttpAsyncClientBuilder setConnectionManagerShared(final boolean shared) { |
| this.connManagerShared = shared; |
| return this; |
| } |
| |
| /** |
| * Sets {@link IOReactorConfig} configuration. |
| */ |
| public final HttpAsyncClientBuilder setIOReactorConfig(final IOReactorConfig ioReactorConfig) { |
| this.ioReactorConfig = ioReactorConfig; |
| return this; |
| } |
| |
| /** |
| * Sets {@link CharCodingConfig} configuration. |
| */ |
| public final HttpAsyncClientBuilder setCharCodingConfig(final CharCodingConfig charCodingConfig) { |
| this.charCodingConfig = charCodingConfig; |
| return this; |
| } |
| |
| /** |
| * Assigns {@link ConnectionReuseStrategy} instance. |
| * <p> |
| * Please note this strategy applies to HTTP/1.0 and HTTP/1.1 connections only |
| */ |
| public final HttpAsyncClientBuilder setConnectionReuseStrategy(final ConnectionReuseStrategy reuseStrategy) { |
| this.reuseStrategy = reuseStrategy; |
| return this; |
| } |
| |
| /** |
| * Assigns {@link ConnectionKeepAliveStrategy} instance. |
| */ |
| public final HttpAsyncClientBuilder setKeepAliveStrategy(final ConnectionKeepAliveStrategy keepAliveStrategy) { |
| this.keepAliveStrategy = keepAliveStrategy; |
| return this; |
| } |
| |
| /** |
| * Assigns {@link UserTokenHandler} instance. |
| * <p> |
| * Please note this value can be overridden by the {@link #disableConnectionState()} |
| * method. |
| * </p> |
| */ |
| public final HttpAsyncClientBuilder setUserTokenHandler(final UserTokenHandler userTokenHandler) { |
| this.userTokenHandler = userTokenHandler; |
| return this; |
| } |
| |
| /** |
| * Assigns {@link AuthenticationStrategy} instance for target |
| * host authentication. |
| */ |
| public final HttpAsyncClientBuilder setTargetAuthenticationStrategy( |
| final AuthenticationStrategy targetAuthStrategy) { |
| this.targetAuthStrategy = targetAuthStrategy; |
| return this; |
| } |
| |
| /** |
| * Assigns {@link AuthenticationStrategy} instance for proxy |
| * authentication. |
| */ |
| public final HttpAsyncClientBuilder setProxyAuthenticationStrategy( |
| final AuthenticationStrategy proxyAuthStrategy) { |
| this.proxyAuthStrategy = proxyAuthStrategy; |
| return this; |
| } |
| |
| /** |
| * Adds this protocol interceptor to the head of the protocol processing list. |
| */ |
| public final HttpAsyncClientBuilder addRequestInterceptorFirst(final HttpResponseInterceptor interceptor) { |
| Args.notNull(interceptor, "Interceptor"); |
| if (responseInterceptors == null) { |
| responseInterceptors = new LinkedList<>(); |
| } |
| responseInterceptors.add(new ResponseInterceptorEntry(ResponseInterceptorEntry.Postion.FIRST, interceptor)); |
| return this; |
| } |
| |
| /** |
| * Adds this protocol interceptor to the tail of the protocol processing list. |
| */ |
| public final HttpAsyncClientBuilder addResponseInterceptorLast(final HttpResponseInterceptor interceptor) { |
| Args.notNull(interceptor, "Interceptor"); |
| if (responseInterceptors == null) { |
| responseInterceptors = new LinkedList<>(); |
| } |
| responseInterceptors.add(new ResponseInterceptorEntry(ResponseInterceptorEntry.Postion.LAST, interceptor)); |
| return this; |
| } |
| |
| /** |
| * Adds this execution interceptor before an existing interceptor. |
| */ |
| public final HttpAsyncClientBuilder addExecInterceptorBefore(final String existing, final String name, final AsyncExecChainHandler interceptor) { |
| Args.notBlank(existing, "Existing"); |
| Args.notBlank(name, "Name"); |
| Args.notNull(interceptor, "Interceptor"); |
| if (execInterceptors == null) { |
| execInterceptors = new LinkedList<>(); |
| } |
| execInterceptors.add(new ExecInterceptorEntry(ExecInterceptorEntry.Postion.BEFORE, name, interceptor, existing)); |
| return this; |
| } |
| |
| /** |
| * Adds this execution interceptor after interceptor with the given name. |
| */ |
| public final HttpAsyncClientBuilder addExecInterceptorAfter(final String existing, final String name, final AsyncExecChainHandler interceptor) { |
| Args.notBlank(existing, "Existing"); |
| Args.notBlank(name, "Name"); |
| Args.notNull(interceptor, "Interceptor"); |
| if (execInterceptors == null) { |
| execInterceptors = new LinkedList<>(); |
| } |
| execInterceptors.add(new ExecInterceptorEntry(ExecInterceptorEntry.Postion.AFTER, name, interceptor, existing)); |
| return this; |
| } |
| |
| /** |
| * Replace an existing interceptor with the given name with new interceptor. |
| */ |
| public final HttpAsyncClientBuilder replaceExecInterceptor(final String existing, final AsyncExecChainHandler interceptor) { |
| Args.notBlank(existing, "Existing"); |
| Args.notNull(interceptor, "Interceptor"); |
| if (execInterceptors == null) { |
| execInterceptors = new LinkedList<>(); |
| } |
| execInterceptors.add(new ExecInterceptorEntry(ExecInterceptorEntry.Postion.REPLACE, existing, interceptor, existing)); |
| return this; |
| } |
| |
| /** |
| * Adds this protocol interceptor to the head of the protocol processing list. |
| */ |
| public final HttpAsyncClientBuilder addRequestInterceptorFirst(final HttpRequestInterceptor interceptor) { |
| Args.notNull(interceptor, "Interceptor"); |
| if (requestInterceptors == null) { |
| requestInterceptors = new LinkedList<>(); |
| } |
| requestInterceptors.add(new RequestInterceptorEntry(RequestInterceptorEntry.Postion.FIRST, interceptor)); |
| return this; |
| } |
| |
| /** |
| * Adds this protocol interceptor to the tail of the protocol processing list. |
| */ |
| public final HttpAsyncClientBuilder addResponseInterceptorLast(final HttpRequestInterceptor interceptor) { |
| Args.notNull(interceptor, "Interceptor"); |
| if (requestInterceptors == null) { |
| requestInterceptors = new LinkedList<>(); |
| } |
| requestInterceptors.add(new RequestInterceptorEntry(RequestInterceptorEntry.Postion.LAST, interceptor)); |
| return this; |
| } |
| |
| /** |
| * Assigns {@link HttpRequestRetryHandler} instance. |
| * <p> |
| * Please note this value can be overridden by the {@link #disableAutomaticRetries()} |
| * method. |
| */ |
| public final HttpAsyncClientBuilder setRetryHandler(final HttpRequestRetryHandler retryHandler) { |
| this.retryHandler = retryHandler; |
| return this; |
| } |
| |
| /** |
| * Assigns {@link RedirectStrategy} instance. |
| * <p> |
| * Please note this value can be overridden by the {@link #disableRedirectHandling()} |
| * method. |
| * </p> |
| */ |
| public HttpAsyncClientBuilder setRedirectStrategy(final RedirectStrategy redirectStrategy) { |
| this.redirectStrategy = redirectStrategy; |
| return this; |
| } |
| |
| /** |
| * Assigns {@link SchemePortResolver} instance. |
| */ |
| public final HttpAsyncClientBuilder setSchemePortResolver(final SchemePortResolver schemePortResolver) { |
| this.schemePortResolver = schemePortResolver; |
| return this; |
| } |
| |
| /** |
| * Assigns {@link ThreadFactory} instance. |
| */ |
| public final HttpAsyncClientBuilder setThreadFactory(final ThreadFactory threadFactory) { |
| this.threadFactory = threadFactory; |
| return this; |
| } |
| |
| /** |
| * Assigns {@code User-Agent} value. |
| */ |
| public final HttpAsyncClientBuilder setUserAgent(final String userAgent) { |
| this.userAgent = userAgent; |
| return this; |
| } |
| |
| /** |
| * Assigns default request header values. |
| */ |
| public final HttpAsyncClientBuilder setDefaultHeaders(final Collection<? extends Header> defaultHeaders) { |
| this.defaultHeaders = defaultHeaders; |
| return this; |
| } |
| |
| /** |
| * Assigns default proxy value. |
| * <p> |
| * Please note this value can be overridden by the {@link #setRoutePlanner( |
| * HttpRoutePlanner)} method. |
| */ |
| public final HttpAsyncClientBuilder setProxy(final HttpHost proxy) { |
| this.proxy = proxy; |
| return this; |
| } |
| |
| /** |
| * Assigns {@link HttpRoutePlanner} instance. |
| */ |
| public final HttpAsyncClientBuilder setRoutePlanner(final HttpRoutePlanner routePlanner) { |
| this.routePlanner = routePlanner; |
| return this; |
| } |
| |
| /** |
| * Assigns default {@link CredentialsProvider} instance which will be used |
| * for request execution if not explicitly set in the client execution |
| * context. |
| */ |
| public final HttpAsyncClientBuilder setDefaultCredentialsProvider(final CredentialsProvider credentialsProvider) { |
| this.credentialsProvider = credentialsProvider; |
| return this; |
| } |
| |
| /** |
| * Assigns default {@link org.apache.hc.client5.http.auth.AuthScheme} registry which will |
| * be used for request execution if not explicitly set in the client execution |
| * context. |
| */ |
| public final HttpAsyncClientBuilder setDefaultAuthSchemeRegistry(final Lookup<AuthSchemeProvider> authSchemeRegistry) { |
| this.authSchemeRegistry = authSchemeRegistry; |
| return this; |
| } |
| |
| /** |
| * Assigns default {@link org.apache.hc.client5.http.cookie.CookieSpec} registry |
| * which will be used for request execution if not explicitly set in the client |
| * execution context. |
| */ |
| public final HttpAsyncClientBuilder setDefaultCookieSpecRegistry(final Lookup<CookieSpecProvider> cookieSpecRegistry) { |
| this.cookieSpecRegistry = cookieSpecRegistry; |
| return this; |
| } |
| |
| /** |
| * Assigns default {@link CookieStore} instance which will be used for |
| * request execution if not explicitly set in the client execution context. |
| */ |
| public final HttpAsyncClientBuilder setDefaultCookieStore(final CookieStore cookieStore) { |
| this.cookieStore = cookieStore; |
| return this; |
| } |
| |
| /** |
| * Assigns default {@link RequestConfig} instance which will be used |
| * for request execution if not explicitly set in the client execution |
| * context. |
| */ |
| public final HttpAsyncClientBuilder setDefaultRequestConfig(final RequestConfig config) { |
| this.defaultRequestConfig = config; |
| return this; |
| } |
| |
| /** |
| * Use system properties when creating and configuring default |
| * implementations. |
| */ |
| public final HttpAsyncClientBuilder useSystemProperties() { |
| this.systemProperties = true; |
| return this; |
| } |
| |
| /** |
| * Disables connection state tracking. |
| */ |
| public final HttpAsyncClientBuilder disableConnectionState() { |
| connectionStateDisabled = true; |
| return this; |
| } |
| |
| /** |
| * Disables automatic redirect handling. |
| */ |
| public final HttpAsyncClientBuilder disableRedirectHandling() { |
| redirectHandlingDisabled = true; |
| return this; |
| } |
| |
| /** |
| * Disables automatic request recovery and re-execution. |
| */ |
| public final HttpAsyncClientBuilder disableAutomaticRetries() { |
| automaticRetriesDisabled = true; |
| return this; |
| } |
| |
| /** |
| * Disables state (cookie) management. |
| */ |
| public final HttpAsyncClientBuilder disableCookieManagement() { |
| this.cookieManagementDisabled = true; |
| return this; |
| } |
| |
| /** |
| * Disables authentication scheme caching. |
| */ |
| public final HttpAsyncClientBuilder disableAuthCaching() { |
| this.authCachingDisabled = true; |
| return this; |
| } |
| |
| /** |
| * Makes this instance of HttpClient proactively evict expired connections from the |
| * connection pool using a background thread. |
| * <p> |
| * One MUST explicitly close HttpClient with {@link CloseableHttpAsyncClient#close()} in order |
| * to stop and release the background thread. |
| * <p> |
| * Please note this method has no effect if the instance of HttpClient is configuted to |
| * use a shared connection manager. |
| * |
| * @see #setConnectionManagerShared(boolean) |
| * @see ConnPoolControl#closeExpired() |
| */ |
| public final HttpAsyncClientBuilder evictExpiredConnections() { |
| evictExpiredConnections = true; |
| return this; |
| } |
| |
| /** |
| * Makes this instance of HttpClient proactively evict idle connections from the |
| * connection pool using a background thread. |
| * <p> |
| * One MUST explicitly close HttpClient with {@link CloseableHttpAsyncClient#close()} |
| * in order to stop and release the background thread. |
| * <p> |
| * Please note this method has no effect if the instance of HttpClient is configuted to |
| * use a shared connection manager. |
| * |
| * @see #setConnectionManagerShared(boolean) |
| * @see ConnPoolControl#closeIdle(TimeValue) |
| * |
| * @param maxIdleTime maximum time persistent connections can stay idle while kept alive |
| * in the connection pool. Connections whose inactivity period exceeds this value will |
| * get closed and evicted from the pool. |
| */ |
| public final HttpAsyncClientBuilder evictIdleConnections(final TimeValue maxIdleTime) { |
| this.evictIdleConnections = true; |
| this.maxIdleTime = maxIdleTime; |
| return this; |
| } |
| |
| /** |
| * Request exec chain customization and extension. |
| * <p> |
| * For internal use. |
| */ |
| @Internal |
| protected void customizeExecChain(final NamedElementChain<AsyncExecChainHandler> execChainDefinition) { |
| } |
| |
| /** |
| * Adds to the list of {@link Closeable} resources to be managed by the client. |
| * <p> |
| * For internal use. |
| */ |
| @Internal |
| protected void addCloseable(final Closeable closeable) { |
| if (closeable == null) { |
| return; |
| } |
| if (closeables == null) { |
| closeables = new ArrayList<>(); |
| } |
| closeables.add(closeable); |
| } |
| |
| public CloseableHttpAsyncClient build() { |
| AsyncClientConnectionManager connManagerCopy = this.connManager; |
| if (connManagerCopy == null) { |
| connManagerCopy = PoolingAsyncClientConnectionManagerBuilder.create().build(); |
| } |
| |
| ConnectionKeepAliveStrategy keepAliveStrategyCopy = this.keepAliveStrategy; |
| if (keepAliveStrategyCopy == null) { |
| keepAliveStrategyCopy = DefaultConnectionKeepAliveStrategy.INSTANCE; |
| } |
| |
| UserTokenHandler userTokenHandlerCopy = this.userTokenHandler; |
| if (userTokenHandlerCopy == null) { |
| if (!connectionStateDisabled) { |
| userTokenHandlerCopy = DefaultUserTokenHandler.INSTANCE; |
| } else { |
| userTokenHandlerCopy = NoopUserTokenHandler.INSTANCE; |
| } |
| } |
| |
| final NamedElementChain<AsyncExecChainHandler> execChainDefinition = new NamedElementChain<>(); |
| execChainDefinition.addLast( |
| new AsyncMainClientExec(keepAliveStrategyCopy, userTokenHandlerCopy), |
| ChainElements.MAIN_TRANSPORT.name()); |
| |
| AuthenticationStrategy targetAuthStrategyCopy = this.targetAuthStrategy; |
| if (targetAuthStrategyCopy == null) { |
| targetAuthStrategyCopy = DefaultAuthenticationStrategy.INSTANCE; |
| } |
| AuthenticationStrategy proxyAuthStrategyCopy = this.proxyAuthStrategy; |
| if (proxyAuthStrategyCopy == null) { |
| proxyAuthStrategyCopy = DefaultAuthenticationStrategy.INSTANCE; |
| } |
| |
| String userAgentCopy = this.userAgent; |
| if (userAgentCopy == null) { |
| if (systemProperties) { |
| userAgentCopy = System.getProperty("http.agent"); |
| } |
| if (userAgentCopy == null) { |
| userAgentCopy = VersionInfo.getSoftwareInfo("Apache-HttpAsyncClient", |
| "org.apache.hc.client5", getClass()); |
| } |
| } |
| |
| final HttpProcessorBuilder b = HttpProcessorBuilder.create(); |
| if (requestInterceptors != null) { |
| for (final RequestInterceptorEntry entry: requestInterceptors) { |
| if (entry.postion == RequestInterceptorEntry.Postion.FIRST) { |
| b.addFirst(entry.interceptor); |
| } |
| } |
| } |
| if (responseInterceptors != null) { |
| for (final ResponseInterceptorEntry entry: responseInterceptors) { |
| if (entry.postion == ResponseInterceptorEntry.Postion.FIRST) { |
| b.addFirst(entry.interceptor); |
| } |
| } |
| } |
| b.addAll( |
| new RequestDefaultHeaders(defaultHeaders), |
| new H2RequestContent(), |
| new H2RequestTargetHost(), |
| new H2RequestConnControl(), |
| new RequestUserAgent(userAgentCopy), |
| new RequestExpectContinue()); |
| if (!cookieManagementDisabled) { |
| b.add(new RequestAddCookies()); |
| } |
| if (!authCachingDisabled) { |
| b.add(new RequestAuthCache()); |
| } |
| if (!cookieManagementDisabled) { |
| b.add(new ResponseProcessCookies()); |
| } |
| if (requestInterceptors != null) { |
| for (final RequestInterceptorEntry entry: requestInterceptors) { |
| if (entry.postion == RequestInterceptorEntry.Postion.LAST) { |
| b.addFirst(entry.interceptor); |
| } |
| } |
| } |
| if (responseInterceptors != null) { |
| for (final ResponseInterceptorEntry entry: responseInterceptors) { |
| if (entry.postion == ResponseInterceptorEntry.Postion.LAST) { |
| b.addFirst(entry.interceptor); |
| } |
| } |
| } |
| |
| final HttpProcessor httpProcessor = b.build(); |
| execChainDefinition.addFirst( |
| new AsyncProtocolExec(httpProcessor, targetAuthStrategyCopy, proxyAuthStrategyCopy), |
| ChainElements.PROTOCOL.name()); |
| |
| // Add request retry executor, if not disabled |
| if (!automaticRetriesDisabled) { |
| HttpRequestRetryHandler retryHandlerCopy = this.retryHandler; |
| if (retryHandlerCopy == null) { |
| retryHandlerCopy = DefaultHttpRequestRetryHandler.INSTANCE; |
| } |
| execChainDefinition.addFirst( |
| new AsyncRetryExec(retryHandlerCopy), |
| ChainElements.RETRY_IO_ERROR.name()); |
| } |
| |
| HttpRoutePlanner routePlannerCopy = this.routePlanner; |
| if (routePlannerCopy == null) { |
| SchemePortResolver schemePortResolverCopy = this.schemePortResolver; |
| if (schemePortResolverCopy == null) { |
| schemePortResolverCopy = DefaultSchemePortResolver.INSTANCE; |
| } |
| if (proxy != null) { |
| routePlannerCopy = new DefaultProxyRoutePlanner(proxy, schemePortResolverCopy); |
| } else if (systemProperties) { |
| routePlannerCopy = new SystemDefaultRoutePlanner( |
| schemePortResolverCopy, ProxySelector.getDefault()); |
| } else { |
| routePlannerCopy = new DefaultRoutePlanner(schemePortResolverCopy); |
| } |
| } |
| |
| // Add redirect executor, if not disabled |
| if (!redirectHandlingDisabled) { |
| RedirectStrategy redirectStrategyCopy = this.redirectStrategy; |
| if (redirectStrategyCopy == null) { |
| redirectStrategyCopy = DefaultRedirectStrategy.INSTANCE; |
| } |
| execChainDefinition.addFirst( |
| new AsyncRedirectExec(routePlannerCopy, redirectStrategyCopy), |
| ChainElements.REDIRECT.name()); |
| } |
| |
| List<Closeable> closeablesCopy = closeables != null ? new ArrayList<>(closeables) : null; |
| if (!this.connManagerShared) { |
| if (closeablesCopy == null) { |
| closeablesCopy = new ArrayList<>(1); |
| } |
| if (evictExpiredConnections || evictIdleConnections) { |
| if (connManagerCopy instanceof ConnPoolControl) { |
| final IdleConnectionEvictor connectionEvictor = new IdleConnectionEvictor((ConnPoolControl<?>) connManagerCopy, |
| maxIdleTime, maxIdleTime); |
| closeablesCopy.add(new Closeable() { |
| |
| @Override |
| public void close() throws IOException { |
| connectionEvictor.shutdown(); |
| } |
| |
| }); |
| connectionEvictor.start(); |
| } |
| } |
| closeablesCopy.add(connManagerCopy); |
| } |
| ConnectionReuseStrategy reuseStrategyCopy = this.reuseStrategy; |
| if (reuseStrategyCopy == null) { |
| if (systemProperties) { |
| final String s = System.getProperty("http.keepAlive", "true"); |
| if ("true".equalsIgnoreCase(s)) { |
| reuseStrategyCopy = DefaultConnectionReuseStrategy.INSTANCE; |
| } else { |
| reuseStrategyCopy = new ConnectionReuseStrategy() { |
| @Override |
| public boolean keepAlive( |
| final HttpRequest request, final HttpResponse response, final HttpContext context) { |
| return false; |
| } |
| }; |
| } |
| } else { |
| reuseStrategyCopy = DefaultConnectionReuseStrategy.INSTANCE; |
| } |
| } |
| final AsyncPushConsumerRegistry pushConsumerRegistry = new AsyncPushConsumerRegistry(); |
| final IOEventHandlerFactory ioEventHandlerFactory = new HttpAsyncClientEventHandlerFactory( |
| NoopHttpProcessor.INSTANCE, |
| new HandlerFactory<AsyncPushConsumer>() { |
| |
| @Override |
| public AsyncPushConsumer create(final HttpRequest request) throws HttpException { |
| return pushConsumerRegistry.get(request); |
| } |
| |
| }, |
| versionPolicy != null ? versionPolicy : HttpVersionPolicy.NEGOTIATE, |
| h2Config != null ? h2Config : H2Config.DEFAULT, |
| h1Config != null ? h1Config : H1Config.DEFAULT, |
| charCodingConfig != null ? charCodingConfig : CharCodingConfig.DEFAULT, |
| reuseStrategyCopy); |
| final DefaultConnectingIOReactor ioReactor; |
| try { |
| ioReactor = new DefaultConnectingIOReactor( |
| ioEventHandlerFactory, |
| ioReactorConfig != null ? ioReactorConfig : IOReactorConfig.DEFAULT, |
| threadFactory != null ? threadFactory : new DefaultThreadFactory("httpclient-dispatch", true), |
| new Callback<IOSession>() { |
| |
| @Override |
| public void execute(final IOSession ioSession) { |
| ioSession.addFirst(new ShutdownCommand(ShutdownType.GRACEFUL)); |
| } |
| |
| }); |
| } catch (final IOReactorException ex) { |
| throw new IllegalStateException(ex.getMessage(), ex); |
| } |
| |
| if (execInterceptors != null) { |
| for (final ExecInterceptorEntry entry: execInterceptors) { |
| switch (entry.postion) { |
| case AFTER: |
| execChainDefinition.addAfter(entry.existing, entry.interceptor, entry.name); |
| break; |
| case BEFORE: |
| execChainDefinition.addBefore(entry.existing, entry.interceptor, entry.name); |
| break; |
| } |
| } |
| } |
| |
| customizeExecChain(execChainDefinition); |
| |
| NamedElementChain<AsyncExecChainHandler>.Node current = execChainDefinition.getLast(); |
| AsyncExecChainElement execChain = null; |
| while (current != null) { |
| execChain = new AsyncExecChainElement(current.getValue(), execChain); |
| current = current.getPrevious(); |
| } |
| |
| Lookup<AuthSchemeProvider> authSchemeRegistryCopy = this.authSchemeRegistry; |
| if (authSchemeRegistryCopy == null) { |
| authSchemeRegistryCopy = RegistryBuilder.<AuthSchemeProvider>create() |
| .register(AuthSchemes.BASIC, new BasicSchemeFactory()) |
| .register(AuthSchemes.DIGEST, new DigestSchemeFactory()) |
| .register(AuthSchemes.CREDSSP, new CredSspSchemeFactory()) |
| .register(AuthSchemes.NTLM, new NTLMSchemeFactory()) |
| .register(AuthSchemes.SPNEGO, new SPNegoSchemeFactory(SystemDefaultDnsResolver.INSTANCE, true, true)) |
| .register(AuthSchemes.KERBEROS, new KerberosSchemeFactory(SystemDefaultDnsResolver.INSTANCE, true, true)) |
| .build(); |
| } |
| Lookup<CookieSpecProvider> cookieSpecRegistryCopy = this.cookieSpecRegistry; |
| if (cookieSpecRegistryCopy == null) { |
| cookieSpecRegistryCopy = CookieSpecRegistries.createDefault(); |
| } |
| |
| CookieStore cookieStoreCopy = this.cookieStore; |
| if (cookieStoreCopy == null) { |
| cookieStoreCopy = new BasicCookieStore(); |
| } |
| |
| CredentialsProvider credentialsProviderCopy = this.credentialsProvider; |
| if (credentialsProviderCopy == null) { |
| if (systemProperties) { |
| credentialsProviderCopy = new SystemDefaultCredentialsProvider(); |
| } else { |
| credentialsProviderCopy = new BasicCredentialsProvider(); |
| } |
| } |
| |
| return new InternalHttpAsyncClient( |
| ioReactor, |
| execChain, |
| pushConsumerRegistry, |
| threadFactory != null ? threadFactory : new DefaultThreadFactory("httpclient-main", true), |
| connManagerCopy, |
| routePlannerCopy, |
| versionPolicy != null ? versionPolicy : HttpVersionPolicy.NEGOTIATE, |
| cookieSpecRegistryCopy, |
| authSchemeRegistryCopy, |
| cookieStoreCopy, |
| credentialsProviderCopy, |
| defaultRequestConfig, |
| closeablesCopy); |
| } |
| |
| } |