addresses) {
- }
-
- /**
- * Notify the callback after hostname resolution failed.
- *
- * @param name the name to be resolved
- * @param cause the failure cause
- */
- default void onHostnameResolutionFailure(String name, Throwable cause) {
- }
-
- // ////////////// TCP CONNECT ////////
-
- /**
- * Notify the callback when trying to open a new connection.
- *
- * Might be called several times if the name was resolved to multiple addresses and we failed to connect to the first(s) one(s).
- *
- * @param remoteAddress the address we try to connect to
- */
- default void onTcpConnectAttempt(InetSocketAddress remoteAddress) {
- }
-
- /**
- * Notify the callback after a successful connect
- *
- * @param remoteAddress the address we try to connect to
- * @param connection the connection
- */
- default void onTcpConnectSuccess(InetSocketAddress remoteAddress, Channel connection) {
- }
-
- /**
- * Notify the callback after a failed connect.
- *
- * Might be called several times, or be followed by onTcpConnectSuccess when the name was resolved to multiple addresses.
- *
- * @param remoteAddress the address we try to connect to
- * @param cause the cause of the failure
- */
- default void onTcpConnectFailure(InetSocketAddress remoteAddress, Throwable cause) {
- }
-
- // ////////////// TLS ///////////////
-
- /**
- * Notify the callback before TLS handshake
- */
- default void onTlsHandshakeAttempt() {
- }
-
- /**
- * Notify the callback after the TLS was successful
- */
- default void onTlsHandshakeSuccess(SSLSession sslSession) {
- }
-
- /**
- * Notify the callback after the TLS failed
- *
- * @param cause the cause of the failure
- */
- default void onTlsHandshakeFailure(Throwable cause) {
- }
-
- // /////////// POOLING /////////////
-
- /**
- * Notify the callback when trying to fetch a connection from the pool.
- */
- default void onConnectionPoolAttempt() {
- }
-
- /**
- * Notify the callback when a new connection was successfully fetched from the pool.
- *
- * @param connection the connection
- */
- default void onConnectionPooled(Channel connection) {
- }
-
- /**
- * Notify the callback when trying to offer a connection to the pool.
- *
- * @param connection the connection
- */
- default void onConnectionOffer(Channel connection) {
- }
-
- // //////////// SENDING //////////////
-
- /**
- * Notify the callback when a request is being written on the channel. If the original request causes multiple requests to be sent, for example, because of authorization or
- * retry, it will be notified multiple times.
- *
- * @param request the real request object as passed to the provider
- */
- default void onRequestSend(NettyRequest request) {
- }
-
- /**
- * Notify the callback every time a request is being retried.
- */
- default void onRetry() {
- }
-
- enum State {
-
- /**
- * Stop the processing.
- */
- ABORT,
- /**
- * Continue the processing
- */
- CONTINUE
- }
+ /**
+ * Invoked as soon as the HTTP status line has been received
+ *
+ * @param responseStatus the status code and test of the response
+ * @return a {@link State} telling to CONTINUE or ABORT the current processing.
+ * @throws Exception if something wrong happens
+ */
+ State onStatusReceived(HttpResponseStatus responseStatus) throws Exception;
+
+ /**
+ * Invoked as soon as the HTTP headers have been received.
+ *
+ * @param headers the HTTP headers.
+ * @return a {@link State} telling to CONTINUE or ABORT the current processing.
+ * @throws Exception if something wrong happens
+ */
+ State onHeadersReceived(HttpHeaders headers) throws Exception;
+
+ /**
+ * Invoked as soon as some response body part are received. Could be invoked many times.
+ * Beware that, depending on the provider (Netty) this can be notified with empty body parts.
+ *
+ * @param bodyPart response's body part.
+ * @return a {@link State} telling to CONTINUE or ABORT the current processing. Aborting will also close the connection.
+ * @throws Exception if something wrong happens
+ */
+ State onBodyPartReceived(HttpResponseBodyPart bodyPart) throws Exception;
+
+ /**
+ * Invoked when trailing headers have been received.
+ *
+ * @param headers the trailing HTTP headers.
+ * @return a {@link State} telling to CONTINUE or ABORT the current processing.
+ * @throws Exception if something wrong happens
+ */
+ default State onTrailingHeadersReceived(HttpHeaders headers) throws Exception {
+ return State.CONTINUE;
+ }
+
+ /**
+ * Invoked when an unexpected exception occurs during the processing of the response. The exception may have been
+ * produced by implementation of onXXXReceived method invocation.
+ *
+ * @param t a {@link Throwable}
+ */
+ void onThrowable(Throwable t);
+
+ /**
+ * Invoked once the HTTP response processing is finished.
+ *
+ * Gets always invoked as last callback method.
+ *
+ * @return T Value that will be returned by the associated {@link Future}
+ * @throws Exception if something wrong happens
+ */
+ T onCompleted() throws Exception;
+
+ /**
+ * Notify the callback before hostname resolution
+ *
+ * @param name the name to be resolved
+ */
+ default void onHostnameResolutionAttempt(String name) {
+ }
+
+ // ////////// DNS /////////////////
+
+ /**
+ * Notify the callback after hostname resolution was successful.
+ *
+ * @param name the name to be resolved
+ * @param addresses the resolved addresses
+ */
+ default void onHostnameResolutionSuccess(String name, List addresses) {
+ }
+
+ /**
+ * Notify the callback after hostname resolution failed.
+ *
+ * @param name the name to be resolved
+ * @param cause the failure cause
+ */
+ default void onHostnameResolutionFailure(String name, Throwable cause) {
+ }
+
+ // ////////////// TCP CONNECT ////////
+
+ /**
+ * Notify the callback when trying to open a new connection.
+ *
+ * Might be called several times if the name was resolved to multiple addresses and we failed to connect to the first(s) one(s).
+ *
+ * @param remoteAddress the address we try to connect to
+ */
+ default void onTcpConnectAttempt(InetSocketAddress remoteAddress) {
+ }
+
+ /**
+ * Notify the callback after a successful connect
+ *
+ * @param remoteAddress the address we try to connect to
+ * @param connection the connection
+ */
+ default void onTcpConnectSuccess(InetSocketAddress remoteAddress, Channel connection) {
+ }
+
+ /**
+ * Notify the callback after a failed connect.
+ *
+ * Might be called several times, or be followed by onTcpConnectSuccess when the name was resolved to multiple addresses.
+ *
+ * @param remoteAddress the address we try to connect to
+ * @param cause the cause of the failure
+ */
+ default void onTcpConnectFailure(InetSocketAddress remoteAddress, Throwable cause) {
+ }
+
+ // ////////////// TLS ///////////////
+
+ /**
+ * Notify the callback before TLS handshake
+ */
+ default void onTlsHandshakeAttempt() {
+ }
+
+ /**
+ * Notify the callback after the TLS was successful
+ */
+ default void onTlsHandshakeSuccess(SSLSession sslSession) {
+ }
+
+ /**
+ * Notify the callback after the TLS failed
+ *
+ * @param cause the cause of the failure
+ */
+ default void onTlsHandshakeFailure(Throwable cause) {
+ }
+
+ // /////////// POOLING /////////////
+
+ /**
+ * Notify the callback when trying to fetch a connection from the pool.
+ */
+ default void onConnectionPoolAttempt() {
+ }
+
+ /**
+ * Notify the callback when a new connection was successfully fetched from the pool.
+ *
+ * @param connection the connection
+ */
+ default void onConnectionPooled(Channel connection) {
+ }
+
+ /**
+ * Notify the callback when trying to offer a connection to the pool.
+ *
+ * @param connection the connection
+ */
+ default void onConnectionOffer(Channel connection) {
+ }
+
+ // //////////// SENDING //////////////
+
+ /**
+ * Notify the callback when a request is being written on the channel. If the original request causes multiple requests to be sent, for example, because of authorization or
+ * retry, it will be notified multiple times.
+ *
+ * @param request the real request object as passed to the provider
+ */
+ default void onRequestSend(NettyRequest request) {
+ }
+
+ /**
+ * Notify the callback every time a request is being retried.
+ */
+ default void onRetry() {
+ }
+
+ enum State {
+
+ /**
+ * Stop the processing.
+ */
+ ABORT,
+ /**
+ * Continue the processing
+ */
+ CONTINUE
+ }
}
diff --git a/client/src/main/java/org/asynchttpclient/AsyncHttpClient.java b/client/src/main/java/org/asynchttpclient/AsyncHttpClient.java
index 2ab335f3f6..a08352647b 100755
--- a/client/src/main/java/org/asynchttpclient/AsyncHttpClient.java
+++ b/client/src/main/java/org/asynchttpclient/AsyncHttpClient.java
@@ -108,7 +108,7 @@
*
* You can asynchronously process the response status, headers and body and decide when to
* stop processing the response by returning a new {@link AsyncHandler.State#ABORT} at any moment.
- *
+ *
* This class can also be used without the need of {@link AsyncHandler}.
*
*
@@ -116,7 +116,7 @@
* Future<Response> f = c.prepareGet(TARGET_URL).execute();
* Response r = f.get();
*
- *
+ *
* Finally, you can configure the AsyncHttpClient using an {@link DefaultAsyncHttpClientConfig} instance.
*
*
@@ -130,173 +130,173 @@
*/
public interface AsyncHttpClient extends Closeable {
- /**
- * Return true if closed
- *
- * @return true if closed
- */
- boolean isClosed();
+ /**
+ * Return true if closed
+ *
+ * @return true if closed
+ */
+ boolean isClosed();
- /**
- * Set default signature calculator to use for requests built by this client instance
- *
- * @param signatureCalculator a signature calculator
- * @return {@link RequestBuilder}
- */
- AsyncHttpClient setSignatureCalculator(SignatureCalculator signatureCalculator);
+ /**
+ * Set default signature calculator to use for requests built by this client instance
+ *
+ * @param signatureCalculator a signature calculator
+ * @return {@link RequestBuilder}
+ */
+ AsyncHttpClient setSignatureCalculator(SignatureCalculator signatureCalculator);
- /**
- * Prepare an HTTP client request.
- *
- * @param method HTTP request method type. MUST BE in upper case
- * @param url A well formed URL.
- * @return {@link RequestBuilder}
- */
- BoundRequestBuilder prepare(String method, String url);
+ /**
+ * Prepare an HTTP client request.
+ *
+ * @param method HTTP request method type. MUST BE in upper case
+ * @param url A well formed URL.
+ * @return {@link RequestBuilder}
+ */
+ BoundRequestBuilder prepare(String method, String url);
- /**
- * Prepare an HTTP client GET request.
- *
- * @param url A well formed URL.
- * @return {@link RequestBuilder}
- */
- BoundRequestBuilder prepareGet(String url);
+ /**
+ * Prepare an HTTP client GET request.
+ *
+ * @param url A well formed URL.
+ * @return {@link RequestBuilder}
+ */
+ BoundRequestBuilder prepareGet(String url);
- /**
- * Prepare an HTTP client CONNECT request.
- *
- * @param url A well formed URL.
- * @return {@link RequestBuilder}
- */
- BoundRequestBuilder prepareConnect(String url);
+ /**
+ * Prepare an HTTP client CONNECT request.
+ *
+ * @param url A well formed URL.
+ * @return {@link RequestBuilder}
+ */
+ BoundRequestBuilder prepareConnect(String url);
- /**
- * Prepare an HTTP client OPTIONS request.
- *
- * @param url A well formed URL.
- * @return {@link RequestBuilder}
- */
- BoundRequestBuilder prepareOptions(String url);
+ /**
+ * Prepare an HTTP client OPTIONS request.
+ *
+ * @param url A well formed URL.
+ * @return {@link RequestBuilder}
+ */
+ BoundRequestBuilder prepareOptions(String url);
- /**
- * Prepare an HTTP client HEAD request.
- *
- * @param url A well formed URL.
- * @return {@link RequestBuilder}
- */
- BoundRequestBuilder prepareHead(String url);
+ /**
+ * Prepare an HTTP client HEAD request.
+ *
+ * @param url A well formed URL.
+ * @return {@link RequestBuilder}
+ */
+ BoundRequestBuilder prepareHead(String url);
- /**
- * Prepare an HTTP client POST request.
- *
- * @param url A well formed URL.
- * @return {@link RequestBuilder}
- */
- BoundRequestBuilder preparePost(String url);
+ /**
+ * Prepare an HTTP client POST request.
+ *
+ * @param url A well formed URL.
+ * @return {@link RequestBuilder}
+ */
+ BoundRequestBuilder preparePost(String url);
- /**
- * Prepare an HTTP client PUT request.
- *
- * @param url A well formed URL.
- * @return {@link RequestBuilder}
- */
- BoundRequestBuilder preparePut(String url);
+ /**
+ * Prepare an HTTP client PUT request.
+ *
+ * @param url A well formed URL.
+ * @return {@link RequestBuilder}
+ */
+ BoundRequestBuilder preparePut(String url);
- /**
- * Prepare an HTTP client DELETE request.
- *
- * @param url A well formed URL.
- * @return {@link RequestBuilder}
- */
- BoundRequestBuilder prepareDelete(String url);
+ /**
+ * Prepare an HTTP client DELETE request.
+ *
+ * @param url A well formed URL.
+ * @return {@link RequestBuilder}
+ */
+ BoundRequestBuilder prepareDelete(String url);
- /**
- * Prepare an HTTP client PATCH request.
- *
- * @param url A well formed URL.
- * @return {@link RequestBuilder}
- */
- BoundRequestBuilder preparePatch(String url);
+ /**
+ * Prepare an HTTP client PATCH request.
+ *
+ * @param url A well formed URL.
+ * @return {@link RequestBuilder}
+ */
+ BoundRequestBuilder preparePatch(String url);
- /**
- * Prepare an HTTP client TRACE request.
- *
- * @param url A well formed URL.
- * @return {@link RequestBuilder}
- */
- BoundRequestBuilder prepareTrace(String url);
+ /**
+ * Prepare an HTTP client TRACE request.
+ *
+ * @param url A well formed URL.
+ * @return {@link RequestBuilder}
+ */
+ BoundRequestBuilder prepareTrace(String url);
- /**
- * Construct a {@link RequestBuilder} using a {@link Request}
- *
- * @param request a {@link Request}
- * @return {@link RequestBuilder}
- */
- BoundRequestBuilder prepareRequest(Request request);
+ /**
+ * Construct a {@link RequestBuilder} using a {@link Request}
+ *
+ * @param request a {@link Request}
+ * @return {@link RequestBuilder}
+ */
+ BoundRequestBuilder prepareRequest(Request request);
- /**
- * Construct a {@link RequestBuilder} using a {@link RequestBuilder}
- *
- * @param requestBuilder a {@link RequestBuilder}
- * @return {@link RequestBuilder}
- */
- BoundRequestBuilder prepareRequest(RequestBuilder requestBuilder);
+ /**
+ * Construct a {@link RequestBuilder} using a {@link RequestBuilder}
+ *
+ * @param requestBuilder a {@link RequestBuilder}
+ * @return {@link RequestBuilder}
+ */
+ BoundRequestBuilder prepareRequest(RequestBuilder requestBuilder);
- /**
- * Execute an HTTP request.
- *
- * @param request {@link Request}
- * @param handler an instance of {@link AsyncHandler}
- * @param Type of the value that will be returned by the associated {@link java.util.concurrent.Future}
- * @return a {@link Future} of type T
- */
- ListenableFuture executeRequest(Request request, AsyncHandler handler);
+ /**
+ * Execute an HTTP request.
+ *
+ * @param request {@link Request}
+ * @param handler an instance of {@link AsyncHandler}
+ * @param Type of the value that will be returned by the associated {@link Future}
+ * @return a {@link Future} of type T
+ */
+ ListenableFuture executeRequest(Request request, AsyncHandler handler);
- /**
- * Execute an HTTP request.
- *
- * @param requestBuilder {@link RequestBuilder}
- * @param handler an instance of {@link AsyncHandler}
- * @param Type of the value that will be returned by the associated {@link java.util.concurrent.Future}
- * @return a {@link Future} of type T
- */
- ListenableFuture executeRequest(RequestBuilder requestBuilder, AsyncHandler handler);
+ /**
+ * Execute an HTTP request.
+ *
+ * @param requestBuilder {@link RequestBuilder}
+ * @param handler an instance of {@link AsyncHandler}
+ * @param Type of the value that will be returned by the associated {@link Future}
+ * @return a {@link Future} of type T
+ */
+ ListenableFuture executeRequest(RequestBuilder requestBuilder, AsyncHandler handler);
- /**
- * Execute an HTTP request.
- *
- * @param request {@link Request}
- * @return a {@link Future} of type Response
- */
- ListenableFuture executeRequest(Request request);
+ /**
+ * Execute an HTTP request.
+ *
+ * @param request {@link Request}
+ * @return a {@link Future} of type Response
+ */
+ ListenableFuture executeRequest(Request request);
- /**
- * Execute an HTTP request.
- *
- * @param requestBuilder {@link RequestBuilder}
- * @return a {@link Future} of type Response
- */
- ListenableFuture executeRequest(RequestBuilder requestBuilder);
+ /**
+ * Execute an HTTP request.
+ *
+ * @param requestBuilder {@link RequestBuilder}
+ * @return a {@link Future} of type Response
+ */
+ ListenableFuture executeRequest(RequestBuilder requestBuilder);
- /***
- * Return details about pooled connections.
- *
- * @return a {@link ClientStats}
- */
- ClientStats getClientStats();
+ /***
+ * Return details about pooled connections.
+ *
+ * @return a {@link ClientStats}
+ */
+ ClientStats getClientStats();
- /**
- * Flush ChannelPool partitions based on a predicate
- *
- * @param predicate the predicate
- */
- void flushChannelPoolPartitions(Predicate predicate);
+ /**
+ * Flush ChannelPool partitions based on a predicate
+ *
+ * @param predicate the predicate
+ */
+ void flushChannelPoolPartitions(Predicate predicate);
- /**
- * Return the config associated to this client.
- *
- * @return the config associated to this client.
- */
- AsyncHttpClientConfig getConfig();
+ /**
+ * Return the config associated to this client.
+ *
+ * @return the config associated to this client.
+ */
+ AsyncHttpClientConfig getConfig();
}
diff --git a/client/src/main/java/org/asynchttpclient/AsyncHttpClientConfig.java b/client/src/main/java/org/asynchttpclient/AsyncHttpClientConfig.java
index a761322dc3..643d4416cd 100644
--- a/client/src/main/java/org/asynchttpclient/AsyncHttpClientConfig.java
+++ b/client/src/main/java/org/asynchttpclient/AsyncHttpClientConfig.java
@@ -1,15 +1,17 @@
/*
- * Copyright (c) 2015 AsyncHttpClient Project. All rights reserved.
+ * Copyright (c) 2015-2023 AsyncHttpClient Project. All rights reserved.
*
- * This program is licensed to you under the Apache License Version 2.0,
- * and you may not use this file except in compliance with the Apache License Version 2.0.
- * You may obtain a copy of the Apache License Version 2.0 at
- * http://www.apache.org/licenses/LICENSE-2.0.
+ * 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
*
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the Apache License Version 2.0 is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the Apache License Version 2.0 for the specific language governing permissions and limitations there under.
+ * 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 org.asynchttpclient;
@@ -19,6 +21,7 @@
import io.netty.channel.ChannelOption;
import io.netty.channel.EventLoopGroup;
import io.netty.handler.ssl.SslContext;
+import io.netty.util.HashedWheelTimer;
import io.netty.util.Timer;
import org.asynchttpclient.channel.ChannelPool;
import org.asynchttpclient.channel.KeepAliveStrategy;
@@ -32,6 +35,7 @@
import org.asynchttpclient.proxy.ProxyServer;
import org.asynchttpclient.proxy.ProxyServerSelector;
+import java.io.IOException;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ThreadFactory;
@@ -39,330 +43,332 @@
public interface AsyncHttpClientConfig {
- /**
- * @return the version of AHC
- */
- String getAhcVersion();
-
- /**
- * Return the name of {@link AsyncHttpClient}, which is used for thread naming and debugging.
- *
- * @return the name.
- */
- String getThreadPoolName();
-
- /**
- * Return the maximum number of connections an {@link AsyncHttpClient} can handle.
- *
- * @return the maximum number of connections an {@link AsyncHttpClient} can handle.
- */
- int getMaxConnections();
-
- /**
- * Return the maximum number of connections per hosts an {@link AsyncHttpClient} can handle.
- *
- * @return the maximum number of connections per host an {@link AsyncHttpClient} can handle.
- */
- int getMaxConnectionsPerHost();
-
- /**
- * Return the maximum duration in milliseconds an {@link AsyncHttpClient} can wait to acquire a free channel
- *
- * @return Return the maximum duration in milliseconds an {@link AsyncHttpClient} can wait to acquire a free channel
- */
- int getAcquireFreeChannelTimeout();
-
-
- /**
- * Return the maximum time in millisecond an {@link AsyncHttpClient} can wait when connecting to a remote host
- *
- * @return the maximum time in millisecond an {@link AsyncHttpClient} can wait when connecting to a remote host
- */
- int getConnectTimeout();
-
- /**
- * Return the maximum time in millisecond an {@link AsyncHttpClient} can stay idle.
- *
- * @return the maximum time in millisecond an {@link AsyncHttpClient} can stay idle.
- */
- int getReadTimeout();
-
- /**
- * Return the maximum time in millisecond an {@link AsyncHttpClient} will keep connection in pool.
- *
- * @return the maximum time in millisecond an {@link AsyncHttpClient} will keep connection in pool.
- */
- int getPooledConnectionIdleTimeout();
-
- /**
- * @return the period in millis to clean the pool of dead and idle connections.
- */
- int getConnectionPoolCleanerPeriod();
-
- /**
- * Return the maximum time in millisecond an {@link AsyncHttpClient} waits until the response is completed.
- *
- * @return the maximum time in millisecond an {@link AsyncHttpClient} waits until the response is completed.
- */
- int getRequestTimeout();
-
- /**
- * Is HTTP redirect enabled
- *
- * @return true if enabled.
- */
- boolean isFollowRedirect();
-
- /**
- * Get the maximum number of HTTP redirect
- *
- * @return the maximum number of HTTP redirect
- */
- int getMaxRedirects();
-
- /**
- * Is the {@link ChannelPool} support enabled.
- *
- * @return true if keep-alive is enabled
- */
- boolean isKeepAlive();
-
- /**
- * Return the USER_AGENT header value
- *
- * @return the USER_AGENT header value
- */
- String getUserAgent();
-
- /**
- * Is HTTP compression enforced.
- *
- * @return true if compression is enforced
- */
- boolean isCompressionEnforced();
-
- /**
- * Return the {@link java.util.concurrent.ThreadFactory} an {@link AsyncHttpClient} use for handling asynchronous response.
- *
- * @return the {@link java.util.concurrent.ThreadFactory} an {@link AsyncHttpClient} use for handling asynchronous response. If no {@link ThreadFactory} has been explicitly
- * provided, this method will return null
- */
- ThreadFactory getThreadFactory();
-
- /**
- * An instance of {@link ProxyServer} used by an {@link AsyncHttpClient}
- *
- * @return instance of {@link ProxyServer}
- */
- ProxyServerSelector getProxyServerSelector();
-
- /**
- * Return an instance of {@link SslContext} used for SSL connection.
- *
- * @return an instance of {@link SslContext} used for SSL connection.
- */
- SslContext getSslContext();
-
- /**
- * Return the current {@link Realm}
- *
- * @return the current {@link Realm}
- */
- Realm getRealm();
-
- /**
- * Return the list of {@link RequestFilter}
- *
- * @return Unmodifiable list of {@link RequestFilter}
- */
- List getRequestFilters();
-
- /**
- * Return the list of {@link ResponseFilter}
- *
- * @return Unmodifiable list of {@link ResponseFilter}
- */
- List getResponseFilters();
-
- /**
- * Return the list of {@link java.io.IOException}
- *
- * @return Unmodifiable list of {@link java.io.IOException}
- */
- List getIoExceptionFilters();
-
- /**
- * Return cookie store that is used to store and retrieve cookies
- *
- * @return {@link CookieStore} object
- */
- CookieStore getCookieStore();
-
- /**
- * Return the delay in milliseconds to evict expired cookies from {@linkplain CookieStore}
- *
- * @return the delay in milliseconds to evict expired cookies from {@linkplain CookieStore}
- */
- int expiredCookieEvictionDelay();
-
- /**
- * Return the number of time the library will retry when an {@link java.io.IOException} is throw by the remote server
- *
- * @return the number of time the library will retry when an {@link java.io.IOException} is throw by the remote server
- */
- int getMaxRequestRetry();
-
- /**
- * @return the disableUrlEncodingForBoundRequests
- */
- boolean isDisableUrlEncodingForBoundRequests();
-
- /**
- * @return true if AHC is to use a LAX cookie encoder, eg accept illegal chars in cookie value
- */
- boolean isUseLaxCookieEncoder();
-
- /**
- * In the case of a POST/Redirect/Get scenario where the server uses a 302 for the redirect, should AHC respond to the redirect with a GET or whatever the original method was.
- * Unless configured otherwise, for a 302, AHC, will use a GET for this case.
- *
- * @return true
if strict 302 handling is to be used, otherwise false
.
- */
- boolean isStrict302Handling();
+ /**
+ * @return the version of AHC
+ */
+ String getAhcVersion();
+
+ /**
+ * Return the name of {@link AsyncHttpClient}, which is used for thread naming and debugging.
+ *
+ * @return the name.
+ */
+ String getThreadPoolName();
+
+ /**
+ * Return the maximum number of connections an {@link AsyncHttpClient} can handle.
+ *
+ * @return the maximum number of connections an {@link AsyncHttpClient} can handle.
+ */
+ int getMaxConnections();
+
+ /**
+ * Return the maximum number of connections per hosts an {@link AsyncHttpClient} can handle.
+ *
+ * @return the maximum number of connections per host an {@link AsyncHttpClient} can handle.
+ */
+ int getMaxConnectionsPerHost();
+
+ /**
+ * Return the maximum duration in milliseconds an {@link AsyncHttpClient} can wait to acquire a free channel
+ *
+ * @return Return the maximum duration in milliseconds an {@link AsyncHttpClient} can wait to acquire a free channel
+ */
+ int getAcquireFreeChannelTimeout();
+
+
+ /**
+ * Return the maximum time in millisecond an {@link AsyncHttpClient} can wait when connecting to a remote host
+ *
+ * @return the maximum time in millisecond an {@link AsyncHttpClient} can wait when connecting to a remote host
+ */
+ int getConnectTimeout();
+
+ /**
+ * Return the maximum time in millisecond an {@link AsyncHttpClient} can stay idle.
+ *
+ * @return the maximum time in millisecond an {@link AsyncHttpClient} can stay idle.
+ */
+ int getReadTimeout();
+
+ /**
+ * Return the maximum time in millisecond an {@link AsyncHttpClient} will keep connection in pool.
+ *
+ * @return the maximum time in millisecond an {@link AsyncHttpClient} will keep connection in pool.
+ */
+ int getPooledConnectionIdleTimeout();
+
+ /**
+ * @return the period in millis to clean the pool of dead and idle connections.
+ */
+ int getConnectionPoolCleanerPeriod();
+
+ /**
+ * Return the maximum time in millisecond an {@link AsyncHttpClient} waits until the response is completed.
+ *
+ * @return the maximum time in millisecond an {@link AsyncHttpClient} waits until the response is completed.
+ */
+ int getRequestTimeout();
+
+ /**
+ * Is HTTP redirect enabled
+ *
+ * @return true if enabled.
+ */
+ boolean isFollowRedirect();
+
+ /**
+ * Get the maximum number of HTTP redirect
+ *
+ * @return the maximum number of HTTP redirect
+ */
+ int getMaxRedirects();
+
+ /**
+ * Is the {@link ChannelPool} support enabled.
+ *
+ * @return true if keep-alive is enabled
+ */
+ boolean isKeepAlive();
+
+ /**
+ * Return the USER_AGENT header value
+ *
+ * @return the USER_AGENT header value
+ */
+ String getUserAgent();
+
+ /**
+ * Is HTTP compression enforced.
+ *
+ * @return true if compression is enforced
+ */
+ boolean isCompressionEnforced();
+
+ /**
+ * Return the {@link ThreadFactory} an {@link AsyncHttpClient} use for handling asynchronous response.
+ *
+ * @return the {@link ThreadFactory} an {@link AsyncHttpClient} use for handling asynchronous response. If no {@link ThreadFactory} has been explicitly
+ * provided, this method will return {@code null}
+ */
+ ThreadFactory getThreadFactory();
+
+ /**
+ * An instance of {@link ProxyServer} used by an {@link AsyncHttpClient}
+ *
+ * @return instance of {@link ProxyServer}
+ */
+ ProxyServerSelector getProxyServerSelector();
+
+ /**
+ * Return an instance of {@link SslContext} used for SSL connection.
+ *
+ * @return an instance of {@link SslContext} used for SSL connection.
+ */
+ SslContext getSslContext();
+
+ /**
+ * Return the current {@link Realm}
+ *
+ * @return the current {@link Realm}
+ */
+ Realm getRealm();
+
+ /**
+ * Return the list of {@link RequestFilter}
+ *
+ * @return Unmodifiable list of {@link RequestFilter}
+ */
+ List getRequestFilters();
+
+ /**
+ * Return the list of {@link ResponseFilter}
+ *
+ * @return Unmodifiable list of {@link ResponseFilter}
+ */
+ List getResponseFilters();
+
+ /**
+ * Return the list of {@link IOException}
+ *
+ * @return Unmodifiable list of {@link IOException}
+ */
+ List getIoExceptionFilters();
+
+ /**
+ * Return cookie store that is used to store and retrieve cookies
+ *
+ * @return {@link CookieStore} object
+ */
+ CookieStore getCookieStore();
+
+ /**
+ * Return the delay in milliseconds to evict expired cookies from {@linkplain CookieStore}
+ *
+ * @return the delay in milliseconds to evict expired cookies from {@linkplain CookieStore}
+ */
+ int expiredCookieEvictionDelay();
+
+ /**
+ * Return the number of time the library will retry when an {@link IOException} is throw by the remote server
+ *
+ * @return the number of time the library will retry when an {@link IOException} is throw by the remote server
+ */
+ int getMaxRequestRetry();
+
+ /**
+ * @return the disableUrlEncodingForBoundRequests
+ */
+ boolean isDisableUrlEncodingForBoundRequests();
+
+ /**
+ * @return true if AHC is to use a LAX cookie encoder, eg accept illegal chars in cookie value
+ */
+ boolean isUseLaxCookieEncoder();
+
+ /**
+ * In the case of a POST/Redirect/Get scenario where the server uses a 302 for the redirect, should AHC respond to the redirect with a GET or whatever the original method was.
+ * Unless configured otherwise, for a 302, AHC, will use a GET for this case.
+ *
+ * @return true
if strict 302 handling is to be used, otherwise {@code false}.
+ */
+ boolean isStrict302Handling();
+
+ /**
+ * @return the maximum time in millisecond an {@link AsyncHttpClient} will keep connection in the pool, or -1 to keep connection while possible.
+ */
+ int getConnectionTtl();
- /**
- * @return the maximum time in millisecond an {@link AsyncHttpClient} will keep connection in the pool, or -1 to keep connection while possible.
- */
- int getConnectionTtl();
+ boolean isUseOpenSsl();
- boolean isUseOpenSsl();
+ boolean isUseInsecureTrustManager();
- boolean isUseInsecureTrustManager();
+ /**
+ * @return true to disable all HTTPS behaviors AT ONCE, such as hostname verification and SNI
+ */
+ boolean isDisableHttpsEndpointIdentificationAlgorithm();
- /**
- * @return true to disable all HTTPS behaviors AT ONCE, such as hostname verification and SNI
- */
- boolean isDisableHttpsEndpointIdentificationAlgorithm();
+ /**
+ * @return the array of enabled protocols
+ */
+ String[] getEnabledProtocols();
- /**
- * @return the array of enabled protocols
- */
- String[] getEnabledProtocols();
+ /**
+ * @return the array of enabled cipher suites
+ */
+ String[] getEnabledCipherSuites();
- /**
- * @return the array of enabled cipher suites
- */
- String[] getEnabledCipherSuites();
+ /**
+ * @return if insecure cipher suites must be filtered out (only used when not explicitly passing enabled cipher suites)
+ */
+ boolean isFilterInsecureCipherSuites();
- /**
- * @return if insecure cipher suites must be filtered out (only used when not explicitly passing enabled cipher suites)
- */
- boolean isFilterInsecureCipherSuites();
+ /**
+ * @return the size of the SSL session cache, 0 means using the default value
+ */
+ int getSslSessionCacheSize();
- /**
- * @return the size of the SSL session cache, 0 means using the default value
- */
- int getSslSessionCacheSize();
+ /**
+ * @return the SSL session timeout in seconds, 0 means using the default value
+ */
+ int getSslSessionTimeout();
- /**
- * @return the SSL session timeout in seconds, 0 means using the default value
- */
- int getSslSessionTimeout();
+ int getHttpClientCodecMaxInitialLineLength();
- int getHttpClientCodecMaxInitialLineLength();
+ int getHttpClientCodecMaxHeaderSize();
- int getHttpClientCodecMaxHeaderSize();
+ int getHttpClientCodecMaxChunkSize();
- int getHttpClientCodecMaxChunkSize();
+ int getHttpClientCodecInitialBufferSize();
- int getHttpClientCodecInitialBufferSize();
+ boolean isDisableZeroCopy();
- boolean isDisableZeroCopy();
+ int getHandshakeTimeout();
- int getHandshakeTimeout();
+ SslEngineFactory getSslEngineFactory();
- SslEngineFactory getSslEngineFactory();
+ int getChunkedFileChunkSize();
- int getChunkedFileChunkSize();
+ int getWebSocketMaxBufferSize();
- int getWebSocketMaxBufferSize();
+ int getWebSocketMaxFrameSize();
- int getWebSocketMaxFrameSize();
+ boolean isKeepEncodingHeader();
- boolean isKeepEncodingHeader();
+ int getShutdownQuietPeriod();
- int getShutdownQuietPeriod();
+ int getShutdownTimeout();
- int getShutdownTimeout();
+ Map, Object> getChannelOptions();
- Map, Object> getChannelOptions();
+ EventLoopGroup getEventLoopGroup();
- EventLoopGroup getEventLoopGroup();
+ boolean isUseNativeTransport();
- boolean isUseNativeTransport();
+ boolean isUseOnlyEpollNativeTransport();
- Consumer getHttpAdditionalChannelInitializer();
+ Consumer getHttpAdditionalChannelInitializer();
- Consumer getWsAdditionalChannelInitializer();
+ Consumer getWsAdditionalChannelInitializer();
- ResponseBodyPartFactory getResponseBodyPartFactory();
+ ResponseBodyPartFactory getResponseBodyPartFactory();
- ChannelPool getChannelPool();
+ ChannelPool getChannelPool();
- ConnectionSemaphoreFactory getConnectionSemaphoreFactory();
+ ConnectionSemaphoreFactory getConnectionSemaphoreFactory();
- Timer getNettyTimer();
+ Timer getNettyTimer();
- /**
- * @return the duration between tick of {@link io.netty.util.HashedWheelTimer}
- */
- long getHashedWheelTimerTickDuration();
+ /**
+ * @return the duration between tick of {@link HashedWheelTimer}
+ */
+ long getHashedWheelTimerTickDuration();
- /**
- * @return the size of the hashed wheel {@link io.netty.util.HashedWheelTimer}
- */
- int getHashedWheelTimerSize();
+ /**
+ * @return the size of the hashed wheel {@link HashedWheelTimer}
+ */
+ int getHashedWheelTimerSize();
- KeepAliveStrategy getKeepAliveStrategy();
+ KeepAliveStrategy getKeepAliveStrategy();
- boolean isValidateResponseHeaders();
+ boolean isValidateResponseHeaders();
- boolean isAggregateWebSocketFrameFragments();
+ boolean isAggregateWebSocketFrameFragments();
- boolean isEnableWebSocketCompression();
+ boolean isEnableWebSocketCompression();
- boolean isTcpNoDelay();
+ boolean isTcpNoDelay();
- boolean isSoReuseAddress();
+ boolean isSoReuseAddress();
- boolean isSoKeepAlive();
+ boolean isSoKeepAlive();
- int getSoLinger();
+ int getSoLinger();
- int getSoSndBuf();
+ int getSoSndBuf();
- int getSoRcvBuf();
+ int getSoRcvBuf();
- ByteBufAllocator getAllocator();
+ ByteBufAllocator getAllocator();
- int getIoThreadsCount();
+ int getIoThreadsCount();
- enum ResponseBodyPartFactory {
+ enum ResponseBodyPartFactory {
- EAGER {
- @Override
- public HttpResponseBodyPart newResponseBodyPart(ByteBuf buf, boolean last) {
- return new EagerResponseBodyPart(buf, last);
- }
- },
+ EAGER {
+ @Override
+ public HttpResponseBodyPart newResponseBodyPart(ByteBuf buf, boolean last) {
+ return new EagerResponseBodyPart(buf, last);
+ }
+ },
- LAZY {
- @Override
- public HttpResponseBodyPart newResponseBodyPart(ByteBuf buf, boolean last) {
- return new LazyResponseBodyPart(buf, last);
- }
- };
+ LAZY {
+ @Override
+ public HttpResponseBodyPart newResponseBodyPart(ByteBuf buf, boolean last) {
+ return new LazyResponseBodyPart(buf, last);
+ }
+ };
- public abstract HttpResponseBodyPart newResponseBodyPart(ByteBuf buf, boolean last);
- }
+ public abstract HttpResponseBodyPart newResponseBodyPart(ByteBuf buf, boolean last);
+ }
}
diff --git a/client/src/main/java/org/asynchttpclient/AsyncHttpClientState.java b/client/src/main/java/org/asynchttpclient/AsyncHttpClientState.java
index 1fcc3ed8bf..5916d69f0c 100644
--- a/client/src/main/java/org/asynchttpclient/AsyncHttpClientState.java
+++ b/client/src/main/java/org/asynchttpclient/AsyncHttpClientState.java
@@ -1,15 +1,17 @@
/*
- * Copyright (c) 2016 AsyncHttpClient Project. All rights reserved.
+ * Copyright (c) 2016-2023 AsyncHttpClient Project. All rights reserved.
*
- * This program is licensed to you under the Apache License Version 2.0,
- * and you may not use this file except in compliance with the Apache License Version 2.0.
- * You may obtain a copy of the Apache License Version 2.0 at
- * http://www.apache.org/licenses/LICENSE-2.0.
+ * 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
*
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the Apache License Version 2.0 is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the Apache License Version 2.0 for the specific language governing permissions and limitations there under.
+ * 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 org.asynchttpclient;
@@ -17,13 +19,13 @@
public class AsyncHttpClientState {
- private final AtomicBoolean closed;
+ private final AtomicBoolean closed;
- AsyncHttpClientState(AtomicBoolean closed) {
- this.closed = closed;
- }
+ AsyncHttpClientState(AtomicBoolean closed) {
+ this.closed = closed;
+ }
- public boolean isClosed() {
- return closed.get();
- }
+ public boolean isClosed() {
+ return closed.get();
+ }
}
diff --git a/client/src/main/java/org/asynchttpclient/BoundRequestBuilder.java b/client/src/main/java/org/asynchttpclient/BoundRequestBuilder.java
index d82d9b02ad..c2e2bce29b 100644
--- a/client/src/main/java/org/asynchttpclient/BoundRequestBuilder.java
+++ b/client/src/main/java/org/asynchttpclient/BoundRequestBuilder.java
@@ -1,41 +1,44 @@
/*
- * Copyright (c) 2014 AsyncHttpClient Project. All rights reserved.
+ * Copyright (c) 2014-2023 AsyncHttpClient Project. All rights reserved.
*
- * This program is licensed to you under the Apache License Version 2.0,
- * and you may not use this file except in compliance with the Apache License Version 2.0.
- * You may obtain a copy of the Apache License Version 2.0 at http://www.apache.org/licenses/LICENSE-2.0.
+ * 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
*
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the Apache License Version 2.0 is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the Apache License Version 2.0 for the specific language governing permissions and limitations there under.
+ * 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 org.asynchttpclient;
public class BoundRequestBuilder extends RequestBuilderBase {
- private final AsyncHttpClient client;
+ private final AsyncHttpClient client;
- public BoundRequestBuilder(AsyncHttpClient client, String method, boolean isDisableUrlEncoding, boolean validateHeaders) {
- super(method, isDisableUrlEncoding, validateHeaders);
- this.client = client;
- }
+ public BoundRequestBuilder(AsyncHttpClient client, String method, boolean isDisableUrlEncoding, boolean validateHeaders) {
+ super(method, isDisableUrlEncoding, validateHeaders);
+ this.client = client;
+ }
- public BoundRequestBuilder(AsyncHttpClient client, String method, boolean isDisableUrlEncoding) {
- super(method, isDisableUrlEncoding);
- this.client = client;
- }
+ public BoundRequestBuilder(AsyncHttpClient client, String method, boolean isDisableUrlEncoding) {
+ super(method, isDisableUrlEncoding);
+ this.client = client;
+ }
- public BoundRequestBuilder(AsyncHttpClient client, Request prototype) {
- super(prototype);
- this.client = client;
- }
+ public BoundRequestBuilder(AsyncHttpClient client, Request prototype) {
+ super(prototype);
+ this.client = client;
+ }
- public ListenableFuture execute(AsyncHandler handler) {
- return client.executeRequest(build(), handler);
- }
+ public ListenableFuture execute(AsyncHandler handler) {
+ return client.executeRequest(build(), handler);
+ }
- public ListenableFuture execute() {
- return client.executeRequest(build(), new AsyncCompletionHandlerBase());
- }
+ public ListenableFuture execute() {
+ return client.executeRequest(build(), new AsyncCompletionHandlerBase());
+ }
}
diff --git a/client/src/main/java/org/asynchttpclient/ClientStats.java b/client/src/main/java/org/asynchttpclient/ClientStats.java
index 9f44604c25..28cb0b2930 100644
--- a/client/src/main/java/org/asynchttpclient/ClientStats.java
+++ b/client/src/main/java/org/asynchttpclient/ClientStats.java
@@ -1,15 +1,17 @@
/*
- * Copyright (c) 2014 AsyncHttpClient Project. All rights reserved.
+ * Copyright (c) 2014-2023 AsyncHttpClient Project. All rights reserved.
*
- * This program is licensed to you under the Apache License Version 2.0,
- * and you may not use this file except in compliance with the Apache License Version 2.0.
- * You may obtain a copy of the Apache License Version 2.0 at
- * http://www.apache.org/licenses/LICENSE-2.0.
+ * 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
*
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the Apache License Version 2.0 is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the Apache License Version 2.0 for the specific language governing permissions and limitations there under.
+ * 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 org.asynchttpclient;
@@ -22,71 +24,75 @@
*/
public class ClientStats {
- private final Map statsPerHost;
+ private final Map statsPerHost;
- public ClientStats(Map statsPerHost) {
- this.statsPerHost = Collections.unmodifiableMap(statsPerHost);
- }
+ public ClientStats(Map statsPerHost) {
+ this.statsPerHost = Collections.unmodifiableMap(statsPerHost);
+ }
- /**
- * @return A map from hostname to statistics on that host's connections.
- * The returned map is unmodifiable.
- */
- public Map getStatsPerHost() {
- return statsPerHost;
- }
+ /**
+ * @return A map from hostname to statistics on that host's connections.
+ * The returned map is unmodifiable.
+ */
+ public Map getStatsPerHost() {
+ return statsPerHost;
+ }
- /**
- * @return The sum of {@link #getTotalActiveConnectionCount()} and {@link #getTotalIdleConnectionCount()},
- * a long representing the total number of connections in the connection pool.
- */
- public long getTotalConnectionCount() {
- return statsPerHost
- .values()
- .stream()
- .mapToLong(HostStats::getHostConnectionCount)
- .sum();
- }
+ /**
+ * @return The sum of {@link #getTotalActiveConnectionCount()} and {@link #getTotalIdleConnectionCount()},
+ * a long representing the total number of connections in the connection pool.
+ */
+ public long getTotalConnectionCount() {
+ return statsPerHost
+ .values()
+ .stream()
+ .mapToLong(HostStats::getHostConnectionCount)
+ .sum();
+ }
- /**
- * @return A long representing the number of active connections in the connection pool.
- */
- public long getTotalActiveConnectionCount() {
- return statsPerHost
- .values()
- .stream()
- .mapToLong(HostStats::getHostActiveConnectionCount)
- .sum();
- }
+ /**
+ * @return A long representing the number of active connections in the connection pool.
+ */
+ public long getTotalActiveConnectionCount() {
+ return statsPerHost
+ .values()
+ .stream()
+ .mapToLong(HostStats::getHostActiveConnectionCount)
+ .sum();
+ }
- /**
- * @return A long representing the number of idle connections in the connection pool.
- */
- public long getTotalIdleConnectionCount() {
- return statsPerHost
- .values()
- .stream()
- .mapToLong(HostStats::getHostIdleConnectionCount)
- .sum();
- }
+ /**
+ * @return A long representing the number of idle connections in the connection pool.
+ */
+ public long getTotalIdleConnectionCount() {
+ return statsPerHost
+ .values()
+ .stream()
+ .mapToLong(HostStats::getHostIdleConnectionCount)
+ .sum();
+ }
- @Override
- public String toString() {
- return "There are " + getTotalConnectionCount() +
- " total connections, " + getTotalActiveConnectionCount() +
- " are active and " + getTotalIdleConnectionCount() + " are idle.";
- }
+ @Override
+ public String toString() {
+ return "There are " + getTotalConnectionCount() +
+ " total connections, " + getTotalActiveConnectionCount() +
+ " are active and " + getTotalIdleConnectionCount() + " are idle.";
+ }
- @Override
- public boolean equals(final Object o) {
- if (this == o) return true;
- if (o == null || getClass() != o.getClass()) return false;
- final ClientStats that = (ClientStats) o;
- return Objects.equals(statsPerHost, that.statsPerHost);
- }
+ @Override
+ public boolean equals(final Object o) {
+ if (this == o) {
+ return true;
+ }
+ if (o == null || getClass() != o.getClass()) {
+ return false;
+ }
+ final ClientStats that = (ClientStats) o;
+ return Objects.equals(statsPerHost, that.statsPerHost);
+ }
- @Override
- public int hashCode() {
- return Objects.hashCode(statsPerHost);
- }
+ @Override
+ public int hashCode() {
+ return Objects.hashCode(statsPerHost);
+ }
}
diff --git a/client/src/main/java/org/asynchttpclient/DefaultAsyncHttpClient.java b/client/src/main/java/org/asynchttpclient/DefaultAsyncHttpClient.java
index 7cc3e6e341..24e2224a69 100644
--- a/client/src/main/java/org/asynchttpclient/DefaultAsyncHttpClient.java
+++ b/client/src/main/java/org/asynchttpclient/DefaultAsyncHttpClient.java
@@ -46,278 +46,283 @@
*/
public class DefaultAsyncHttpClient implements AsyncHttpClient {
- private final static Logger LOGGER = LoggerFactory.getLogger(DefaultAsyncHttpClient.class);
- private final AsyncHttpClientConfig config;
- private final boolean noRequestFilters;
- private final AtomicBoolean closed = new AtomicBoolean(false);
- private final ChannelManager channelManager;
- private final NettyRequestSender requestSender;
- private final boolean allowStopNettyTimer;
- private final Timer nettyTimer;
-
- /**
- * Default signature calculator to use for all requests constructed by this
- * client instance.
- */
- private SignatureCalculator signatureCalculator;
-
- /**
- * Create a new HTTP Asynchronous Client using the default
- * {@link DefaultAsyncHttpClientConfig} configuration. The default
- * {@link AsyncHttpClient} that will be used will be based on the classpath
- * configuration.
- *
- * If none of those providers are found, then the engine will throw an
- * IllegalStateException.
- */
- public DefaultAsyncHttpClient() {
- this(new DefaultAsyncHttpClientConfig.Builder().build());
- }
-
- /**
- * Create a new HTTP Asynchronous Client using the specified
- * {@link DefaultAsyncHttpClientConfig} configuration. This configuration
- * will be passed to the default {@link AsyncHttpClient} that will be
- * selected based on the classpath configuration.
- *
- * @param config a {@link DefaultAsyncHttpClientConfig}
- */
- public DefaultAsyncHttpClient(AsyncHttpClientConfig config) {
-
- this.config = config;
- this.noRequestFilters = config.getRequestFilters().isEmpty();
- allowStopNettyTimer = config.getNettyTimer() == null;
- nettyTimer = allowStopNettyTimer ? newNettyTimer(config) : config.getNettyTimer();
-
- channelManager = new ChannelManager(config, nettyTimer);
- requestSender = new NettyRequestSender(config, channelManager, nettyTimer, new AsyncHttpClientState(closed));
- channelManager.configureBootstraps(requestSender);
-
- CookieStore cookieStore = config.getCookieStore();
- if (cookieStore != null) {
- int cookieStoreCount = config.getCookieStore().incrementAndGet();
- if (
- allowStopNettyTimer // timer is not shared
- || cookieStoreCount == 1 // this is the first AHC instance for the shared (user-provided) timer
- ) {
- nettyTimer.newTimeout(new CookieEvictionTask(config.expiredCookieEvictionDelay(), cookieStore),
- config.expiredCookieEvictionDelay(), TimeUnit.MILLISECONDS);
- }
- }
- }
-
- private Timer newNettyTimer(AsyncHttpClientConfig config) {
- ThreadFactory threadFactory = config.getThreadFactory() != null ? config.getThreadFactory() : new DefaultThreadFactory(config.getThreadPoolName() + "-timer");
- HashedWheelTimer timer = new HashedWheelTimer(threadFactory, config.getHashedWheelTimerTickDuration(), TimeUnit.MILLISECONDS, config.getHashedWheelTimerSize());
- timer.start();
- return timer;
- }
-
- @Override
- public void close() {
- if (closed.compareAndSet(false, true)) {
- try {
- channelManager.close();
- } catch (Throwable t) {
- LOGGER.warn("Unexpected error on ChannelManager close", t);
- }
- CookieStore cookieStore = config.getCookieStore();
- if (cookieStore != null) {
- cookieStore.decrementAndGet();
- }
- if (allowStopNettyTimer) {
+ private static final Logger LOGGER = LoggerFactory.getLogger(DefaultAsyncHttpClient.class);
+ private final AsyncHttpClientConfig config;
+ private final boolean noRequestFilters;
+ private final AtomicBoolean closed = new AtomicBoolean(false);
+ private final ChannelManager channelManager;
+ private final NettyRequestSender requestSender;
+ private final boolean allowStopNettyTimer;
+ private final Timer nettyTimer;
+
+ /**
+ * Default signature calculator to use for all requests constructed by this
+ * client instance.
+ */
+ private SignatureCalculator signatureCalculator;
+
+ /**
+ * Create a new HTTP Asynchronous Client using the default
+ * {@link DefaultAsyncHttpClientConfig} configuration. The default
+ * {@link AsyncHttpClient} that will be used will be based on the classpath
+ * configuration.
+ *
+ * If none of those providers are found, then the engine will throw an
+ * IllegalStateException.
+ */
+ public DefaultAsyncHttpClient() {
+ this(new DefaultAsyncHttpClientConfig.Builder().build());
+ }
+
+ /**
+ * Create a new HTTP Asynchronous Client using the specified
+ * {@link DefaultAsyncHttpClientConfig} configuration. This configuration
+ * will be passed to the default {@link AsyncHttpClient} that will be
+ * selected based on the classpath configuration.
+ *
+ * @param config a {@link DefaultAsyncHttpClientConfig}
+ */
+ public DefaultAsyncHttpClient(AsyncHttpClientConfig config) {
+
+ this.config = config;
+ noRequestFilters = config.getRequestFilters().isEmpty();
+ allowStopNettyTimer = config.getNettyTimer() == null;
+ nettyTimer = allowStopNettyTimer ? newNettyTimer(config) : config.getNettyTimer();
+
+ channelManager = new ChannelManager(config, nettyTimer);
+ requestSender = new NettyRequestSender(config, channelManager, nettyTimer, new AsyncHttpClientState(closed));
+ channelManager.configureBootstraps(requestSender);
+
+ CookieStore cookieStore = config.getCookieStore();
+ if (cookieStore != null) {
+ int cookieStoreCount = config.getCookieStore().incrementAndGet();
+ if (
+ allowStopNettyTimer // timer is not shared
+ || cookieStoreCount == 1 // this is the first AHC instance for the shared (user-provided) timer
+ ) {
+ nettyTimer.newTimeout(new CookieEvictionTask(config.expiredCookieEvictionDelay(), cookieStore),
+ config.expiredCookieEvictionDelay(), TimeUnit.MILLISECONDS);
+ }
+ }
+ }
+
+ // Visible for testing
+ ChannelManager channelManager() {
+ return channelManager;
+ }
+
+ private static Timer newNettyTimer(AsyncHttpClientConfig config) {
+ ThreadFactory threadFactory = config.getThreadFactory() != null ? config.getThreadFactory() : new DefaultThreadFactory(config.getThreadPoolName() + "-timer");
+ HashedWheelTimer timer = new HashedWheelTimer(threadFactory, config.getHashedWheelTimerTickDuration(), TimeUnit.MILLISECONDS, config.getHashedWheelTimerSize());
+ timer.start();
+ return timer;
+ }
+
+ @Override
+ public void close() {
+ if (closed.compareAndSet(false, true)) {
+ try {
+ channelManager.close();
+ } catch (Throwable t) {
+ LOGGER.warn("Unexpected error on ChannelManager close", t);
+ }
+ CookieStore cookieStore = config.getCookieStore();
+ if (cookieStore != null) {
+ cookieStore.decrementAndGet();
+ }
+ if (allowStopNettyTimer) {
+ try {
+ nettyTimer.stop();
+ } catch (Throwable t) {
+ LOGGER.warn("Unexpected error on HashedWheelTimer close", t);
+ }
+ }
+ }
+ }
+
+ @Override
+ public boolean isClosed() {
+ return closed.get();
+ }
+
+ @Override
+ public DefaultAsyncHttpClient setSignatureCalculator(SignatureCalculator signatureCalculator) {
+ this.signatureCalculator = signatureCalculator;
+ return this;
+ }
+
+ @Override
+ public BoundRequestBuilder prepare(String method, String url) {
+ return requestBuilder(method, url);
+ }
+
+ @Override
+ public BoundRequestBuilder prepareGet(String url) {
+ return requestBuilder("GET", url);
+ }
+
+ @Override
+ public BoundRequestBuilder prepareConnect(String url) {
+ return requestBuilder("CONNECT", url);
+ }
+
+ @Override
+ public BoundRequestBuilder prepareOptions(String url) {
+ return requestBuilder("OPTIONS", url);
+ }
+
+ @Override
+ public BoundRequestBuilder prepareHead(String url) {
+ return requestBuilder("HEAD", url);
+ }
+
+ @Override
+ public BoundRequestBuilder preparePost(String url) {
+ return requestBuilder("POST", url);
+ }
+
+ @Override
+ public BoundRequestBuilder preparePut(String url) {
+ return requestBuilder("PUT", url);
+ }
+
+ @Override
+ public BoundRequestBuilder prepareDelete(String url) {
+ return requestBuilder("DELETE", url);
+ }
+
+ @Override
+ public BoundRequestBuilder preparePatch(String url) {
+ return requestBuilder("PATCH", url);
+ }
+
+ @Override
+ public BoundRequestBuilder prepareTrace(String url) {
+ return requestBuilder("TRACE", url);
+ }
+
+ @Override
+ public BoundRequestBuilder prepareRequest(Request request) {
+ return requestBuilder(request);
+ }
+
+ @Override
+ public BoundRequestBuilder prepareRequest(RequestBuilder requestBuilder) {
+ return prepareRequest(requestBuilder.build());
+ }
+
+ @Override
+ public ListenableFuture executeRequest(Request request, AsyncHandler handler) {
+ if (config.getCookieStore() != null) {
+ try {
+ List cookies = config.getCookieStore().get(request.getUri());
+ if (!cookies.isEmpty()) {
+ RequestBuilder requestBuilder = request.toBuilder();
+ for (Cookie cookie : cookies) {
+ requestBuilder.addOrReplaceCookie(cookie);
+ }
+ request = requestBuilder.build();
+ }
+ } catch (Exception e) {
+ handler.onThrowable(e);
+ return new ListenableFuture.CompletedFailure<>("Failed to set cookies of request", e);
+ }
+ }
+
+ if (noRequestFilters) {
+ return execute(request, handler);
+ } else {
+ FilterContext fc = new FilterContext.FilterContextBuilder().asyncHandler(handler).request(request).build();
+ try {
+ fc = preProcessRequest(fc);
+ } catch (Exception e) {
+ handler.onThrowable(e);
+ return new ListenableFuture.CompletedFailure<>("preProcessRequest failed", e);
+ }
+
+ return execute(fc.getRequest(), fc.getAsyncHandler());
+ }
+ }
+
+ @Override
+ public ListenableFuture executeRequest(RequestBuilder requestBuilder, AsyncHandler handler) {
+ return executeRequest(requestBuilder.build(), handler);
+ }
+
+ @Override
+ public ListenableFuture executeRequest(Request request) {
+ return executeRequest(request, new AsyncCompletionHandlerBase());
+ }
+
+ @Override
+ public ListenableFuture executeRequest(RequestBuilder requestBuilder) {
+ return executeRequest(requestBuilder.build());
+ }
+
+ private ListenableFuture execute(Request request, final AsyncHandler asyncHandler) {
try {
- nettyTimer.stop();
- } catch (Throwable t) {
- LOGGER.warn("Unexpected error on HashedWheelTimer close", t);
+ return requestSender.sendRequest(request, asyncHandler, null);
+ } catch (Exception e) {
+ asyncHandler.onThrowable(e);
+ return new ListenableFuture.CompletedFailure<>(e);
+ }
+ }
+
+ /**
+ * Configure and execute the associated {@link RequestFilter}. This class
+ * may decorate the {@link Request} and {@link AsyncHandler}
+ *
+ * @param fc {@link FilterContext}
+ * @return {@link FilterContext}
+ */
+ private FilterContext preProcessRequest(FilterContext fc) throws FilterException {
+ for (RequestFilter asyncFilter : config.getRequestFilters()) {
+ fc = asyncFilter.filter(fc);
+ assertNotNull(fc, "filterContext");
}
- }
- }
- }
-
- @Override
- public boolean isClosed() {
- return closed.get();
- }
-
- @Override
- public DefaultAsyncHttpClient setSignatureCalculator(SignatureCalculator signatureCalculator) {
- this.signatureCalculator = signatureCalculator;
- return this;
- }
-
- @Override
- public BoundRequestBuilder prepare(String method, String url) {
- return requestBuilder(method, url);
- }
-
- @Override
- public BoundRequestBuilder prepareGet(String url) {
- return requestBuilder("GET", url);
- }
-
- @Override
- public BoundRequestBuilder prepareConnect(String url) {
- return requestBuilder("CONNECT", url);
- }
-
- @Override
- public BoundRequestBuilder prepareOptions(String url) {
- return requestBuilder("OPTIONS", url);
- }
-
- @Override
- public BoundRequestBuilder prepareHead(String url) {
- return requestBuilder("HEAD", url);
- }
-
- @Override
- public BoundRequestBuilder preparePost(String url) {
- return requestBuilder("POST", url);
- }
-
- @Override
- public BoundRequestBuilder preparePut(String url) {
- return requestBuilder("PUT", url);
- }
-
- @Override
- public BoundRequestBuilder prepareDelete(String url) {
- return requestBuilder("DELETE", url);
- }
-
- @Override
- public BoundRequestBuilder preparePatch(String url) {
- return requestBuilder("PATCH", url);
- }
-
- @Override
- public BoundRequestBuilder prepareTrace(String url) {
- return requestBuilder("TRACE", url);
- }
-
- @Override
- public BoundRequestBuilder prepareRequest(Request request) {
- return requestBuilder(request);
- }
-
- @Override
- public BoundRequestBuilder prepareRequest(RequestBuilder requestBuilder) {
- return prepareRequest(requestBuilder.build());
- }
-
- @Override
- public ListenableFuture executeRequest(Request request, AsyncHandler handler) {
- if (config.getCookieStore() != null) {
- try {
- List cookies = config.getCookieStore().get(request.getUri());
- if (!cookies.isEmpty()) {
- RequestBuilder requestBuilder = request.toBuilder();
- for (Cookie cookie : cookies) {
- requestBuilder.addOrReplaceCookie(cookie);
- }
- request = requestBuilder.build();
+
+ Request request = fc.getRequest();
+ if (fc.getAsyncHandler() instanceof ResumableAsyncHandler) {
+ request = ((ResumableAsyncHandler) fc.getAsyncHandler()).adjustRequestRange(request);
+ }
+
+ if (request.getRangeOffset() != 0) {
+ RequestBuilder builder = request.toBuilder();
+ builder.setHeader("Range", "bytes=" + request.getRangeOffset() + '-');
+ request = builder.build();
}
- } catch (Exception e) {
- handler.onThrowable(e);
- return new ListenableFuture.CompletedFailure<>("Failed to set cookies of request", e);
- }
- }
-
- if (noRequestFilters) {
- return execute(request, handler);
- } else {
- FilterContext fc = new FilterContext.FilterContextBuilder().asyncHandler(handler).request(request).build();
- try {
- fc = preProcessRequest(fc);
- } catch (Exception e) {
- handler.onThrowable(e);
- return new ListenableFuture.CompletedFailure<>("preProcessRequest failed", e);
- }
-
- return execute(fc.getRequest(), fc.getAsyncHandler());
- }
- }
-
- @Override
- public ListenableFuture executeRequest(RequestBuilder requestBuilder, AsyncHandler handler) {
- return executeRequest(requestBuilder.build(), handler);
- }
-
- @Override
- public ListenableFuture executeRequest(Request request) {
- return executeRequest(request, new AsyncCompletionHandlerBase());
- }
-
- @Override
- public ListenableFuture executeRequest(RequestBuilder requestBuilder) {
- return executeRequest(requestBuilder.build());
- }
-
- private ListenableFuture execute(Request request, final AsyncHandler asyncHandler) {
- try {
- return requestSender.sendRequest(request, asyncHandler, null);
- } catch (Exception e) {
- asyncHandler.onThrowable(e);
- return new ListenableFuture.CompletedFailure<>(e);
- }
- }
-
- /**
- * Configure and execute the associated {@link RequestFilter}. This class
- * may decorate the {@link Request} and {@link AsyncHandler}
- *
- * @param fc {@link FilterContext}
- * @return {@link FilterContext}
- */
- private FilterContext preProcessRequest(FilterContext fc) throws FilterException {
- for (RequestFilter asyncFilter : config.getRequestFilters()) {
- fc = asyncFilter.filter(fc);
- assertNotNull(fc, "filterContext");
- }
-
- Request request = fc.getRequest();
- if (fc.getAsyncHandler() instanceof ResumableAsyncHandler) {
- request = ResumableAsyncHandler.class.cast(fc.getAsyncHandler()).adjustRequestRange(request);
- }
-
- if (request.getRangeOffset() != 0) {
- RequestBuilder builder = request.toBuilder();
- builder.setHeader("Range", "bytes=" + request.getRangeOffset() + "-");
- request = builder.build();
- }
- fc = new FilterContext.FilterContextBuilder<>(fc).request(request).build();
- return fc;
- }
-
- public ChannelPool getChannelPool() {
- return channelManager.getChannelPool();
- }
-
- public EventLoopGroup getEventLoopGroup() {
- return channelManager.getEventLoopGroup();
- }
-
- @Override
- public ClientStats getClientStats() {
- return channelManager.getClientStats();
- }
-
- @Override
- public void flushChannelPoolPartitions(Predicate predicate) {
- getChannelPool().flushPartitions(predicate);
- }
-
- protected BoundRequestBuilder requestBuilder(String method, String url) {
- return new BoundRequestBuilder(this, method, config.isDisableUrlEncodingForBoundRequests()).setUrl(url).setSignatureCalculator(signatureCalculator);
- }
-
- protected BoundRequestBuilder requestBuilder(Request prototype) {
- return new BoundRequestBuilder(this, prototype).setSignatureCalculator(signatureCalculator);
- }
-
- @Override
- public AsyncHttpClientConfig getConfig() {
- return this.config;
- }
+ fc = new FilterContext.FilterContextBuilder<>(fc).request(request).build();
+ return fc;
+ }
+
+ public ChannelPool getChannelPool() {
+ return channelManager.getChannelPool();
+ }
+
+ public EventLoopGroup getEventLoopGroup() {
+ return channelManager.getEventLoopGroup();
+ }
+
+ @Override
+ public ClientStats getClientStats() {
+ return channelManager.getClientStats();
+ }
+
+ @Override
+ public void flushChannelPoolPartitions(Predicate predicate) {
+ getChannelPool().flushPartitions(predicate);
+ }
+
+ protected BoundRequestBuilder requestBuilder(String method, String url) {
+ return new BoundRequestBuilder(this, method, config.isDisableUrlEncodingForBoundRequests()).setUrl(url).setSignatureCalculator(signatureCalculator);
+ }
+
+ protected BoundRequestBuilder requestBuilder(Request prototype) {
+ return new BoundRequestBuilder(this, prototype).setSignatureCalculator(signatureCalculator);
+ }
+
+ @Override
+ public AsyncHttpClientConfig getConfig() {
+ return config;
+ }
}
diff --git a/client/src/main/java/org/asynchttpclient/DefaultAsyncHttpClientConfig.java b/client/src/main/java/org/asynchttpclient/DefaultAsyncHttpClientConfig.java
index 0f4e62c560..ba954c1e47 100644
--- a/client/src/main/java/org/asynchttpclient/DefaultAsyncHttpClientConfig.java
+++ b/client/src/main/java/org/asynchttpclient/DefaultAsyncHttpClientConfig.java
@@ -35,11 +35,70 @@
import org.asynchttpclient.proxy.ProxyServerSelector;
import org.asynchttpclient.util.ProxyUtils;
-import java.util.*;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.LinkedList;
+import java.util.List;
+import java.util.Map;
import java.util.concurrent.ThreadFactory;
import java.util.function.Consumer;
-import static org.asynchttpclient.config.AsyncHttpClientConfigDefaults.*;
+import static org.asynchttpclient.config.AsyncHttpClientConfigDefaults.defaultAcquireFreeChannelTimeout;
+import static org.asynchttpclient.config.AsyncHttpClientConfigDefaults.defaultAggregateWebSocketFrameFragments;
+import static org.asynchttpclient.config.AsyncHttpClientConfigDefaults.defaultChunkedFileChunkSize;
+import static org.asynchttpclient.config.AsyncHttpClientConfigDefaults.defaultCompressionEnforced;
+import static org.asynchttpclient.config.AsyncHttpClientConfigDefaults.defaultConnectTimeout;
+import static org.asynchttpclient.config.AsyncHttpClientConfigDefaults.defaultConnectionPoolCleanerPeriod;
+import static org.asynchttpclient.config.AsyncHttpClientConfigDefaults.defaultConnectionTtl;
+import static org.asynchttpclient.config.AsyncHttpClientConfigDefaults.defaultDisableHttpsEndpointIdentificationAlgorithm;
+import static org.asynchttpclient.config.AsyncHttpClientConfigDefaults.defaultDisableUrlEncodingForBoundRequests;
+import static org.asynchttpclient.config.AsyncHttpClientConfigDefaults.defaultDisableZeroCopy;
+import static org.asynchttpclient.config.AsyncHttpClientConfigDefaults.defaultEnableWebSocketCompression;
+import static org.asynchttpclient.config.AsyncHttpClientConfigDefaults.defaultEnabledCipherSuites;
+import static org.asynchttpclient.config.AsyncHttpClientConfigDefaults.defaultEnabledProtocols;
+import static org.asynchttpclient.config.AsyncHttpClientConfigDefaults.defaultExpiredCookieEvictionDelay;
+import static org.asynchttpclient.config.AsyncHttpClientConfigDefaults.defaultFilterInsecureCipherSuites;
+import static org.asynchttpclient.config.AsyncHttpClientConfigDefaults.defaultFollowRedirect;
+import static org.asynchttpclient.config.AsyncHttpClientConfigDefaults.defaultHandshakeTimeout;
+import static org.asynchttpclient.config.AsyncHttpClientConfigDefaults.defaultHashedWheelTimerSize;
+import static org.asynchttpclient.config.AsyncHttpClientConfigDefaults.defaultHashedWheelTimerTickDuration;
+import static org.asynchttpclient.config.AsyncHttpClientConfigDefaults.defaultHttpClientCodecInitialBufferSize;
+import static org.asynchttpclient.config.AsyncHttpClientConfigDefaults.defaultHttpClientCodecMaxChunkSize;
+import static org.asynchttpclient.config.AsyncHttpClientConfigDefaults.defaultHttpClientCodecMaxHeaderSize;
+import static org.asynchttpclient.config.AsyncHttpClientConfigDefaults.defaultHttpClientCodecMaxInitialLineLength;
+import static org.asynchttpclient.config.AsyncHttpClientConfigDefaults.defaultIoThreadsCount;
+import static org.asynchttpclient.config.AsyncHttpClientConfigDefaults.defaultKeepAlive;
+import static org.asynchttpclient.config.AsyncHttpClientConfigDefaults.defaultKeepEncodingHeader;
+import static org.asynchttpclient.config.AsyncHttpClientConfigDefaults.defaultMaxConnections;
+import static org.asynchttpclient.config.AsyncHttpClientConfigDefaults.defaultMaxConnectionsPerHost;
+import static org.asynchttpclient.config.AsyncHttpClientConfigDefaults.defaultMaxRedirects;
+import static org.asynchttpclient.config.AsyncHttpClientConfigDefaults.defaultMaxRequestRetry;
+import static org.asynchttpclient.config.AsyncHttpClientConfigDefaults.defaultPooledConnectionIdleTimeout;
+import static org.asynchttpclient.config.AsyncHttpClientConfigDefaults.defaultReadTimeout;
+import static org.asynchttpclient.config.AsyncHttpClientConfigDefaults.defaultRequestTimeout;
+import static org.asynchttpclient.config.AsyncHttpClientConfigDefaults.defaultShutdownQuietPeriod;
+import static org.asynchttpclient.config.AsyncHttpClientConfigDefaults.defaultShutdownTimeout;
+import static org.asynchttpclient.config.AsyncHttpClientConfigDefaults.defaultSoKeepAlive;
+import static org.asynchttpclient.config.AsyncHttpClientConfigDefaults.defaultSoLinger;
+import static org.asynchttpclient.config.AsyncHttpClientConfigDefaults.defaultSoRcvBuf;
+import static org.asynchttpclient.config.AsyncHttpClientConfigDefaults.defaultSoReuseAddress;
+import static org.asynchttpclient.config.AsyncHttpClientConfigDefaults.defaultSoSndBuf;
+import static org.asynchttpclient.config.AsyncHttpClientConfigDefaults.defaultSslSessionCacheSize;
+import static org.asynchttpclient.config.AsyncHttpClientConfigDefaults.defaultSslSessionTimeout;
+import static org.asynchttpclient.config.AsyncHttpClientConfigDefaults.defaultStrict302Handling;
+import static org.asynchttpclient.config.AsyncHttpClientConfigDefaults.defaultTcpNoDelay;
+import static org.asynchttpclient.config.AsyncHttpClientConfigDefaults.defaultThreadPoolName;
+import static org.asynchttpclient.config.AsyncHttpClientConfigDefaults.defaultUseInsecureTrustManager;
+import static org.asynchttpclient.config.AsyncHttpClientConfigDefaults.defaultUseLaxCookieEncoder;
+import static org.asynchttpclient.config.AsyncHttpClientConfigDefaults.defaultUseNativeTransport;
+import static org.asynchttpclient.config.AsyncHttpClientConfigDefaults.defaultUseOnlyEpollNativeTransport;
+import static org.asynchttpclient.config.AsyncHttpClientConfigDefaults.defaultUseOpenSsl;
+import static org.asynchttpclient.config.AsyncHttpClientConfigDefaults.defaultUseProxyProperties;
+import static org.asynchttpclient.config.AsyncHttpClientConfigDefaults.defaultUseProxySelector;
+import static org.asynchttpclient.config.AsyncHttpClientConfigDefaults.defaultUserAgent;
+import static org.asynchttpclient.config.AsyncHttpClientConfigDefaults.defaultValidateResponseHeaders;
+import static org.asynchttpclient.config.AsyncHttpClientConfigDefaults.defaultWebSocketMaxBufferSize;
+import static org.asynchttpclient.config.AsyncHttpClientConfigDefaults.defaultWebSocketMaxFrameSize;
/**
* Configuration class to use with a {@link AsyncHttpClient}. System property can be also used to configure this object default behavior by doing:
@@ -49,1328 +108,1356 @@
*/
public class DefaultAsyncHttpClientConfig implements AsyncHttpClientConfig {
- // http
- private final boolean followRedirect;
- private final int maxRedirects;
- private final boolean strict302Handling;
- private final boolean compressionEnforced;
- private final String userAgent;
- private final Realm realm;
- private final int maxRequestRetry;
- private final boolean disableUrlEncodingForBoundRequests;
- private final boolean useLaxCookieEncoder;
- private final boolean disableZeroCopy;
- private final boolean keepEncodingHeader;
- private final ProxyServerSelector proxyServerSelector;
- private final boolean validateResponseHeaders;
-
- // websockets
- private final boolean aggregateWebSocketFrameFragments;
- private final boolean enablewebSocketCompression;
- private final int webSocketMaxBufferSize;
- private final int webSocketMaxFrameSize;
-
- // timeouts
- private final int connectTimeout;
- private final int requestTimeout;
- private final int readTimeout;
- private final int shutdownQuietPeriod;
- private final int shutdownTimeout;
-
- // keep-alive
- private final boolean keepAlive;
- private final int pooledConnectionIdleTimeout;
- private final int connectionPoolCleanerPeriod;
- private final int connectionTtl;
- private final int maxConnections;
- private final int maxConnectionsPerHost;
- private final int acquireFreeChannelTimeout;
- private final ChannelPool channelPool;
- private final ConnectionSemaphoreFactory connectionSemaphoreFactory;
- private final KeepAliveStrategy keepAliveStrategy;
-
- // ssl
- private final boolean useOpenSsl;
- private final boolean useInsecureTrustManager;
- private final boolean disableHttpsEndpointIdentificationAlgorithm;
- private final int handshakeTimeout;
- private final String[] enabledProtocols;
- private final String[] enabledCipherSuites;
- private final boolean filterInsecureCipherSuites;
- private final int sslSessionCacheSize;
- private final int sslSessionTimeout;
- private final SslContext sslContext;
- private final SslEngineFactory sslEngineFactory;
-
- // filters
- private final List requestFilters;
- private final List responseFilters;
- private final List ioExceptionFilters;
-
- // cookie store
- private final CookieStore cookieStore;
- private final int expiredCookieEvictionDelay;
-
- // internals
- private final String threadPoolName;
- private final int httpClientCodecMaxInitialLineLength;
- private final int httpClientCodecMaxHeaderSize;
- private final int httpClientCodecMaxChunkSize;
- private final int httpClientCodecInitialBufferSize;
- private final int chunkedFileChunkSize;
- private final Map, Object> channelOptions;
- private final EventLoopGroup eventLoopGroup;
- private final boolean useNativeTransport;
- private final ByteBufAllocator allocator;
- private final boolean tcpNoDelay;
- private final boolean soReuseAddress;
- private final boolean soKeepAlive;
- private final int soLinger;
- private final int soSndBuf;
- private final int soRcvBuf;
- private final Timer nettyTimer;
- private final ThreadFactory threadFactory;
- private final Consumer httpAdditionalChannelInitializer;
- private final Consumer wsAdditionalChannelInitializer;
- private final ResponseBodyPartFactory responseBodyPartFactory;
- private final int ioThreadsCount;
- private final long hashedWheelTimerTickDuration;
- private final int hashedWheelTimerSize;
-
- private DefaultAsyncHttpClientConfig(// http
- boolean followRedirect,
- int maxRedirects,
- boolean strict302Handling,
- boolean compressionEnforced,
- String userAgent,
- Realm realm,
- int maxRequestRetry,
- boolean disableUrlEncodingForBoundRequests,
- boolean useLaxCookieEncoder,
- boolean disableZeroCopy,
- boolean keepEncodingHeader,
- ProxyServerSelector proxyServerSelector,
- boolean validateResponseHeaders,
- boolean aggregateWebSocketFrameFragments,
- boolean enablewebSocketCompression,
-
- // timeouts
- int connectTimeout,
- int requestTimeout,
- int readTimeout,
- int shutdownQuietPeriod,
- int shutdownTimeout,
-
- // keep-alive
- boolean keepAlive,
- int pooledConnectionIdleTimeout,
- int connectionPoolCleanerPeriod,
- int connectionTtl,
- int maxConnections,
- int maxConnectionsPerHost,
- int acquireFreeChannelTimeout,
- ChannelPool channelPool,
- ConnectionSemaphoreFactory connectionSemaphoreFactory,
- KeepAliveStrategy keepAliveStrategy,
-
- // ssl
- boolean useOpenSsl,
- boolean useInsecureTrustManager,
- boolean disableHttpsEndpointIdentificationAlgorithm,
- int handshakeTimeout,
- String[] enabledProtocols,
- String[] enabledCipherSuites,
- boolean filterInsecureCipherSuites,
- int sslSessionCacheSize,
- int sslSessionTimeout,
- SslContext sslContext,
- SslEngineFactory sslEngineFactory,
-
- // filters
- List requestFilters,
- List responseFilters,
- List ioExceptionFilters,
-
- // cookie store
- CookieStore cookieStore,
- int expiredCookieEvictionDelay,
-
- // tuning
- boolean tcpNoDelay,
- boolean soReuseAddress,
- boolean soKeepAlive,
- int soLinger,
- int soSndBuf,
- int soRcvBuf,
-
- // internals
- String threadPoolName,
- int httpClientCodecMaxInitialLineLength,
- int httpClientCodecMaxHeaderSize,
- int httpClientCodecMaxChunkSize,
- int httpClientCodecInitialBufferSize,
- int chunkedFileChunkSize,
- int webSocketMaxBufferSize,
- int webSocketMaxFrameSize,
- Map, Object> channelOptions,
- EventLoopGroup eventLoopGroup,
- boolean useNativeTransport,
- ByteBufAllocator allocator,
- Timer nettyTimer,
- ThreadFactory threadFactory,
- Consumer httpAdditionalChannelInitializer,
- Consumer wsAdditionalChannelInitializer,
- ResponseBodyPartFactory responseBodyPartFactory,
- int ioThreadsCount,
- long hashedWheelTimerTickDuration,
- int hashedWheelTimerSize) {
-
// http
- this.followRedirect = followRedirect;
- this.maxRedirects = maxRedirects;
- this.strict302Handling = strict302Handling;
- this.compressionEnforced = compressionEnforced;
- this.userAgent = userAgent;
- this.realm = realm;
- this.maxRequestRetry = maxRequestRetry;
- this.disableUrlEncodingForBoundRequests = disableUrlEncodingForBoundRequests;
- this.useLaxCookieEncoder = useLaxCookieEncoder;
- this.disableZeroCopy = disableZeroCopy;
- this.keepEncodingHeader = keepEncodingHeader;
- this.proxyServerSelector = proxyServerSelector;
- this.validateResponseHeaders = validateResponseHeaders;
-
- // websocket
- this.aggregateWebSocketFrameFragments = aggregateWebSocketFrameFragments;
- this.enablewebSocketCompression = enablewebSocketCompression;
- this.webSocketMaxBufferSize = webSocketMaxBufferSize;
- this.webSocketMaxFrameSize = webSocketMaxFrameSize;
+ private final boolean followRedirect;
+ private final int maxRedirects;
+ private final boolean strict302Handling;
+ private final boolean compressionEnforced;
+ private final String userAgent;
+ private final Realm realm;
+ private final int maxRequestRetry;
+ private final boolean disableUrlEncodingForBoundRequests;
+ private final boolean useLaxCookieEncoder;
+ private final boolean disableZeroCopy;
+ private final boolean keepEncodingHeader;
+ private final ProxyServerSelector proxyServerSelector;
+ private final boolean validateResponseHeaders;
+
+ // websockets
+ private final boolean aggregateWebSocketFrameFragments;
+ private final boolean enablewebSocketCompression;
+ private final int webSocketMaxBufferSize;
+ private final int webSocketMaxFrameSize;
// timeouts
- this.connectTimeout = connectTimeout;
- this.requestTimeout = requestTimeout;
- this.readTimeout = readTimeout;
- this.shutdownQuietPeriod = shutdownQuietPeriod;
- this.shutdownTimeout = shutdownTimeout;
+ private final int connectTimeout;
+ private final int requestTimeout;
+ private final int readTimeout;
+ private final int shutdownQuietPeriod;
+ private final int shutdownTimeout;
// keep-alive
- this.keepAlive = keepAlive;
- this.pooledConnectionIdleTimeout = pooledConnectionIdleTimeout;
- this.connectionPoolCleanerPeriod = connectionPoolCleanerPeriod;
- this.connectionTtl = connectionTtl;
- this.maxConnections = maxConnections;
- this.maxConnectionsPerHost = maxConnectionsPerHost;
- this.acquireFreeChannelTimeout = acquireFreeChannelTimeout;
- this.channelPool = channelPool;
- this.connectionSemaphoreFactory = connectionSemaphoreFactory;
- this.keepAliveStrategy = keepAliveStrategy;
+ private final boolean keepAlive;
+ private final int pooledConnectionIdleTimeout;
+ private final int connectionPoolCleanerPeriod;
+ private final int connectionTtl;
+ private final int maxConnections;
+ private final int maxConnectionsPerHost;
+ private final int acquireFreeChannelTimeout;
+ private final ChannelPool channelPool;
+ private final ConnectionSemaphoreFactory connectionSemaphoreFactory;
+ private final KeepAliveStrategy keepAliveStrategy;
// ssl
- this.useOpenSsl = useOpenSsl;
- this.useInsecureTrustManager = useInsecureTrustManager;
- this.disableHttpsEndpointIdentificationAlgorithm = disableHttpsEndpointIdentificationAlgorithm;
- this.handshakeTimeout = handshakeTimeout;
- this.enabledProtocols = enabledProtocols;
- this.enabledCipherSuites = enabledCipherSuites;
- this.filterInsecureCipherSuites = filterInsecureCipherSuites;
- this.sslSessionCacheSize = sslSessionCacheSize;
- this.sslSessionTimeout = sslSessionTimeout;
- this.sslContext = sslContext;
- this.sslEngineFactory = sslEngineFactory;
+ private final boolean useOpenSsl;
+ private final boolean useInsecureTrustManager;
+ private final boolean disableHttpsEndpointIdentificationAlgorithm;
+ private final int handshakeTimeout;
+ private final String[] enabledProtocols;
+ private final String[] enabledCipherSuites;
+ private final boolean filterInsecureCipherSuites;
+ private final int sslSessionCacheSize;
+ private final int sslSessionTimeout;
+ private final SslContext sslContext;
+ private final SslEngineFactory sslEngineFactory;
// filters
- this.requestFilters = requestFilters;
- this.responseFilters = responseFilters;
- this.ioExceptionFilters = ioExceptionFilters;
+ private final List requestFilters;
+ private final List responseFilters;
+ private final List ioExceptionFilters;
// cookie store
- this.cookieStore = cookieStore;
- this.expiredCookieEvictionDelay = expiredCookieEvictionDelay;
-
- // tuning
- this.tcpNoDelay = tcpNoDelay;
- this.soReuseAddress = soReuseAddress;
- this.soKeepAlive = soKeepAlive;
- this.soLinger = soLinger;
- this.soSndBuf = soSndBuf;
- this.soRcvBuf = soRcvBuf;
+ private final CookieStore cookieStore;
+ private final int expiredCookieEvictionDelay;
// internals
- this.threadPoolName = threadPoolName;
- this.httpClientCodecMaxInitialLineLength = httpClientCodecMaxInitialLineLength;
- this.httpClientCodecMaxHeaderSize = httpClientCodecMaxHeaderSize;
- this.httpClientCodecMaxChunkSize = httpClientCodecMaxChunkSize;
- this.httpClientCodecInitialBufferSize = httpClientCodecInitialBufferSize;
- this.chunkedFileChunkSize = chunkedFileChunkSize;
- this.channelOptions = channelOptions;
- this.eventLoopGroup = eventLoopGroup;
- this.useNativeTransport = useNativeTransport;
- this.allocator = allocator;
- this.nettyTimer = nettyTimer;
- this.threadFactory = threadFactory;
- this.httpAdditionalChannelInitializer = httpAdditionalChannelInitializer;
- this.wsAdditionalChannelInitializer = wsAdditionalChannelInitializer;
- this.responseBodyPartFactory = responseBodyPartFactory;
- this.ioThreadsCount = ioThreadsCount;
- this.hashedWheelTimerTickDuration = hashedWheelTimerTickDuration;
- this.hashedWheelTimerSize = hashedWheelTimerSize;
- }
-
- @Override
- public String getAhcVersion() {
- return AsyncHttpClientConfigDefaults.AHC_VERSION;
- }
-
- // http
- @Override
- public boolean isFollowRedirect() {
- return followRedirect;
- }
-
- @Override
- public int getMaxRedirects() {
- return maxRedirects;
- }
-
- @Override
- public boolean isStrict302Handling() {
- return strict302Handling;
- }
-
- @Override
- public boolean isCompressionEnforced() {
- return compressionEnforced;
- }
-
- @Override
- public String getUserAgent() {
- return userAgent;
- }
-
- @Override
- public Realm getRealm() {
- return realm;
- }
-
- @Override
- public int getMaxRequestRetry() {
- return maxRequestRetry;
- }
-
- @Override
- public boolean isDisableUrlEncodingForBoundRequests() {
- return disableUrlEncodingForBoundRequests;
- }
-
- @Override
- public boolean isUseLaxCookieEncoder() {
- return useLaxCookieEncoder;
- }
-
- @Override
- public boolean isDisableZeroCopy() {
- return disableZeroCopy;
- }
-
- @Override
- public boolean isKeepEncodingHeader() {
- return keepEncodingHeader;
- }
-
- @Override
- public ProxyServerSelector getProxyServerSelector() {
- return proxyServerSelector;
- }
-
- // websocket
- @Override
- public boolean isAggregateWebSocketFrameFragments() {
- return aggregateWebSocketFrameFragments;
- }
-
- @Override
- public boolean isEnableWebSocketCompression() {
- return enablewebSocketCompression;
- }
-
- @Override
- public int getWebSocketMaxBufferSize() {
- return webSocketMaxBufferSize;
- }
-
- @Override
- public int getWebSocketMaxFrameSize() {
- return webSocketMaxFrameSize;
- }
-
- // timeouts
- @Override
- public int getConnectTimeout() {
- return connectTimeout;
- }
-
- @Override
- public int getRequestTimeout() {
- return requestTimeout;
- }
-
- @Override
- public int getReadTimeout() {
- return readTimeout;
- }
-
- @Override
- public int getShutdownQuietPeriod() {
- return shutdownQuietPeriod;
- }
-
- @Override
- public int getShutdownTimeout() {
- return shutdownTimeout;
- }
-
- // keep-alive
- @Override
- public boolean isKeepAlive() {
- return keepAlive;
- }
-
- @Override
- public int getPooledConnectionIdleTimeout() {
- return pooledConnectionIdleTimeout;
- }
-
- @Override
- public int getConnectionPoolCleanerPeriod() {
- return connectionPoolCleanerPeriod;
- }
-
- @Override
- public int getConnectionTtl() {
- return connectionTtl;
- }
-
- @Override
- public int getMaxConnections() {
- return maxConnections;
- }
-
- @Override
- public int getMaxConnectionsPerHost() {
- return maxConnectionsPerHost;
- }
-
- @Override
- public int getAcquireFreeChannelTimeout() { return acquireFreeChannelTimeout; }
-
- @Override
- public ChannelPool getChannelPool() {
- return channelPool;
- }
-
- @Override
- public ConnectionSemaphoreFactory getConnectionSemaphoreFactory() {
- return connectionSemaphoreFactory;
- }
-
- @Override
- public KeepAliveStrategy getKeepAliveStrategy() {
- return keepAliveStrategy;
- }
-
- @Override
- public boolean isValidateResponseHeaders() {
- return validateResponseHeaders;
- }
-
- // ssl
- @Override
- public boolean isUseOpenSsl() {
- return useOpenSsl;
- }
-
- @Override
- public boolean isUseInsecureTrustManager() {
- return useInsecureTrustManager;
- }
-
- @Override
- public boolean isDisableHttpsEndpointIdentificationAlgorithm() {
- return disableHttpsEndpointIdentificationAlgorithm;
- }
-
- @Override
- public int getHandshakeTimeout() {
- return handshakeTimeout;
- }
-
- @Override
- public String[] getEnabledProtocols() {
- return enabledProtocols;
- }
-
- @Override
- public String[] getEnabledCipherSuites() {
- return enabledCipherSuites;
- }
-
- @Override
- public boolean isFilterInsecureCipherSuites() {
- return filterInsecureCipherSuites;
- }
-
- @Override
- public int getSslSessionCacheSize() {
- return sslSessionCacheSize;
- }
-
- @Override
- public int getSslSessionTimeout() {
- return sslSessionTimeout;
- }
-
- @Override
- public SslContext getSslContext() {
- return sslContext;
- }
-
- @Override
- public SslEngineFactory getSslEngineFactory() {
- return sslEngineFactory;
- }
-
- // filters
- @Override
- public List getRequestFilters() {
- return requestFilters;
- }
-
- @Override
- public List getResponseFilters() {
- return responseFilters;
- }
-
- @Override
- public List getIoExceptionFilters() {
- return ioExceptionFilters;
- }
-
- // cookie store
- @Override
- public CookieStore getCookieStore() {
- return cookieStore;
- }
-
- @Override
- public int expiredCookieEvictionDelay() {
- return expiredCookieEvictionDelay;
- }
-
- // tuning
- @Override
- public boolean isTcpNoDelay() {
- return tcpNoDelay;
- }
-
- @Override
- public boolean isSoReuseAddress() {
- return soReuseAddress;
- }
-
- @Override
- public boolean isSoKeepAlive() {
- return soKeepAlive;
- }
-
- @Override
- public int getSoLinger() {
- return soLinger;
- }
-
- @Override
- public int getSoSndBuf() {
- return soSndBuf;
- }
-
- @Override
- public int getSoRcvBuf() {
- return soRcvBuf;
- }
-
- // internals
- @Override
- public String getThreadPoolName() {
- return threadPoolName;
- }
-
- @Override
- public int getHttpClientCodecMaxInitialLineLength() {
- return httpClientCodecMaxInitialLineLength;
- }
-
- @Override
- public int getHttpClientCodecMaxHeaderSize() {
- return httpClientCodecMaxHeaderSize;
- }
-
- @Override
- public int getHttpClientCodecMaxChunkSize() {
- return httpClientCodecMaxChunkSize;
- }
-
- @Override
- public int getHttpClientCodecInitialBufferSize() {
- return httpClientCodecInitialBufferSize;
- }
-
- @Override
- public int getChunkedFileChunkSize() {
- return chunkedFileChunkSize;
- }
-
- @Override
- public Map, Object> getChannelOptions() {
- return channelOptions;
- }
-
- @Override
- public EventLoopGroup getEventLoopGroup() {
- return eventLoopGroup;
- }
-
- @Override
- public boolean isUseNativeTransport() {
- return useNativeTransport;
- }
-
- @Override
- public ByteBufAllocator getAllocator() {
- return allocator;
- }
-
- @Override
- public Timer getNettyTimer() {
- return nettyTimer;
- }
-
- @Override
- public long getHashedWheelTimerTickDuration() {
- return hashedWheelTimerTickDuration;
- }
-
- @Override
- public int getHashedWheelTimerSize() {
- return hashedWheelTimerSize;
- }
-
- @Override
- public ThreadFactory getThreadFactory() {
- return threadFactory;
- }
-
- @Override
- public Consumer getHttpAdditionalChannelInitializer() {
- return httpAdditionalChannelInitializer;
- }
-
- @Override
- public Consumer getWsAdditionalChannelInitializer() {
- return wsAdditionalChannelInitializer;
- }
-
- @Override
- public ResponseBodyPartFactory getResponseBodyPartFactory() {
- return responseBodyPartFactory;
- }
-
- @Override
- public int getIoThreadsCount() {
- return ioThreadsCount;
- }
-
- /**
- * Builder for an {@link AsyncHttpClient}
- */
- public static class Builder {
-
- // filters
- private final List requestFilters = new LinkedList<>();
- private final List responseFilters = new LinkedList<>();
- private final List ioExceptionFilters = new LinkedList<>();
- // http
- private boolean followRedirect = defaultFollowRedirect();
- private int maxRedirects = defaultMaxRedirects();
- private boolean strict302Handling = defaultStrict302Handling();
- private boolean compressionEnforced = defaultCompressionEnforced();
- private String userAgent = defaultUserAgent();
- private Realm realm;
- private int maxRequestRetry = defaultMaxRequestRetry();
- private boolean disableUrlEncodingForBoundRequests = defaultDisableUrlEncodingForBoundRequests();
- private boolean useLaxCookieEncoder = defaultUseLaxCookieEncoder();
- private boolean disableZeroCopy = defaultDisableZeroCopy();
- private boolean keepEncodingHeader = defaultKeepEncodingHeader();
- private ProxyServerSelector proxyServerSelector;
- private boolean useProxySelector = defaultUseProxySelector();
- private boolean useProxyProperties = defaultUseProxyProperties();
- private boolean validateResponseHeaders = defaultValidateResponseHeaders();
-
- // websocket
- private boolean aggregateWebSocketFrameFragments = defaultAggregateWebSocketFrameFragments();
- private boolean enablewebSocketCompression = defaultEnableWebSocketCompression();
- private int webSocketMaxBufferSize = defaultWebSocketMaxBufferSize();
- private int webSocketMaxFrameSize = defaultWebSocketMaxFrameSize();
-
- // timeouts
- private int connectTimeout = defaultConnectTimeout();
- private int requestTimeout = defaultRequestTimeout();
- private int readTimeout = defaultReadTimeout();
- private int shutdownQuietPeriod = defaultShutdownQuietPeriod();
- private int shutdownTimeout = defaultShutdownTimeout();
-
- // keep-alive
- private boolean keepAlive = defaultKeepAlive();
- private int pooledConnectionIdleTimeout = defaultPooledConnectionIdleTimeout();
- private int connectionPoolCleanerPeriod = defaultConnectionPoolCleanerPeriod();
- private int connectionTtl = defaultConnectionTtl();
- private int maxConnections = defaultMaxConnections();
- private int maxConnectionsPerHost = defaultMaxConnectionsPerHost();
- private int acquireFreeChannelTimeout = defaultAcquireFreeChannelTimeout();
- private ChannelPool channelPool;
- private ConnectionSemaphoreFactory connectionSemaphoreFactory;
- private KeepAliveStrategy keepAliveStrategy = new DefaultKeepAliveStrategy();
-
- // ssl
- private boolean useOpenSsl = defaultUseOpenSsl();
- private boolean useInsecureTrustManager = defaultUseInsecureTrustManager();
- private boolean disableHttpsEndpointIdentificationAlgorithm = defaultDisableHttpsEndpointIdentificationAlgorithm();
- private int handshakeTimeout = defaultHandshakeTimeout();
- private String[] enabledProtocols = defaultEnabledProtocols();
- private String[] enabledCipherSuites = defaultEnabledCipherSuites();
- private boolean filterInsecureCipherSuites = defaultFilterInsecureCipherSuites();
- private int sslSessionCacheSize = defaultSslSessionCacheSize();
- private int sslSessionTimeout = defaultSslSessionTimeout();
- private SslContext sslContext;
- private SslEngineFactory sslEngineFactory;
-
- // cookie store
- private CookieStore cookieStore = new ThreadSafeCookieStore();
- private int expiredCookieEvictionDelay = defaultExpiredCookieEvictionDelay();
-
- // tuning
- private boolean tcpNoDelay = defaultTcpNoDelay();
- private boolean soReuseAddress = defaultSoReuseAddress();
- private boolean soKeepAlive = defaultSoKeepAlive();
- private int soLinger = defaultSoLinger();
- private int soSndBuf = defaultSoSndBuf();
- private int soRcvBuf = defaultSoRcvBuf();
-
- // internals
- private String threadPoolName = defaultThreadPoolName();
- private int httpClientCodecMaxInitialLineLength = defaultHttpClientCodecMaxInitialLineLength();
- private int httpClientCodecMaxHeaderSize = defaultHttpClientCodecMaxHeaderSize();
- private int httpClientCodecMaxChunkSize = defaultHttpClientCodecMaxChunkSize();
- private int httpClientCodecInitialBufferSize = defaultHttpClientCodecInitialBufferSize();
- private int chunkedFileChunkSize = defaultChunkedFileChunkSize();
- private boolean useNativeTransport = defaultUseNativeTransport();
- private ByteBufAllocator allocator;
- private Map, Object> channelOptions = new HashMap<>();
- private EventLoopGroup eventLoopGroup;
- private Timer nettyTimer;
- private ThreadFactory threadFactory;
- private Consumer httpAdditionalChannelInitializer;
- private Consumer wsAdditionalChannelInitializer;
- private ResponseBodyPartFactory responseBodyPartFactory = ResponseBodyPartFactory.EAGER;
- private int ioThreadsCount = defaultIoThreadsCount();
- private long hashedWheelTickDuration = defaultHashedWheelTimerTickDuration();
- private int hashedWheelSize = defaultHashedWheelTimerSize();
-
- public Builder() {
- }
-
- public Builder(AsyncHttpClientConfig config) {
- // http
- followRedirect = config.isFollowRedirect();
- maxRedirects = config.getMaxRedirects();
- strict302Handling = config.isStrict302Handling();
- compressionEnforced = config.isCompressionEnforced();
- userAgent = config.getUserAgent();
- realm = config.getRealm();
- maxRequestRetry = config.getMaxRequestRetry();
- disableUrlEncodingForBoundRequests = config.isDisableUrlEncodingForBoundRequests();
- useLaxCookieEncoder = config.isUseLaxCookieEncoder();
- disableZeroCopy = config.isDisableZeroCopy();
- keepEncodingHeader = config.isKeepEncodingHeader();
- proxyServerSelector = config.getProxyServerSelector();
-
- // websocket
- aggregateWebSocketFrameFragments = config.isAggregateWebSocketFrameFragments();
- enablewebSocketCompression = config.isEnableWebSocketCompression();
- webSocketMaxBufferSize = config.getWebSocketMaxBufferSize();
- webSocketMaxFrameSize = config.getWebSocketMaxFrameSize();
-
- // timeouts
- connectTimeout = config.getConnectTimeout();
- requestTimeout = config.getRequestTimeout();
- readTimeout = config.getReadTimeout();
- shutdownQuietPeriod = config.getShutdownQuietPeriod();
- shutdownTimeout = config.getShutdownTimeout();
-
- // keep-alive
- keepAlive = config.isKeepAlive();
- pooledConnectionIdleTimeout = config.getPooledConnectionIdleTimeout();
- connectionTtl = config.getConnectionTtl();
- maxConnections = config.getMaxConnections();
- maxConnectionsPerHost = config.getMaxConnectionsPerHost();
- channelPool = config.getChannelPool();
- connectionSemaphoreFactory = config.getConnectionSemaphoreFactory();
- keepAliveStrategy = config.getKeepAliveStrategy();
-
- // ssl
- useInsecureTrustManager = config.isUseInsecureTrustManager();
- handshakeTimeout = config.getHandshakeTimeout();
- enabledProtocols = config.getEnabledProtocols();
- enabledCipherSuites = config.getEnabledCipherSuites();
- filterInsecureCipherSuites = config.isFilterInsecureCipherSuites();
- sslSessionCacheSize = config.getSslSessionCacheSize();
- sslSessionTimeout = config.getSslSessionTimeout();
- sslContext = config.getSslContext();
- sslEngineFactory = config.getSslEngineFactory();
-
- // filters
- requestFilters.addAll(config.getRequestFilters());
- responseFilters.addAll(config.getResponseFilters());
- ioExceptionFilters.addAll(config.getIoExceptionFilters());
-
- // tuning
- tcpNoDelay = config.isTcpNoDelay();
- soReuseAddress = config.isSoReuseAddress();
- soKeepAlive = config.isSoKeepAlive();
- soLinger = config.getSoLinger();
- soSndBuf = config.getSoSndBuf();
- soRcvBuf = config.getSoRcvBuf();
-
- // internals
- threadPoolName = config.getThreadPoolName();
- httpClientCodecMaxInitialLineLength = config.getHttpClientCodecMaxInitialLineLength();
- httpClientCodecMaxHeaderSize = config.getHttpClientCodecMaxHeaderSize();
- httpClientCodecMaxChunkSize = config.getHttpClientCodecMaxChunkSize();
- chunkedFileChunkSize = config.getChunkedFileChunkSize();
- channelOptions.putAll(config.getChannelOptions());
- eventLoopGroup = config.getEventLoopGroup();
- useNativeTransport = config.isUseNativeTransport();
- allocator = config.getAllocator();
- nettyTimer = config.getNettyTimer();
- threadFactory = config.getThreadFactory();
- httpAdditionalChannelInitializer = config.getHttpAdditionalChannelInitializer();
- wsAdditionalChannelInitializer = config.getWsAdditionalChannelInitializer();
- responseBodyPartFactory = config.getResponseBodyPartFactory();
- ioThreadsCount = config.getIoThreadsCount();
- hashedWheelTickDuration = config.getHashedWheelTimerTickDuration();
- hashedWheelSize = config.getHashedWheelTimerSize();
+ private final String threadPoolName;
+ private final int httpClientCodecMaxInitialLineLength;
+ private final int httpClientCodecMaxHeaderSize;
+ private final int httpClientCodecMaxChunkSize;
+ private final int httpClientCodecInitialBufferSize;
+ private final int chunkedFileChunkSize;
+ private final Map, Object> channelOptions;
+ private final EventLoopGroup eventLoopGroup;
+ private final boolean useNativeTransport;
+ private final boolean useOnlyEpollNativeTransport;
+ private final ByteBufAllocator allocator;
+ private final boolean tcpNoDelay;
+ private final boolean soReuseAddress;
+ private final boolean soKeepAlive;
+ private final int soLinger;
+ private final int soSndBuf;
+ private final int soRcvBuf;
+ private final Timer nettyTimer;
+ private final ThreadFactory threadFactory;
+ private final Consumer httpAdditionalChannelInitializer;
+ private final Consumer wsAdditionalChannelInitializer;
+ private final ResponseBodyPartFactory responseBodyPartFactory;
+ private final int ioThreadsCount;
+ private final long hashedWheelTimerTickDuration;
+ private final int hashedWheelTimerSize;
+
+ private DefaultAsyncHttpClientConfig(// http
+ boolean followRedirect,
+ int maxRedirects,
+ boolean strict302Handling,
+ boolean compressionEnforced,
+ String userAgent,
+ Realm realm,
+ int maxRequestRetry,
+ boolean disableUrlEncodingForBoundRequests,
+ boolean useLaxCookieEncoder,
+ boolean disableZeroCopy,
+ boolean keepEncodingHeader,
+ ProxyServerSelector proxyServerSelector,
+ boolean validateResponseHeaders,
+ boolean aggregateWebSocketFrameFragments,
+ boolean enablewebSocketCompression,
+
+ // timeouts
+ int connectTimeout,
+ int requestTimeout,
+ int readTimeout,
+ int shutdownQuietPeriod,
+ int shutdownTimeout,
+
+ // keep-alive
+ boolean keepAlive,
+ int pooledConnectionIdleTimeout,
+ int connectionPoolCleanerPeriod,
+ int connectionTtl,
+ int maxConnections,
+ int maxConnectionsPerHost,
+ int acquireFreeChannelTimeout,
+ ChannelPool channelPool,
+ ConnectionSemaphoreFactory connectionSemaphoreFactory,
+ KeepAliveStrategy keepAliveStrategy,
+
+ // ssl
+ boolean useOpenSsl,
+ boolean useInsecureTrustManager,
+ boolean disableHttpsEndpointIdentificationAlgorithm,
+ int handshakeTimeout,
+ String[] enabledProtocols,
+ String[] enabledCipherSuites,
+ boolean filterInsecureCipherSuites,
+ int sslSessionCacheSize,
+ int sslSessionTimeout,
+ SslContext sslContext,
+ SslEngineFactory sslEngineFactory,
+
+ // filters
+ List requestFilters,
+ List responseFilters,
+ List ioExceptionFilters,
+
+ // cookie store
+ CookieStore cookieStore,
+ int expiredCookieEvictionDelay,
+
+ // tuning
+ boolean tcpNoDelay,
+ boolean soReuseAddress,
+ boolean soKeepAlive,
+ int soLinger,
+ int soSndBuf,
+ int soRcvBuf,
+
+ // internals
+ String threadPoolName,
+ int httpClientCodecMaxInitialLineLength,
+ int httpClientCodecMaxHeaderSize,
+ int httpClientCodecMaxChunkSize,
+ int httpClientCodecInitialBufferSize,
+ int chunkedFileChunkSize,
+ int webSocketMaxBufferSize,
+ int webSocketMaxFrameSize,
+ Map, Object> channelOptions,
+ EventLoopGroup eventLoopGroup,
+ boolean useNativeTransport,
+ boolean useOnlyEpollNativeTransport,
+ ByteBufAllocator allocator,
+ Timer nettyTimer,
+ ThreadFactory threadFactory,
+ Consumer httpAdditionalChannelInitializer,
+ Consumer wsAdditionalChannelInitializer,
+ ResponseBodyPartFactory responseBodyPartFactory,
+ int ioThreadsCount,
+ long hashedWheelTimerTickDuration,
+ int hashedWheelTimerSize) {
+
+ // http
+ this.followRedirect = followRedirect;
+ this.maxRedirects = maxRedirects;
+ this.strict302Handling = strict302Handling;
+ this.compressionEnforced = compressionEnforced;
+ this.userAgent = userAgent;
+ this.realm = realm;
+ this.maxRequestRetry = maxRequestRetry;
+ this.disableUrlEncodingForBoundRequests = disableUrlEncodingForBoundRequests;
+ this.useLaxCookieEncoder = useLaxCookieEncoder;
+ this.disableZeroCopy = disableZeroCopy;
+ this.keepEncodingHeader = keepEncodingHeader;
+ this.proxyServerSelector = proxyServerSelector;
+ this.validateResponseHeaders = validateResponseHeaders;
+
+ // websocket
+ this.aggregateWebSocketFrameFragments = aggregateWebSocketFrameFragments;
+ this.enablewebSocketCompression = enablewebSocketCompression;
+ this.webSocketMaxBufferSize = webSocketMaxBufferSize;
+ this.webSocketMaxFrameSize = webSocketMaxFrameSize;
+
+ // timeouts
+ this.connectTimeout = connectTimeout;
+ this.requestTimeout = requestTimeout;
+ this.readTimeout = readTimeout;
+ this.shutdownQuietPeriod = shutdownQuietPeriod;
+ this.shutdownTimeout = shutdownTimeout;
+
+ // keep-alive
+ this.keepAlive = keepAlive;
+ this.pooledConnectionIdleTimeout = pooledConnectionIdleTimeout;
+ this.connectionPoolCleanerPeriod = connectionPoolCleanerPeriod;
+ this.connectionTtl = connectionTtl;
+ this.maxConnections = maxConnections;
+ this.maxConnectionsPerHost = maxConnectionsPerHost;
+ this.acquireFreeChannelTimeout = acquireFreeChannelTimeout;
+ this.channelPool = channelPool;
+ this.connectionSemaphoreFactory = connectionSemaphoreFactory;
+ this.keepAliveStrategy = keepAliveStrategy;
+
+ // ssl
+ this.useOpenSsl = useOpenSsl;
+ this.useInsecureTrustManager = useInsecureTrustManager;
+ this.disableHttpsEndpointIdentificationAlgorithm = disableHttpsEndpointIdentificationAlgorithm;
+ this.handshakeTimeout = handshakeTimeout;
+ this.enabledProtocols = enabledProtocols;
+ this.enabledCipherSuites = enabledCipherSuites;
+ this.filterInsecureCipherSuites = filterInsecureCipherSuites;
+ this.sslSessionCacheSize = sslSessionCacheSize;
+ this.sslSessionTimeout = sslSessionTimeout;
+ this.sslContext = sslContext;
+ this.sslEngineFactory = sslEngineFactory;
+
+ // filters
+ this.requestFilters = requestFilters;
+ this.responseFilters = responseFilters;
+ this.ioExceptionFilters = ioExceptionFilters;
+
+ // cookie store
+ this.cookieStore = cookieStore;
+ this.expiredCookieEvictionDelay = expiredCookieEvictionDelay;
+
+ // tuning
+ this.tcpNoDelay = tcpNoDelay;
+ this.soReuseAddress = soReuseAddress;
+ this.soKeepAlive = soKeepAlive;
+ this.soLinger = soLinger;
+ this.soSndBuf = soSndBuf;
+ this.soRcvBuf = soRcvBuf;
+
+ // internals
+ this.threadPoolName = threadPoolName;
+ this.httpClientCodecMaxInitialLineLength = httpClientCodecMaxInitialLineLength;
+ this.httpClientCodecMaxHeaderSize = httpClientCodecMaxHeaderSize;
+ this.httpClientCodecMaxChunkSize = httpClientCodecMaxChunkSize;
+ this.httpClientCodecInitialBufferSize = httpClientCodecInitialBufferSize;
+ this.chunkedFileChunkSize = chunkedFileChunkSize;
+ this.channelOptions = channelOptions;
+ this.eventLoopGroup = eventLoopGroup;
+ this.useNativeTransport = useNativeTransport;
+ this.useOnlyEpollNativeTransport = useOnlyEpollNativeTransport;
+
+ if (useOnlyEpollNativeTransport && !useNativeTransport) {
+ throw new IllegalArgumentException("Native Transport must be enabled to use Epoll Native Transport only");
+ }
+
+ this.allocator = allocator;
+ this.nettyTimer = nettyTimer;
+ this.threadFactory = threadFactory;
+ this.httpAdditionalChannelInitializer = httpAdditionalChannelInitializer;
+ this.wsAdditionalChannelInitializer = wsAdditionalChannelInitializer;
+ this.responseBodyPartFactory = responseBodyPartFactory;
+ this.ioThreadsCount = ioThreadsCount;
+ this.hashedWheelTimerTickDuration = hashedWheelTimerTickDuration;
+ this.hashedWheelTimerSize = hashedWheelTimerSize;
+ }
+
+ @Override
+ public String getAhcVersion() {
+ return AsyncHttpClientConfigDefaults.AHC_VERSION;
}
// http
- public Builder setFollowRedirect(boolean followRedirect) {
- this.followRedirect = followRedirect;
- return this;
- }
-
- public Builder setMaxRedirects(int maxRedirects) {
- this.maxRedirects = maxRedirects;
- return this;
- }
-
- public Builder setStrict302Handling(final boolean strict302Handling) {
- this.strict302Handling = strict302Handling;
- return this;
- }
-
- public Builder setCompressionEnforced(boolean compressionEnforced) {
- this.compressionEnforced = compressionEnforced;
- return this;
- }
-
- public Builder setUserAgent(String userAgent) {
- this.userAgent = userAgent;
- return this;
- }
-
- public Builder setRealm(Realm realm) {
- this.realm = realm;
- return this;
+ @Override
+ public boolean isFollowRedirect() {
+ return followRedirect;
}
- public Builder setRealm(Realm.Builder realmBuilder) {
- this.realm = realmBuilder.build();
- return this;
+ @Override
+ public int getMaxRedirects() {
+ return maxRedirects;
}
- public Builder setMaxRequestRetry(int maxRequestRetry) {
- this.maxRequestRetry = maxRequestRetry;
- return this;
+ @Override
+ public boolean isStrict302Handling() {
+ return strict302Handling;
}
- public Builder setDisableUrlEncodingForBoundRequests(boolean disableUrlEncodingForBoundRequests) {
- this.disableUrlEncodingForBoundRequests = disableUrlEncodingForBoundRequests;
- return this;
+ @Override
+ public boolean isCompressionEnforced() {
+ return compressionEnforced;
}
- public Builder setUseLaxCookieEncoder(boolean useLaxCookieEncoder) {
- this.useLaxCookieEncoder = useLaxCookieEncoder;
- return this;
+ @Override
+ public String getUserAgent() {
+ return userAgent;
}
- public Builder setDisableZeroCopy(boolean disableZeroCopy) {
- this.disableZeroCopy = disableZeroCopy;
- return this;
+ @Override
+ public Realm getRealm() {
+ return realm;
}
- public Builder setKeepEncodingHeader(boolean keepEncodingHeader) {
- this.keepEncodingHeader = keepEncodingHeader;
- return this;
+ @Override
+ public int getMaxRequestRetry() {
+ return maxRequestRetry;
}
- public Builder setProxyServerSelector(ProxyServerSelector proxyServerSelector) {
- this.proxyServerSelector = proxyServerSelector;
- return this;
+ @Override
+ public boolean isDisableUrlEncodingForBoundRequests() {
+ return disableUrlEncodingForBoundRequests;
}
- public Builder setValidateResponseHeaders(boolean validateResponseHeaders) {
- this.validateResponseHeaders = validateResponseHeaders;
- return this;
+ @Override
+ public boolean isUseLaxCookieEncoder() {
+ return useLaxCookieEncoder;
}
- public Builder setProxyServer(ProxyServer proxyServer) {
- this.proxyServerSelector = uri -> proxyServer;
- return this;
+ @Override
+ public boolean isDisableZeroCopy() {
+ return disableZeroCopy;
}
- public Builder setProxyServer(ProxyServer.Builder proxyServerBuilder) {
- return setProxyServer(proxyServerBuilder.build());
+ @Override
+ public boolean isKeepEncodingHeader() {
+ return keepEncodingHeader;
}
- public Builder setUseProxySelector(boolean useProxySelector) {
- this.useProxySelector = useProxySelector;
- return this;
- }
-
- public Builder setUseProxyProperties(boolean useProxyProperties) {
- this.useProxyProperties = useProxyProperties;
- return this;
+ @Override
+ public ProxyServerSelector getProxyServerSelector() {
+ return proxyServerSelector;
}
// websocket
- public Builder setAggregateWebSocketFrameFragments(boolean aggregateWebSocketFrameFragments) {
- this.aggregateWebSocketFrameFragments = aggregateWebSocketFrameFragments;
- return this;
+ @Override
+ public boolean isAggregateWebSocketFrameFragments() {
+ return aggregateWebSocketFrameFragments;
}
- public Builder setEnablewebSocketCompression(boolean enablewebSocketCompression) {
- this.enablewebSocketCompression = enablewebSocketCompression;
- return this;
+ @Override
+ public boolean isEnableWebSocketCompression() {
+ return enablewebSocketCompression;
}
- public Builder setWebSocketMaxBufferSize(int webSocketMaxBufferSize) {
- this.webSocketMaxBufferSize = webSocketMaxBufferSize;
- return this;
+ @Override
+ public int getWebSocketMaxBufferSize() {
+ return webSocketMaxBufferSize;
}
- public Builder setWebSocketMaxFrameSize(int webSocketMaxFrameSize) {
- this.webSocketMaxFrameSize = webSocketMaxFrameSize;
- return this;
+ @Override
+ public int getWebSocketMaxFrameSize() {
+ return webSocketMaxFrameSize;
}
// timeouts
- public Builder setConnectTimeout(int connectTimeout) {
- this.connectTimeout = connectTimeout;
- return this;
+ @Override
+ public int getConnectTimeout() {
+ return connectTimeout;
}
- public Builder setRequestTimeout(int requestTimeout) {
- this.requestTimeout = requestTimeout;
- return this;
+ @Override
+ public int getRequestTimeout() {
+ return requestTimeout;
}
- public Builder setReadTimeout(int readTimeout) {
- this.readTimeout = readTimeout;
- return this;
+ @Override
+ public int getReadTimeout() {
+ return readTimeout;
}
- public Builder setShutdownQuietPeriod(int shutdownQuietPeriod) {
- this.shutdownQuietPeriod = shutdownQuietPeriod;
- return this;
+ @Override
+ public int getShutdownQuietPeriod() {
+ return shutdownQuietPeriod;
}
- public Builder setShutdownTimeout(int shutdownTimeout) {
- this.shutdownTimeout = shutdownTimeout;
- return this;
+ @Override
+ public int getShutdownTimeout() {
+ return shutdownTimeout;
}
// keep-alive
- public Builder setKeepAlive(boolean keepAlive) {
- this.keepAlive = keepAlive;
- return this;
+ @Override
+ public boolean isKeepAlive() {
+ return keepAlive;
}
- public Builder setPooledConnectionIdleTimeout(int pooledConnectionIdleTimeout) {
- this.pooledConnectionIdleTimeout = pooledConnectionIdleTimeout;
- return this;
+ @Override
+ public int getPooledConnectionIdleTimeout() {
+ return pooledConnectionIdleTimeout;
}
- public Builder setConnectionPoolCleanerPeriod(int connectionPoolCleanerPeriod) {
- this.connectionPoolCleanerPeriod = connectionPoolCleanerPeriod;
- return this;
+ @Override
+ public int getConnectionPoolCleanerPeriod() {
+ return connectionPoolCleanerPeriod;
}
- public Builder setConnectionTtl(int connectionTtl) {
- this.connectionTtl = connectionTtl;
- return this;
+ @Override
+ public int getConnectionTtl() {
+ return connectionTtl;
}
- public Builder setMaxConnections(int maxConnections) {
- this.maxConnections = maxConnections;
- return this;
+ @Override
+ public int getMaxConnections() {
+ return maxConnections;
}
- public Builder setMaxConnectionsPerHost(int maxConnectionsPerHost) {
- this.maxConnectionsPerHost = maxConnectionsPerHost;
- return this;
+ @Override
+ public int getMaxConnectionsPerHost() {
+ return maxConnectionsPerHost;
}
- /**
- * Sets the maximum duration in milliseconds to acquire a free channel to send a request
- * @param acquireFreeChannelTimeout maximum duration in milliseconds to acquire a free channel to send a request
- * @return the same builder instance
- */
- public Builder setAcquireFreeChannelTimeout(int acquireFreeChannelTimeout) {
- this.acquireFreeChannelTimeout = acquireFreeChannelTimeout;
- return this;
+ @Override
+ public int getAcquireFreeChannelTimeout() {
+ return acquireFreeChannelTimeout;
}
- public Builder setChannelPool(ChannelPool channelPool) {
- this.channelPool = channelPool;
- return this;
+ @Override
+ public ChannelPool getChannelPool() {
+ return channelPool;
}
- public Builder setConnectionSemaphoreFactory(ConnectionSemaphoreFactory connectionSemaphoreFactory) {
- this.connectionSemaphoreFactory = connectionSemaphoreFactory;
- return this;
+ @Override
+ public ConnectionSemaphoreFactory getConnectionSemaphoreFactory() {
+ return connectionSemaphoreFactory;
}
- public Builder setKeepAliveStrategy(KeepAliveStrategy keepAliveStrategy) {
- this.keepAliveStrategy = keepAliveStrategy;
- return this;
+ @Override
+ public KeepAliveStrategy getKeepAliveStrategy() {
+ return keepAliveStrategy;
}
- // ssl
- public Builder setUseOpenSsl(boolean useOpenSsl) {
- this.useOpenSsl = useOpenSsl;
- return this;
+ @Override
+ public boolean isValidateResponseHeaders() {
+ return validateResponseHeaders;
}
- public Builder setUseInsecureTrustManager(boolean useInsecureTrustManager) {
- this.useInsecureTrustManager = useInsecureTrustManager;
- return this;
- }
-
- public Builder setDisableHttpsEndpointIdentificationAlgorithm(boolean disableHttpsEndpointIdentificationAlgorithm) {
- this.disableHttpsEndpointIdentificationAlgorithm = disableHttpsEndpointIdentificationAlgorithm;
- return this;
- }
-
- public Builder setHandshakeTimeout(int handshakeTimeout) {
- this.handshakeTimeout = handshakeTimeout;
- return this;
+ // ssl
+ @Override
+ public boolean isUseOpenSsl() {
+ return useOpenSsl;
}
- public Builder setEnabledProtocols(String[] enabledProtocols) {
- this.enabledProtocols = enabledProtocols;
- return this;
+ @Override
+ public boolean isUseInsecureTrustManager() {
+ return useInsecureTrustManager;
}
- public Builder setEnabledCipherSuites(String[] enabledCipherSuites) {
- this.enabledCipherSuites = enabledCipherSuites;
- return this;
+ @Override
+ public boolean isDisableHttpsEndpointIdentificationAlgorithm() {
+ return disableHttpsEndpointIdentificationAlgorithm;
}
- public Builder setFilterInsecureCipherSuites(boolean filterInsecureCipherSuites) {
- this.filterInsecureCipherSuites = filterInsecureCipherSuites;
- return this;
+ @Override
+ public int getHandshakeTimeout() {
+ return handshakeTimeout;
}
- public Builder setSslSessionCacheSize(Integer sslSessionCacheSize) {
- this.sslSessionCacheSize = sslSessionCacheSize;
- return this;
+ @Override
+ public String[] getEnabledProtocols() {
+ return enabledProtocols;
}
- public Builder setSslSessionTimeout(Integer sslSessionTimeout) {
- this.sslSessionTimeout = sslSessionTimeout;
- return this;
+ @Override
+ public String[] getEnabledCipherSuites() {
+ return enabledCipherSuites;
}
- public Builder setSslContext(final SslContext sslContext) {
- this.sslContext = sslContext;
- return this;
+ @Override
+ public boolean isFilterInsecureCipherSuites() {
+ return filterInsecureCipherSuites;
}
- public Builder setSslEngineFactory(SslEngineFactory sslEngineFactory) {
- this.sslEngineFactory = sslEngineFactory;
- return this;
+ @Override
+ public int getSslSessionCacheSize() {
+ return sslSessionCacheSize;
}
- // filters
- public Builder addRequestFilter(RequestFilter requestFilter) {
- requestFilters.add(requestFilter);
- return this;
+ @Override
+ public int getSslSessionTimeout() {
+ return sslSessionTimeout;
}
- public Builder removeRequestFilter(RequestFilter requestFilter) {
- requestFilters.remove(requestFilter);
- return this;
+ @Override
+ public SslContext getSslContext() {
+ return sslContext;
}
- public Builder addResponseFilter(ResponseFilter responseFilter) {
- responseFilters.add(responseFilter);
- return this;
+ @Override
+ public SslEngineFactory getSslEngineFactory() {
+ return sslEngineFactory;
}
- public Builder removeResponseFilter(ResponseFilter responseFilter) {
- responseFilters.remove(responseFilter);
- return this;
+ // filters
+ @Override
+ public List getRequestFilters() {
+ return requestFilters;
}
- public Builder addIOExceptionFilter(IOExceptionFilter ioExceptionFilter) {
- ioExceptionFilters.add(ioExceptionFilter);
- return this;
+ @Override
+ public List getResponseFilters() {
+ return responseFilters;
}
- public Builder removeIOExceptionFilter(IOExceptionFilter ioExceptionFilter) {
- ioExceptionFilters.remove(ioExceptionFilter);
- return this;
+ @Override
+ public List getIoExceptionFilters() {
+ return ioExceptionFilters;
}
// cookie store
- public Builder setCookieStore(CookieStore cookieStore) {
- this.cookieStore = cookieStore;
- return this;
+ @Override
+ public CookieStore getCookieStore() {
+ return cookieStore;
}
- public Builder setExpiredCookieEvictionDelay(int expiredCookieEvictionDelay) {
- this.expiredCookieEvictionDelay = expiredCookieEvictionDelay;
- return this;
+ @Override
+ public int expiredCookieEvictionDelay() {
+ return expiredCookieEvictionDelay;
}
// tuning
- public Builder setTcpNoDelay(boolean tcpNoDelay) {
- this.tcpNoDelay = tcpNoDelay;
- return this;
+ @Override
+ public boolean isTcpNoDelay() {
+ return tcpNoDelay;
}
- public Builder setSoReuseAddress(boolean soReuseAddress) {
- this.soReuseAddress = soReuseAddress;
- return this;
+ @Override
+ public boolean isSoReuseAddress() {
+ return soReuseAddress;
}
- public Builder setSoKeepAlive(boolean soKeepAlive) {
- this.soKeepAlive = soKeepAlive;
- return this;
+ @Override
+ public boolean isSoKeepAlive() {
+ return soKeepAlive;
}
- public Builder setSoLinger(int soLinger) {
- this.soLinger = soLinger;
- return this;
+ @Override
+ public int getSoLinger() {
+ return soLinger;
}
- public Builder setSoSndBuf(int soSndBuf) {
- this.soSndBuf = soSndBuf;
- return this;
+ @Override
+ public int getSoSndBuf() {
+ return soSndBuf;
}
- public Builder setSoRcvBuf(int soRcvBuf) {
- this.soRcvBuf = soRcvBuf;
- return this;
+ @Override
+ public int getSoRcvBuf() {
+ return soRcvBuf;
}
// internals
- public Builder setThreadPoolName(String threadPoolName) {
- this.threadPoolName = threadPoolName;
- return this;
+ @Override
+ public String getThreadPoolName() {
+ return threadPoolName;
}
- public Builder setHttpClientCodecMaxInitialLineLength(int httpClientCodecMaxInitialLineLength) {
- this.httpClientCodecMaxInitialLineLength = httpClientCodecMaxInitialLineLength;
- return this;
+ @Override
+ public int getHttpClientCodecMaxInitialLineLength() {
+ return httpClientCodecMaxInitialLineLength;
}
- public Builder setHttpClientCodecMaxHeaderSize(int httpClientCodecMaxHeaderSize) {
- this.httpClientCodecMaxHeaderSize = httpClientCodecMaxHeaderSize;
- return this;
+ @Override
+ public int getHttpClientCodecMaxHeaderSize() {
+ return httpClientCodecMaxHeaderSize;
}
- public Builder setHttpClientCodecMaxChunkSize(int httpClientCodecMaxChunkSize) {
- this.httpClientCodecMaxChunkSize = httpClientCodecMaxChunkSize;
- return this;
+ @Override
+ public int getHttpClientCodecMaxChunkSize() {
+ return httpClientCodecMaxChunkSize;
}
- public Builder setHttpClientCodecInitialBufferSize(int httpClientCodecInitialBufferSize) {
- this.httpClientCodecInitialBufferSize = httpClientCodecInitialBufferSize;
- return this;
+ @Override
+ public int getHttpClientCodecInitialBufferSize() {
+ return httpClientCodecInitialBufferSize;
}
- public Builder setChunkedFileChunkSize(int chunkedFileChunkSize) {
- this.chunkedFileChunkSize = chunkedFileChunkSize;
- return this;
+ @Override
+ public int getChunkedFileChunkSize() {
+ return chunkedFileChunkSize;
}
- public Builder setHashedWheelTickDuration(long hashedWheelTickDuration) {
- this.hashedWheelTickDuration = hashedWheelTickDuration;
- return this;
+ @Override
+ public Map, Object> getChannelOptions() {
+ return channelOptions;
}
- public Builder setHashedWheelSize(int hashedWheelSize) {
- this.hashedWheelSize = hashedWheelSize;
- return this;
+ @Override
+ public EventLoopGroup getEventLoopGroup() {
+ return eventLoopGroup;
}
- @SuppressWarnings("unchecked")
- public Builder addChannelOption(ChannelOption name, T value) {
- channelOptions.put((ChannelOption) name, value);
- return this;
+ @Override
+ public boolean isUseNativeTransport() {
+ return useNativeTransport;
}
- public Builder setEventLoopGroup(EventLoopGroup eventLoopGroup) {
- this.eventLoopGroup = eventLoopGroup;
- return this;
+ @Override
+ public boolean isUseOnlyEpollNativeTransport() {
+ return useOnlyEpollNativeTransport;
}
- public Builder setUseNativeTransport(boolean useNativeTransport) {
- this.useNativeTransport = useNativeTransport;
- return this;
+ @Override
+ public ByteBufAllocator getAllocator() {
+ return allocator;
}
- public Builder setAllocator(ByteBufAllocator allocator) {
- this.allocator = allocator;
- return this;
+ @Override
+ public Timer getNettyTimer() {
+ return nettyTimer;
}
- public Builder setNettyTimer(Timer nettyTimer) {
- this.nettyTimer = nettyTimer;
- return this;
+ @Override
+ public long getHashedWheelTimerTickDuration() {
+ return hashedWheelTimerTickDuration;
}
- public Builder setThreadFactory(ThreadFactory threadFactory) {
- this.threadFactory = threadFactory;
- return this;
+ @Override
+ public int getHashedWheelTimerSize() {
+ return hashedWheelTimerSize;
}
- public Builder setHttpAdditionalChannelInitializer(Consumer httpAdditionalChannelInitializer) {
- this.httpAdditionalChannelInitializer = httpAdditionalChannelInitializer;
- return this;
+ @Override
+ public ThreadFactory getThreadFactory() {
+ return threadFactory;
}
- public Builder setWsAdditionalChannelInitializer(Consumer wsAdditionalChannelInitializer) {
- this.wsAdditionalChannelInitializer = wsAdditionalChannelInitializer;
- return this;
+ @Override
+ public Consumer getHttpAdditionalChannelInitializer() {
+ return httpAdditionalChannelInitializer;
}
- public Builder setResponseBodyPartFactory(ResponseBodyPartFactory responseBodyPartFactory) {
- this.responseBodyPartFactory = responseBodyPartFactory;
- return this;
+ @Override
+ public Consumer getWsAdditionalChannelInitializer() {
+ return wsAdditionalChannelInitializer;
}
- public Builder setIoThreadsCount(int ioThreadsCount) {
- this.ioThreadsCount = ioThreadsCount;
- return this;
+ @Override
+ public ResponseBodyPartFactory getResponseBodyPartFactory() {
+ return responseBodyPartFactory;
}
- private ProxyServerSelector resolveProxyServerSelector() {
- if (proxyServerSelector != null)
- return proxyServerSelector;
+ @Override
+ public int getIoThreadsCount() {
+ return ioThreadsCount;
+ }
- if (useProxySelector)
- return ProxyUtils.getJdkDefaultProxyServerSelector();
-
- if (useProxyProperties)
- return ProxyUtils.createProxyServerSelector(System.getProperties());
-
- return ProxyServerSelector.NO_PROXY_SELECTOR;
- }
-
- public DefaultAsyncHttpClientConfig build() {
-
- return new DefaultAsyncHttpClientConfig(
- followRedirect,
- maxRedirects,
- strict302Handling,
- compressionEnforced,
- userAgent,
- realm,
- maxRequestRetry,
- disableUrlEncodingForBoundRequests,
- useLaxCookieEncoder,
- disableZeroCopy,
- keepEncodingHeader,
- resolveProxyServerSelector(),
- validateResponseHeaders,
- aggregateWebSocketFrameFragments,
- enablewebSocketCompression,
- connectTimeout,
- requestTimeout,
- readTimeout,
- shutdownQuietPeriod,
- shutdownTimeout,
- keepAlive,
- pooledConnectionIdleTimeout,
- connectionPoolCleanerPeriod,
- connectionTtl,
- maxConnections,
- maxConnectionsPerHost,
- acquireFreeChannelTimeout,
- channelPool,
- connectionSemaphoreFactory,
- keepAliveStrategy,
- useOpenSsl,
- useInsecureTrustManager,
- disableHttpsEndpointIdentificationAlgorithm,
- handshakeTimeout,
- enabledProtocols,
- enabledCipherSuites,
- filterInsecureCipherSuites,
- sslSessionCacheSize,
- sslSessionTimeout,
- sslContext,
- sslEngineFactory,
- requestFilters.isEmpty() ? Collections.emptyList() : Collections.unmodifiableList(requestFilters),
- responseFilters.isEmpty() ? Collections.emptyList() : Collections.unmodifiableList(responseFilters),
- ioExceptionFilters.isEmpty() ? Collections.emptyList() : Collections.unmodifiableList(ioExceptionFilters),
- cookieStore,
- expiredCookieEvictionDelay,
- tcpNoDelay,
- soReuseAddress,
- soKeepAlive,
- soLinger,
- soSndBuf,
- soRcvBuf,
- threadPoolName,
- httpClientCodecMaxInitialLineLength,
- httpClientCodecMaxHeaderSize,
- httpClientCodecMaxChunkSize,
- httpClientCodecInitialBufferSize,
- chunkedFileChunkSize,
- webSocketMaxBufferSize,
- webSocketMaxFrameSize,
- channelOptions.isEmpty() ? Collections.emptyMap() : Collections.unmodifiableMap(channelOptions),
- eventLoopGroup,
- useNativeTransport,
- allocator,
- nettyTimer,
- threadFactory,
- httpAdditionalChannelInitializer,
- wsAdditionalChannelInitializer,
- responseBodyPartFactory,
- ioThreadsCount,
- hashedWheelTickDuration,
- hashedWheelSize);
- }
- }
+ /**
+ * Builder for an {@link AsyncHttpClient}
+ */
+ public static class Builder {
+
+ // filters
+ private final List requestFilters = new LinkedList<>();
+ private final List responseFilters = new LinkedList<>();
+ private final List ioExceptionFilters = new LinkedList<>();
+ // http
+ private boolean followRedirect = defaultFollowRedirect();
+ private int maxRedirects = defaultMaxRedirects();
+ private boolean strict302Handling = defaultStrict302Handling();
+ private boolean compressionEnforced = defaultCompressionEnforced();
+ private String userAgent = defaultUserAgent();
+ private Realm realm;
+ private int maxRequestRetry = defaultMaxRequestRetry();
+ private boolean disableUrlEncodingForBoundRequests = defaultDisableUrlEncodingForBoundRequests();
+ private boolean useLaxCookieEncoder = defaultUseLaxCookieEncoder();
+ private boolean disableZeroCopy = defaultDisableZeroCopy();
+ private boolean keepEncodingHeader = defaultKeepEncodingHeader();
+ private ProxyServerSelector proxyServerSelector;
+ private boolean useProxySelector = defaultUseProxySelector();
+ private boolean useProxyProperties = defaultUseProxyProperties();
+ private boolean validateResponseHeaders = defaultValidateResponseHeaders();
+
+ // websocket
+ private boolean aggregateWebSocketFrameFragments = defaultAggregateWebSocketFrameFragments();
+ private boolean enablewebSocketCompression = defaultEnableWebSocketCompression();
+ private int webSocketMaxBufferSize = defaultWebSocketMaxBufferSize();
+ private int webSocketMaxFrameSize = defaultWebSocketMaxFrameSize();
+
+ // timeouts
+ private int connectTimeout = defaultConnectTimeout();
+ private int requestTimeout = defaultRequestTimeout();
+ private int readTimeout = defaultReadTimeout();
+ private int shutdownQuietPeriod = defaultShutdownQuietPeriod();
+ private int shutdownTimeout = defaultShutdownTimeout();
+
+ // keep-alive
+ private boolean keepAlive = defaultKeepAlive();
+ private int pooledConnectionIdleTimeout = defaultPooledConnectionIdleTimeout();
+ private int connectionPoolCleanerPeriod = defaultConnectionPoolCleanerPeriod();
+ private int connectionTtl = defaultConnectionTtl();
+ private int maxConnections = defaultMaxConnections();
+ private int maxConnectionsPerHost = defaultMaxConnectionsPerHost();
+ private int acquireFreeChannelTimeout = defaultAcquireFreeChannelTimeout();
+ private ChannelPool channelPool;
+ private ConnectionSemaphoreFactory connectionSemaphoreFactory;
+ private KeepAliveStrategy keepAliveStrategy = new DefaultKeepAliveStrategy();
+
+ // ssl
+ private boolean useOpenSsl = defaultUseOpenSsl();
+ private boolean useInsecureTrustManager = defaultUseInsecureTrustManager();
+ private boolean disableHttpsEndpointIdentificationAlgorithm = defaultDisableHttpsEndpointIdentificationAlgorithm();
+ private int handshakeTimeout = defaultHandshakeTimeout();
+ private String[] enabledProtocols = defaultEnabledProtocols();
+ private String[] enabledCipherSuites = defaultEnabledCipherSuites();
+ private boolean filterInsecureCipherSuites = defaultFilterInsecureCipherSuites();
+ private int sslSessionCacheSize = defaultSslSessionCacheSize();
+ private int sslSessionTimeout = defaultSslSessionTimeout();
+ private SslContext sslContext;
+ private SslEngineFactory sslEngineFactory;
+
+ // cookie store
+ private CookieStore cookieStore = new ThreadSafeCookieStore();
+ private int expiredCookieEvictionDelay = defaultExpiredCookieEvictionDelay();
+
+ // tuning
+ private boolean tcpNoDelay = defaultTcpNoDelay();
+ private boolean soReuseAddress = defaultSoReuseAddress();
+ private boolean soKeepAlive = defaultSoKeepAlive();
+ private int soLinger = defaultSoLinger();
+ private int soSndBuf = defaultSoSndBuf();
+ private int soRcvBuf = defaultSoRcvBuf();
+
+ // internals
+ private String threadPoolName = defaultThreadPoolName();
+ private int httpClientCodecMaxInitialLineLength = defaultHttpClientCodecMaxInitialLineLength();
+ private int httpClientCodecMaxHeaderSize = defaultHttpClientCodecMaxHeaderSize();
+ private int httpClientCodecMaxChunkSize = defaultHttpClientCodecMaxChunkSize();
+ private int httpClientCodecInitialBufferSize = defaultHttpClientCodecInitialBufferSize();
+ private int chunkedFileChunkSize = defaultChunkedFileChunkSize();
+ private boolean useNativeTransport = defaultUseNativeTransport();
+ private boolean useOnlyEpollNativeTransport = defaultUseOnlyEpollNativeTransport();
+ private ByteBufAllocator allocator;
+ private final Map, Object> channelOptions = new HashMap<>();
+ private EventLoopGroup eventLoopGroup;
+ private Timer nettyTimer;
+ private ThreadFactory threadFactory;
+ private Consumer httpAdditionalChannelInitializer;
+ private Consumer wsAdditionalChannelInitializer;
+ private ResponseBodyPartFactory responseBodyPartFactory = ResponseBodyPartFactory.EAGER;
+ private int ioThreadsCount = defaultIoThreadsCount();
+ private long hashedWheelTickDuration = defaultHashedWheelTimerTickDuration();
+ private int hashedWheelSize = defaultHashedWheelTimerSize();
+
+ public Builder() {
+ }
+
+ public Builder(AsyncHttpClientConfig config) {
+ // http
+ followRedirect = config.isFollowRedirect();
+ maxRedirects = config.getMaxRedirects();
+ strict302Handling = config.isStrict302Handling();
+ compressionEnforced = config.isCompressionEnforced();
+ userAgent = config.getUserAgent();
+ realm = config.getRealm();
+ maxRequestRetry = config.getMaxRequestRetry();
+ disableUrlEncodingForBoundRequests = config.isDisableUrlEncodingForBoundRequests();
+ useLaxCookieEncoder = config.isUseLaxCookieEncoder();
+ disableZeroCopy = config.isDisableZeroCopy();
+ keepEncodingHeader = config.isKeepEncodingHeader();
+ proxyServerSelector = config.getProxyServerSelector();
+
+ // websocket
+ aggregateWebSocketFrameFragments = config.isAggregateWebSocketFrameFragments();
+ enablewebSocketCompression = config.isEnableWebSocketCompression();
+ webSocketMaxBufferSize = config.getWebSocketMaxBufferSize();
+ webSocketMaxFrameSize = config.getWebSocketMaxFrameSize();
+
+ // timeouts
+ connectTimeout = config.getConnectTimeout();
+ requestTimeout = config.getRequestTimeout();
+ readTimeout = config.getReadTimeout();
+ shutdownQuietPeriod = config.getShutdownQuietPeriod();
+ shutdownTimeout = config.getShutdownTimeout();
+
+ // keep-alive
+ keepAlive = config.isKeepAlive();
+ pooledConnectionIdleTimeout = config.getPooledConnectionIdleTimeout();
+ connectionTtl = config.getConnectionTtl();
+ maxConnections = config.getMaxConnections();
+ maxConnectionsPerHost = config.getMaxConnectionsPerHost();
+ channelPool = config.getChannelPool();
+ connectionSemaphoreFactory = config.getConnectionSemaphoreFactory();
+ keepAliveStrategy = config.getKeepAliveStrategy();
+
+ // ssl
+ useInsecureTrustManager = config.isUseInsecureTrustManager();
+ handshakeTimeout = config.getHandshakeTimeout();
+ enabledProtocols = config.getEnabledProtocols();
+ enabledCipherSuites = config.getEnabledCipherSuites();
+ filterInsecureCipherSuites = config.isFilterInsecureCipherSuites();
+ sslSessionCacheSize = config.getSslSessionCacheSize();
+ sslSessionTimeout = config.getSslSessionTimeout();
+ sslContext = config.getSslContext();
+ sslEngineFactory = config.getSslEngineFactory();
+
+ // filters
+ requestFilters.addAll(config.getRequestFilters());
+ responseFilters.addAll(config.getResponseFilters());
+ ioExceptionFilters.addAll(config.getIoExceptionFilters());
+
+ // tuning
+ tcpNoDelay = config.isTcpNoDelay();
+ soReuseAddress = config.isSoReuseAddress();
+ soKeepAlive = config.isSoKeepAlive();
+ soLinger = config.getSoLinger();
+ soSndBuf = config.getSoSndBuf();
+ soRcvBuf = config.getSoRcvBuf();
+
+ // internals
+ threadPoolName = config.getThreadPoolName();
+ httpClientCodecMaxInitialLineLength = config.getHttpClientCodecMaxInitialLineLength();
+ httpClientCodecMaxHeaderSize = config.getHttpClientCodecMaxHeaderSize();
+ httpClientCodecMaxChunkSize = config.getHttpClientCodecMaxChunkSize();
+ chunkedFileChunkSize = config.getChunkedFileChunkSize();
+ channelOptions.putAll(config.getChannelOptions());
+ eventLoopGroup = config.getEventLoopGroup();
+ useNativeTransport = config.isUseNativeTransport();
+ useOnlyEpollNativeTransport = config.isUseOnlyEpollNativeTransport();
+
+ allocator = config.getAllocator();
+ nettyTimer = config.getNettyTimer();
+ threadFactory = config.getThreadFactory();
+ httpAdditionalChannelInitializer = config.getHttpAdditionalChannelInitializer();
+ wsAdditionalChannelInitializer = config.getWsAdditionalChannelInitializer();
+ responseBodyPartFactory = config.getResponseBodyPartFactory();
+ ioThreadsCount = config.getIoThreadsCount();
+ hashedWheelTickDuration = config.getHashedWheelTimerTickDuration();
+ hashedWheelSize = config.getHashedWheelTimerSize();
+ }
+
+ // http
+ public Builder setFollowRedirect(boolean followRedirect) {
+ this.followRedirect = followRedirect;
+ return this;
+ }
+
+ public Builder setMaxRedirects(int maxRedirects) {
+ this.maxRedirects = maxRedirects;
+ return this;
+ }
+
+ public Builder setStrict302Handling(final boolean strict302Handling) {
+ this.strict302Handling = strict302Handling;
+ return this;
+ }
+
+ public Builder setCompressionEnforced(boolean compressionEnforced) {
+ this.compressionEnforced = compressionEnforced;
+ return this;
+ }
+
+ public Builder setUserAgent(String userAgent) {
+ this.userAgent = userAgent;
+ return this;
+ }
+
+ public Builder setRealm(Realm realm) {
+ this.realm = realm;
+ return this;
+ }
+
+ public Builder setRealm(Realm.Builder realmBuilder) {
+ realm = realmBuilder.build();
+ return this;
+ }
+
+ public Builder setMaxRequestRetry(int maxRequestRetry) {
+ this.maxRequestRetry = maxRequestRetry;
+ return this;
+ }
+
+ public Builder setDisableUrlEncodingForBoundRequests(boolean disableUrlEncodingForBoundRequests) {
+ this.disableUrlEncodingForBoundRequests = disableUrlEncodingForBoundRequests;
+ return this;
+ }
+
+ public Builder setUseLaxCookieEncoder(boolean useLaxCookieEncoder) {
+ this.useLaxCookieEncoder = useLaxCookieEncoder;
+ return this;
+ }
+
+ public Builder setDisableZeroCopy(boolean disableZeroCopy) {
+ this.disableZeroCopy = disableZeroCopy;
+ return this;
+ }
+
+ public Builder setKeepEncodingHeader(boolean keepEncodingHeader) {
+ this.keepEncodingHeader = keepEncodingHeader;
+ return this;
+ }
+
+ public Builder setProxyServerSelector(ProxyServerSelector proxyServerSelector) {
+ this.proxyServerSelector = proxyServerSelector;
+ return this;
+ }
+
+ public Builder setValidateResponseHeaders(boolean validateResponseHeaders) {
+ this.validateResponseHeaders = validateResponseHeaders;
+ return this;
+ }
+
+ public Builder setProxyServer(ProxyServer proxyServer) {
+ proxyServerSelector = uri -> proxyServer;
+ return this;
+ }
+
+ public Builder setProxyServer(ProxyServer.Builder proxyServerBuilder) {
+ return setProxyServer(proxyServerBuilder.build());
+ }
+
+ public Builder setUseProxySelector(boolean useProxySelector) {
+ this.useProxySelector = useProxySelector;
+ return this;
+ }
+
+ public Builder setUseProxyProperties(boolean useProxyProperties) {
+ this.useProxyProperties = useProxyProperties;
+ return this;
+ }
+
+ // websocket
+ public Builder setAggregateWebSocketFrameFragments(boolean aggregateWebSocketFrameFragments) {
+ this.aggregateWebSocketFrameFragments = aggregateWebSocketFrameFragments;
+ return this;
+ }
+
+ public Builder setEnablewebSocketCompression(boolean enablewebSocketCompression) {
+ this.enablewebSocketCompression = enablewebSocketCompression;
+ return this;
+ }
+
+ public Builder setWebSocketMaxBufferSize(int webSocketMaxBufferSize) {
+ this.webSocketMaxBufferSize = webSocketMaxBufferSize;
+ return this;
+ }
+
+ public Builder setWebSocketMaxFrameSize(int webSocketMaxFrameSize) {
+ this.webSocketMaxFrameSize = webSocketMaxFrameSize;
+ return this;
+ }
+
+ // timeouts
+ public Builder setConnectTimeout(int connectTimeout) {
+ this.connectTimeout = connectTimeout;
+ return this;
+ }
+
+ public Builder setRequestTimeout(int requestTimeout) {
+ this.requestTimeout = requestTimeout;
+ return this;
+ }
+
+ public Builder setReadTimeout(int readTimeout) {
+ this.readTimeout = readTimeout;
+ return this;
+ }
+
+ public Builder setShutdownQuietPeriod(int shutdownQuietPeriod) {
+ this.shutdownQuietPeriod = shutdownQuietPeriod;
+ return this;
+ }
+
+ public Builder setShutdownTimeout(int shutdownTimeout) {
+ this.shutdownTimeout = shutdownTimeout;
+ return this;
+ }
+
+ // keep-alive
+ public Builder setKeepAlive(boolean keepAlive) {
+ this.keepAlive = keepAlive;
+ return this;
+ }
+
+ public Builder setPooledConnectionIdleTimeout(int pooledConnectionIdleTimeout) {
+ this.pooledConnectionIdleTimeout = pooledConnectionIdleTimeout;
+ return this;
+ }
+
+ public Builder setConnectionPoolCleanerPeriod(int connectionPoolCleanerPeriod) {
+ this.connectionPoolCleanerPeriod = connectionPoolCleanerPeriod;
+ return this;
+ }
+
+ public Builder setConnectionTtl(int connectionTtl) {
+ this.connectionTtl = connectionTtl;
+ return this;
+ }
+
+ public Builder setMaxConnections(int maxConnections) {
+ this.maxConnections = maxConnections;
+ return this;
+ }
+
+ public Builder setMaxConnectionsPerHost(int maxConnectionsPerHost) {
+ this.maxConnectionsPerHost = maxConnectionsPerHost;
+ return this;
+ }
+
+ /**
+ * Sets the maximum duration in milliseconds to acquire a free channel to send a request
+ *
+ * @param acquireFreeChannelTimeout maximum duration in milliseconds to acquire a free channel to send a request
+ * @return the same builder instance
+ */
+ public Builder setAcquireFreeChannelTimeout(int acquireFreeChannelTimeout) {
+ this.acquireFreeChannelTimeout = acquireFreeChannelTimeout;
+ return this;
+ }
+
+ public Builder setChannelPool(ChannelPool channelPool) {
+ this.channelPool = channelPool;
+ return this;
+ }
+
+ public Builder setConnectionSemaphoreFactory(ConnectionSemaphoreFactory connectionSemaphoreFactory) {
+ this.connectionSemaphoreFactory = connectionSemaphoreFactory;
+ return this;
+ }
+
+ public Builder setKeepAliveStrategy(KeepAliveStrategy keepAliveStrategy) {
+ this.keepAliveStrategy = keepAliveStrategy;
+ return this;
+ }
+
+ // ssl
+ public Builder setUseOpenSsl(boolean useOpenSsl) {
+ this.useOpenSsl = useOpenSsl;
+ return this;
+ }
+
+ public Builder setUseInsecureTrustManager(boolean useInsecureTrustManager) {
+ this.useInsecureTrustManager = useInsecureTrustManager;
+ return this;
+ }
+
+ public Builder setDisableHttpsEndpointIdentificationAlgorithm(boolean disableHttpsEndpointIdentificationAlgorithm) {
+ this.disableHttpsEndpointIdentificationAlgorithm = disableHttpsEndpointIdentificationAlgorithm;
+ return this;
+ }
+
+ public Builder setHandshakeTimeout(int handshakeTimeout) {
+ this.handshakeTimeout = handshakeTimeout;
+ return this;
+ }
+
+ public Builder setEnabledProtocols(String[] enabledProtocols) {
+ this.enabledProtocols = enabledProtocols;
+ return this;
+ }
+
+ public Builder setEnabledCipherSuites(String[] enabledCipherSuites) {
+ this.enabledCipherSuites = enabledCipherSuites;
+ return this;
+ }
+
+ public Builder setFilterInsecureCipherSuites(boolean filterInsecureCipherSuites) {
+ this.filterInsecureCipherSuites = filterInsecureCipherSuites;
+ return this;
+ }
+
+ public Builder setSslSessionCacheSize(Integer sslSessionCacheSize) {
+ this.sslSessionCacheSize = sslSessionCacheSize;
+ return this;
+ }
+
+ public Builder setSslSessionTimeout(Integer sslSessionTimeout) {
+ this.sslSessionTimeout = sslSessionTimeout;
+ return this;
+ }
+
+ public Builder setSslContext(final SslContext sslContext) {
+ this.sslContext = sslContext;
+ return this;
+ }
+
+ public Builder setSslEngineFactory(SslEngineFactory sslEngineFactory) {
+ this.sslEngineFactory = sslEngineFactory;
+ return this;
+ }
+
+ // filters
+ public Builder addRequestFilter(RequestFilter requestFilter) {
+ requestFilters.add(requestFilter);
+ return this;
+ }
+
+ public Builder removeRequestFilter(RequestFilter requestFilter) {
+ requestFilters.remove(requestFilter);
+ return this;
+ }
+
+ public Builder addResponseFilter(ResponseFilter responseFilter) {
+ responseFilters.add(responseFilter);
+ return this;
+ }
+
+ public Builder removeResponseFilter(ResponseFilter responseFilter) {
+ responseFilters.remove(responseFilter);
+ return this;
+ }
+
+ public Builder addIOExceptionFilter(IOExceptionFilter ioExceptionFilter) {
+ ioExceptionFilters.add(ioExceptionFilter);
+ return this;
+ }
+
+ public Builder removeIOExceptionFilter(IOExceptionFilter ioExceptionFilter) {
+ ioExceptionFilters.remove(ioExceptionFilter);
+ return this;
+ }
+
+ // cookie store
+ public Builder setCookieStore(CookieStore cookieStore) {
+ this.cookieStore = cookieStore;
+ return this;
+ }
+
+ public Builder setExpiredCookieEvictionDelay(int expiredCookieEvictionDelay) {
+ this.expiredCookieEvictionDelay = expiredCookieEvictionDelay;
+ return this;
+ }
+
+ // tuning
+ public Builder setTcpNoDelay(boolean tcpNoDelay) {
+ this.tcpNoDelay = tcpNoDelay;
+ return this;
+ }
+
+ public Builder setSoReuseAddress(boolean soReuseAddress) {
+ this.soReuseAddress = soReuseAddress;
+ return this;
+ }
+
+ public Builder setSoKeepAlive(boolean soKeepAlive) {
+ this.soKeepAlive = soKeepAlive;
+ return this;
+ }
+
+ public Builder setSoLinger(int soLinger) {
+ this.soLinger = soLinger;
+ return this;
+ }
+
+ public Builder setSoSndBuf(int soSndBuf) {
+ this.soSndBuf = soSndBuf;
+ return this;
+ }
+
+ public Builder setSoRcvBuf(int soRcvBuf) {
+ this.soRcvBuf = soRcvBuf;
+ return this;
+ }
+
+ // internals
+ public Builder setThreadPoolName(String threadPoolName) {
+ this.threadPoolName = threadPoolName;
+ return this;
+ }
+
+ public Builder setHttpClientCodecMaxInitialLineLength(int httpClientCodecMaxInitialLineLength) {
+ this.httpClientCodecMaxInitialLineLength = httpClientCodecMaxInitialLineLength;
+ return this;
+ }
+
+ public Builder setHttpClientCodecMaxHeaderSize(int httpClientCodecMaxHeaderSize) {
+ this.httpClientCodecMaxHeaderSize = httpClientCodecMaxHeaderSize;
+ return this;
+ }
+
+ public Builder setHttpClientCodecMaxChunkSize(int httpClientCodecMaxChunkSize) {
+ this.httpClientCodecMaxChunkSize = httpClientCodecMaxChunkSize;
+ return this;
+ }
+
+ public Builder setHttpClientCodecInitialBufferSize(int httpClientCodecInitialBufferSize) {
+ this.httpClientCodecInitialBufferSize = httpClientCodecInitialBufferSize;
+ return this;
+ }
+
+ public Builder setChunkedFileChunkSize(int chunkedFileChunkSize) {
+ this.chunkedFileChunkSize = chunkedFileChunkSize;
+ return this;
+ }
+
+ public Builder setHashedWheelTickDuration(long hashedWheelTickDuration) {
+ this.hashedWheelTickDuration = hashedWheelTickDuration;
+ return this;
+ }
+
+ public Builder setHashedWheelSize(int hashedWheelSize) {
+ this.hashedWheelSize = hashedWheelSize;
+ return this;
+ }
+
+ @SuppressWarnings("unchecked")
+ public Builder addChannelOption(ChannelOption name, T value) {
+ channelOptions.put((ChannelOption) name, value);
+ return this;
+ }
+
+ public Builder setEventLoopGroup(EventLoopGroup eventLoopGroup) {
+ this.eventLoopGroup = eventLoopGroup;
+ return this;
+ }
+
+ public Builder setUseNativeTransport(boolean useNativeTransport) {
+ this.useNativeTransport = useNativeTransport;
+ return this;
+ }
+
+ public Builder setUseOnlyEpollNativeTransport(boolean useOnlyEpollNativeTransport) {
+ this.useOnlyEpollNativeTransport = useOnlyEpollNativeTransport;
+ return this;
+ }
+
+ public Builder setAllocator(ByteBufAllocator allocator) {
+ this.allocator = allocator;
+ return this;
+ }
+
+ public Builder setNettyTimer(Timer nettyTimer) {
+ this.nettyTimer = nettyTimer;
+ return this;
+ }
+
+ public Builder setThreadFactory(ThreadFactory threadFactory) {
+ this.threadFactory = threadFactory;
+ return this;
+ }
+
+ public Builder setHttpAdditionalChannelInitializer(Consumer httpAdditionalChannelInitializer) {
+ this.httpAdditionalChannelInitializer = httpAdditionalChannelInitializer;
+ return this;
+ }
+
+ public Builder setWsAdditionalChannelInitializer(Consumer wsAdditionalChannelInitializer) {
+ this.wsAdditionalChannelInitializer = wsAdditionalChannelInitializer;
+ return this;
+ }
+
+ public Builder setResponseBodyPartFactory(ResponseBodyPartFactory responseBodyPartFactory) {
+ this.responseBodyPartFactory = responseBodyPartFactory;
+ return this;
+ }
+
+ public Builder setIoThreadsCount(int ioThreadsCount) {
+ this.ioThreadsCount = ioThreadsCount;
+ return this;
+ }
+
+ private ProxyServerSelector resolveProxyServerSelector() {
+ if (proxyServerSelector != null) {
+ return proxyServerSelector;
+ }
+
+ if (useProxySelector) {
+ return ProxyUtils.getJdkDefaultProxyServerSelector();
+ }
+
+ if (useProxyProperties) {
+ return ProxyUtils.createProxyServerSelector(System.getProperties());
+ }
+
+ return ProxyServerSelector.NO_PROXY_SELECTOR;
+ }
+
+ public DefaultAsyncHttpClientConfig build() {
+
+ return new DefaultAsyncHttpClientConfig(
+ followRedirect,
+ maxRedirects,
+ strict302Handling,
+ compressionEnforced,
+ userAgent,
+ realm,
+ maxRequestRetry,
+ disableUrlEncodingForBoundRequests,
+ useLaxCookieEncoder,
+ disableZeroCopy,
+ keepEncodingHeader,
+ resolveProxyServerSelector(),
+ validateResponseHeaders,
+ aggregateWebSocketFrameFragments,
+ enablewebSocketCompression,
+ connectTimeout,
+ requestTimeout,
+ readTimeout,
+ shutdownQuietPeriod,
+ shutdownTimeout,
+ keepAlive,
+ pooledConnectionIdleTimeout,
+ connectionPoolCleanerPeriod,
+ connectionTtl,
+ maxConnections,
+ maxConnectionsPerHost,
+ acquireFreeChannelTimeout,
+ channelPool,
+ connectionSemaphoreFactory,
+ keepAliveStrategy,
+ useOpenSsl,
+ useInsecureTrustManager,
+ disableHttpsEndpointIdentificationAlgorithm,
+ handshakeTimeout,
+ enabledProtocols,
+ enabledCipherSuites,
+ filterInsecureCipherSuites,
+ sslSessionCacheSize,
+ sslSessionTimeout,
+ sslContext,
+ sslEngineFactory,
+ requestFilters.isEmpty() ? Collections.emptyList() : Collections.unmodifiableList(requestFilters),
+ responseFilters.isEmpty() ? Collections.emptyList() : Collections.unmodifiableList(responseFilters),
+ ioExceptionFilters.isEmpty() ? Collections.emptyList() : Collections.unmodifiableList(ioExceptionFilters),
+ cookieStore,
+ expiredCookieEvictionDelay,
+ tcpNoDelay,
+ soReuseAddress,
+ soKeepAlive,
+ soLinger,
+ soSndBuf,
+ soRcvBuf,
+ threadPoolName,
+ httpClientCodecMaxInitialLineLength,
+ httpClientCodecMaxHeaderSize,
+ httpClientCodecMaxChunkSize,
+ httpClientCodecInitialBufferSize,
+ chunkedFileChunkSize,
+ webSocketMaxBufferSize,
+ webSocketMaxFrameSize,
+ channelOptions.isEmpty() ? Collections.emptyMap() : Collections.unmodifiableMap(channelOptions),
+ eventLoopGroup,
+ useNativeTransport,
+ useOnlyEpollNativeTransport,
+ allocator,
+ nettyTimer,
+ threadFactory,
+ httpAdditionalChannelInitializer,
+ wsAdditionalChannelInitializer,
+ responseBodyPartFactory,
+ ioThreadsCount,
+ hashedWheelTickDuration,
+ hashedWheelSize);
+ }
+ }
}
diff --git a/client/src/main/java/org/asynchttpclient/DefaultRequest.java b/client/src/main/java/org/asynchttpclient/DefaultRequest.java
index 4cabb41792..07347ce05b 100644
--- a/client/src/main/java/org/asynchttpclient/DefaultRequest.java
+++ b/client/src/main/java/org/asynchttpclient/DefaultRequest.java
@@ -1,15 +1,17 @@
/*
- * Copyright (c) 2015 AsyncHttpClient Project. All rights reserved.
+ * Copyright (c) 2015-2023 AsyncHttpClient Project. All rights reserved.
*
- * This program is licensed to you under the Apache License Version 2.0,
- * and you may not use this file except in compliance with the Apache License Version 2.0.
- * You may obtain a copy of the Apache License Version 2.0 at
- * http://www.apache.org/licenses/LICENSE-2.0.
+ * 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
*
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the Apache License Version 2.0 is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the Apache License Version 2.0 for the specific language governing permissions and limitations there under.
+ * 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 org.asynchttpclient;
@@ -36,259 +38,263 @@
public class DefaultRequest implements Request {
- public final ProxyServer proxyServer;
- private final String method;
- private final Uri uri;
- private final InetAddress address;
- private final InetAddress localAddress;
- private final HttpHeaders headers;
- private final List cookies;
- private final byte[] byteData;
- private final List compositeByteData;
- private final String stringData;
- private final ByteBuffer byteBufferData;
- private final InputStream streamData;
- private final BodyGenerator bodyGenerator;
- private final List formParams;
- private final List bodyParts;
- private final String virtualHost;
- private final Realm realm;
- private final File file;
- private final Boolean followRedirect;
- private final int requestTimeout;
- private final int readTimeout;
- private final long rangeOffset;
- private final Charset charset;
- private final ChannelPoolPartitioning channelPoolPartitioning;
- private final NameResolver nameResolver;
- // lazily loaded
- private List queryParams;
-
- public DefaultRequest(String method,
- Uri uri,
- InetAddress address,
- InetAddress localAddress,
- HttpHeaders headers,
- List cookies,
- byte[] byteData,
- List compositeByteData,
- String stringData,
- ByteBuffer byteBufferData,
- InputStream streamData,
- BodyGenerator bodyGenerator,
- List formParams,
- List bodyParts,
- String virtualHost,
- ProxyServer proxyServer,
- Realm realm,
- File file,
- Boolean followRedirect,
- int requestTimeout,
- int readTimeout,
- long rangeOffset,
- Charset charset,
- ChannelPoolPartitioning channelPoolPartitioning,
- NameResolver nameResolver) {
- this.method = method;
- this.uri = uri;
- this.address = address;
- this.localAddress = localAddress;
- this.headers = headers;
- this.cookies = cookies;
- this.byteData = byteData;
- this.compositeByteData = compositeByteData;
- this.stringData = stringData;
- this.byteBufferData = byteBufferData;
- this.streamData = streamData;
- this.bodyGenerator = bodyGenerator;
- this.formParams = formParams;
- this.bodyParts = bodyParts;
- this.virtualHost = virtualHost;
- this.proxyServer = proxyServer;
- this.realm = realm;
- this.file = file;
- this.followRedirect = followRedirect;
- this.requestTimeout = requestTimeout;
- this.readTimeout = readTimeout;
- this.rangeOffset = rangeOffset;
- this.charset = charset;
- this.channelPoolPartitioning = channelPoolPartitioning;
- this.nameResolver = nameResolver;
- }
-
- @Override
- public String getUrl() {
- return uri.toUrl();
- }
-
- @Override
- public String getMethod() {
- return method;
- }
-
- @Override
- public Uri getUri() {
- return uri;
- }
-
- @Override
- public InetAddress getAddress() {
- return address;
- }
-
- @Override
- public InetAddress getLocalAddress() {
- return localAddress;
- }
-
- @Override
- public HttpHeaders getHeaders() {
- return headers;
- }
-
- @Override
- public List getCookies() {
- return cookies;
- }
-
- @Override
- public byte[] getByteData() {
- return byteData;
- }
-
- @Override
- public List getCompositeByteData() {
- return compositeByteData;
- }
-
- @Override
- public String getStringData() {
- return stringData;
- }
-
- @Override
- public ByteBuffer getByteBufferData() {
- return byteBufferData;
- }
-
- @Override
- public InputStream getStreamData() {
- return streamData;
- }
-
- @Override
- public BodyGenerator getBodyGenerator() {
- return bodyGenerator;
- }
-
- @Override
- public List getFormParams() {
- return formParams;
- }
-
- @Override
- public List getBodyParts() {
- return bodyParts;
- }
-
- @Override
- public String getVirtualHost() {
- return virtualHost;
- }
-
- @Override
- public ProxyServer getProxyServer() {
- return proxyServer;
- }
-
- @Override
- public Realm getRealm() {
- return realm;
- }
-
- @Override
- public File getFile() {
- return file;
- }
-
- @Override
- public Boolean getFollowRedirect() {
- return followRedirect;
- }
-
- @Override
- public int getRequestTimeout() {
- return requestTimeout;
- }
-
- @Override
- public int getReadTimeout() {
- return readTimeout;
- }
-
- @Override
- public long getRangeOffset() {
- return rangeOffset;
- }
-
- @Override
- public Charset getCharset() {
- return charset;
- }
-
- @Override
- public ChannelPoolPartitioning getChannelPoolPartitioning() {
- return channelPoolPartitioning;
- }
-
- @Override
- public NameResolver getNameResolver() {
- return nameResolver;
- }
-
- @Override
- public List getQueryParams() {
- if (queryParams == null)
- // lazy load
- if (isNonEmpty(uri.getQuery())) {
- queryParams = new ArrayList<>(1);
- for (String queryStringParam : uri.getQuery().split("&")) {
- int pos = queryStringParam.indexOf('=');
- if (pos <= 0)
- queryParams.add(new Param(queryStringParam, null));
- else
- queryParams.add(new Param(queryStringParam.substring(0, pos), queryStringParam.substring(pos + 1)));
- }
- } else
- queryParams = Collections.emptyList();
- return queryParams;
- }
-
- @Override
- public String toString() {
- StringBuilder sb = new StringBuilder(getUrl());
-
- sb.append("\t");
- sb.append(method);
- sb.append("\theaders:");
- if (!headers.isEmpty()) {
- for (Map.Entry header : headers) {
- sb.append("\t");
- sb.append(header.getKey());
- sb.append(":");
- sb.append(header.getValue());
- }
+ public final ProxyServer proxyServer;
+ private final String method;
+ private final Uri uri;
+ private final InetAddress address;
+ private final InetAddress localAddress;
+ private final HttpHeaders headers;
+ private final List cookies;
+ private final byte[] byteData;
+ private final List compositeByteData;
+ private final String stringData;
+ private final ByteBuffer byteBufferData;
+ private final InputStream streamData;
+ private final BodyGenerator bodyGenerator;
+ private final List formParams;
+ private final List bodyParts;
+ private final String virtualHost;
+ private final Realm realm;
+ private final File file;
+ private final Boolean followRedirect;
+ private final int requestTimeout;
+ private final int readTimeout;
+ private final long rangeOffset;
+ private final Charset charset;
+ private final ChannelPoolPartitioning channelPoolPartitioning;
+ private final NameResolver nameResolver;
+
+ // lazily loaded
+ private List queryParams;
+
+ public DefaultRequest(String method,
+ Uri uri,
+ InetAddress address,
+ InetAddress localAddress,
+ HttpHeaders headers,
+ List cookies,
+ byte[] byteData,
+ List compositeByteData,
+ String stringData,
+ ByteBuffer byteBufferData,
+ InputStream streamData,
+ BodyGenerator bodyGenerator,
+ List formParams,
+ List bodyParts,
+ String virtualHost,
+ ProxyServer proxyServer,
+ Realm realm,
+ File file,
+ Boolean followRedirect,
+ int requestTimeout,
+ int readTimeout,
+ long rangeOffset,
+ Charset charset,
+ ChannelPoolPartitioning channelPoolPartitioning,
+ NameResolver nameResolver) {
+ this.method = method;
+ this.uri = uri;
+ this.address = address;
+ this.localAddress = localAddress;
+ this.headers = headers;
+ this.cookies = cookies;
+ this.byteData = byteData;
+ this.compositeByteData = compositeByteData;
+ this.stringData = stringData;
+ this.byteBufferData = byteBufferData;
+ this.streamData = streamData;
+ this.bodyGenerator = bodyGenerator;
+ this.formParams = formParams;
+ this.bodyParts = bodyParts;
+ this.virtualHost = virtualHost;
+ this.proxyServer = proxyServer;
+ this.realm = realm;
+ this.file = file;
+ this.followRedirect = followRedirect;
+ this.requestTimeout = requestTimeout;
+ this.readTimeout = readTimeout;
+ this.rangeOffset = rangeOffset;
+ this.charset = charset;
+ this.channelPoolPartitioning = channelPoolPartitioning;
+ this.nameResolver = nameResolver;
+ }
+
+ @Override
+ public String getUrl() {
+ return uri.toUrl();
+ }
+
+ @Override
+ public String getMethod() {
+ return method;
+ }
+
+ @Override
+ public Uri getUri() {
+ return uri;
+ }
+
+ @Override
+ public InetAddress getAddress() {
+ return address;
+ }
+
+ @Override
+ public InetAddress getLocalAddress() {
+ return localAddress;
+ }
+
+ @Override
+ public HttpHeaders getHeaders() {
+ return headers;
+ }
+
+ @Override
+ public List getCookies() {
+ return cookies;
+ }
+
+ @Override
+ public byte[] getByteData() {
+ return byteData;
+ }
+
+ @Override
+ public List getCompositeByteData() {
+ return compositeByteData;
+ }
+
+ @Override
+ public String getStringData() {
+ return stringData;
+ }
+
+ @Override
+ public ByteBuffer getByteBufferData() {
+ return byteBufferData;
+ }
+
+ @Override
+ public InputStream getStreamData() {
+ return streamData;
+ }
+
+ @Override
+ public BodyGenerator getBodyGenerator() {
+ return bodyGenerator;
+ }
+
+ @Override
+ public List getFormParams() {
+ return formParams;
}
- if (isNonEmpty(formParams)) {
- sb.append("\tformParams:");
- for (Param param : formParams) {
- sb.append("\t");
- sb.append(param.getName());
- sb.append(":");
- sb.append(param.getValue());
- }
+
+ @Override
+ public List getBodyParts() {
+ return bodyParts;
+ }
+
+ @Override
+ public String getVirtualHost() {
+ return virtualHost;
+ }
+
+ @Override
+ public ProxyServer getProxyServer() {
+ return proxyServer;
+ }
+
+ @Override
+ public Realm getRealm() {
+ return realm;
+ }
+
+ @Override
+ public File getFile() {
+ return file;
+ }
+
+ @Override
+ public Boolean getFollowRedirect() {
+ return followRedirect;
+ }
+
+ @Override
+ public int getRequestTimeout() {
+ return requestTimeout;
+ }
+
+ @Override
+ public int getReadTimeout() {
+ return readTimeout;
}
- return sb.toString();
- }
+ @Override
+ public long getRangeOffset() {
+ return rangeOffset;
+ }
+
+ @Override
+ public Charset getCharset() {
+ return charset;
+ }
+
+ @Override
+ public ChannelPoolPartitioning getChannelPoolPartitioning() {
+ return channelPoolPartitioning;
+ }
+
+ @Override
+ public NameResolver getNameResolver() {
+ return nameResolver;
+ }
+
+ @Override
+ public List getQueryParams() {
+ // lazy load
+ if (queryParams == null) {
+ if (isNonEmpty(uri.getQuery())) {
+ queryParams = new ArrayList<>(1);
+ for (String queryStringParam : uri.getQuery().split("&")) {
+ int pos = queryStringParam.indexOf('=');
+ if (pos <= 0) {
+ queryParams.add(new Param(queryStringParam, null));
+ } else {
+ queryParams.add(new Param(queryStringParam.substring(0, pos), queryStringParam.substring(pos + 1)));
+ }
+ }
+ } else {
+ queryParams = Collections.emptyList();
+ }
+ }
+ return queryParams;
+ }
+
+ @Override
+ public String toString() {
+ StringBuilder sb = new StringBuilder(getUrl());
+ sb.append('\t');
+ sb.append(method);
+ sb.append("\theaders:");
+
+ if (!headers.isEmpty()) {
+ for (Map.Entry header : headers) {
+ sb.append('\t');
+ sb.append(header.getKey());
+ sb.append(':');
+ sb.append(header.getValue());
+ }
+ }
+
+ if (isNonEmpty(formParams)) {
+ sb.append("\tformParams:");
+ for (Param param : formParams) {
+ sb.append('\t');
+ sb.append(param.getName());
+ sb.append(':');
+ sb.append(param.getValue());
+ }
+ }
+ return sb.toString();
+ }
}
diff --git a/client/src/main/java/org/asynchttpclient/Dsl.java b/client/src/main/java/org/asynchttpclient/Dsl.java
index cdb30ed165..f72820258c 100644
--- a/client/src/main/java/org/asynchttpclient/Dsl.java
+++ b/client/src/main/java/org/asynchttpclient/Dsl.java
@@ -1,125 +1,133 @@
/*
- * Copyright (c) 2015 AsyncHttpClient Project. All rights reserved.
+ * Copyright (c) 2015-2023 AsyncHttpClient Project. All rights reserved.
*
- * This program is licensed to you under the Apache License Version 2.0,
- * and you may not use this file except in compliance with the Apache License Version 2.0.
- * You may obtain a copy of the Apache License Version 2.0 at
- * http://www.apache.org/licenses/LICENSE-2.0.
+ * 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
*
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the Apache License Version 2.0 is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the Apache License Version 2.0 for the specific language governing permissions and limitations there under.
+ * 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 org.asynchttpclient;
import org.asynchttpclient.Realm.AuthScheme;
import org.asynchttpclient.proxy.ProxyServer;
-import static org.asynchttpclient.util.HttpConstants.Methods.*;
+import static org.asynchttpclient.util.HttpConstants.Methods.DELETE;
+import static org.asynchttpclient.util.HttpConstants.Methods.GET;
+import static org.asynchttpclient.util.HttpConstants.Methods.HEAD;
+import static org.asynchttpclient.util.HttpConstants.Methods.OPTIONS;
+import static org.asynchttpclient.util.HttpConstants.Methods.PATCH;
+import static org.asynchttpclient.util.HttpConstants.Methods.POST;
+import static org.asynchttpclient.util.HttpConstants.Methods.PUT;
+import static org.asynchttpclient.util.HttpConstants.Methods.TRACE;
public final class Dsl {
- private Dsl() {
- }
-
- // /////////// Client ////////////////
- public static AsyncHttpClient asyncHttpClient() {
- return new DefaultAsyncHttpClient();
- }
-
- public static AsyncHttpClient asyncHttpClient(DefaultAsyncHttpClientConfig.Builder configBuilder) {
- return new DefaultAsyncHttpClient(configBuilder.build());
- }
-
- public static AsyncHttpClient asyncHttpClient(AsyncHttpClientConfig config) {
- return new DefaultAsyncHttpClient(config);
- }
-
- // /////////// Request ////////////////
- public static RequestBuilder get(String url) {
- return request(GET, url);
- }
-
- public static RequestBuilder put(String url) {
- return request(PUT, url);
- }
-
- public static RequestBuilder post(String url) {
- return request(POST, url);
- }
-
- public static RequestBuilder delete(String url) {
- return request(DELETE, url);
- }
-
- public static RequestBuilder head(String url) {
- return request(HEAD, url);
- }
-
- public static RequestBuilder options(String url) {
- return request(OPTIONS, url);
- }
-
- public static RequestBuilder patch(String url) {
- return request(PATCH, url);
- }
-
- public static RequestBuilder trace(String url) {
- return request(TRACE, url);
- }
-
- public static RequestBuilder request(String method, String url) {
- return new RequestBuilder(method).setUrl(url);
- }
-
- // /////////// ProxyServer ////////////////
- public static ProxyServer.Builder proxyServer(String host, int port) {
- return new ProxyServer.Builder(host, port);
- }
-
- // /////////// Config ////////////////
- public static DefaultAsyncHttpClientConfig.Builder config() {
- return new DefaultAsyncHttpClientConfig.Builder();
- }
-
- // /////////// Realm ////////////////
- public static Realm.Builder realm(Realm prototype) {
- return new Realm.Builder(prototype.getPrincipal(), prototype.getPassword())
- .setRealmName(prototype.getRealmName())
- .setAlgorithm(prototype.getAlgorithm())
- .setNc(prototype.getNc())
- .setNonce(prototype.getNonce())
- .setCharset(prototype.getCharset())
- .setOpaque(prototype.getOpaque())
- .setQop(prototype.getQop())
- .setScheme(prototype.getScheme())
- .setUri(prototype.getUri())
- .setUsePreemptiveAuth(prototype.isUsePreemptiveAuth())
- .setNtlmDomain(prototype.getNtlmDomain())
- .setNtlmHost(prototype.getNtlmHost())
- .setUseAbsoluteURI(prototype.isUseAbsoluteURI())
- .setOmitQuery(prototype.isOmitQuery())
- .setServicePrincipalName(prototype.getServicePrincipalName())
- .setUseCanonicalHostname(prototype.isUseCanonicalHostname())
- .setCustomLoginConfig(prototype.getCustomLoginConfig())
- .setLoginContextName(prototype.getLoginContextName());
- }
-
- public static Realm.Builder realm(AuthScheme scheme, String principal, String password) {
- return new Realm.Builder(principal, password)
- .setScheme(scheme);
- }
-
- public static Realm.Builder basicAuthRealm(String principal, String password) {
- return realm(AuthScheme.BASIC, principal, password);
- }
-
- public static Realm.Builder digestAuthRealm(String principal, String password) {
- return realm(AuthScheme.DIGEST, principal, password);
- }
-
- public static Realm.Builder ntlmAuthRealm(String principal, String password) {
- return realm(AuthScheme.NTLM, principal, password);
- }
+ private Dsl() {
+ }
+
+ // /////////// Client ////////////////
+ public static AsyncHttpClient asyncHttpClient() {
+ return new DefaultAsyncHttpClient();
+ }
+
+ public static AsyncHttpClient asyncHttpClient(DefaultAsyncHttpClientConfig.Builder configBuilder) {
+ return new DefaultAsyncHttpClient(configBuilder.build());
+ }
+
+ public static AsyncHttpClient asyncHttpClient(AsyncHttpClientConfig config) {
+ return new DefaultAsyncHttpClient(config);
+ }
+
+ // /////////// Request ////////////////
+ public static RequestBuilder get(String url) {
+ return request(GET, url);
+ }
+
+ public static RequestBuilder put(String url) {
+ return request(PUT, url);
+ }
+
+ public static RequestBuilder post(String url) {
+ return request(POST, url);
+ }
+
+ public static RequestBuilder delete(String url) {
+ return request(DELETE, url);
+ }
+
+ public static RequestBuilder head(String url) {
+ return request(HEAD, url);
+ }
+
+ public static RequestBuilder options(String url) {
+ return request(OPTIONS, url);
+ }
+
+ public static RequestBuilder patch(String url) {
+ return request(PATCH, url);
+ }
+
+ public static RequestBuilder trace(String url) {
+ return request(TRACE, url);
+ }
+
+ public static RequestBuilder request(String method, String url) {
+ return new RequestBuilder(method).setUrl(url);
+ }
+
+ // /////////// ProxyServer ////////////////
+ public static ProxyServer.Builder proxyServer(String host, int port) {
+ return new ProxyServer.Builder(host, port);
+ }
+
+ // /////////// Config ////////////////
+ public static DefaultAsyncHttpClientConfig.Builder config() {
+ return new DefaultAsyncHttpClientConfig.Builder();
+ }
+
+ // /////////// Realm ////////////////
+ public static Realm.Builder realm(Realm prototype) {
+ return new Realm.Builder(prototype.getPrincipal(), prototype.getPassword())
+ .setRealmName(prototype.getRealmName())
+ .setAlgorithm(prototype.getAlgorithm())
+ .setNc(prototype.getNc())
+ .setNonce(prototype.getNonce())
+ .setCharset(prototype.getCharset())
+ .setOpaque(prototype.getOpaque())
+ .setQop(prototype.getQop())
+ .setScheme(prototype.getScheme())
+ .setUri(prototype.getUri())
+ .setUsePreemptiveAuth(prototype.isUsePreemptiveAuth())
+ .setNtlmDomain(prototype.getNtlmDomain())
+ .setNtlmHost(prototype.getNtlmHost())
+ .setUseAbsoluteURI(prototype.isUseAbsoluteURI())
+ .setOmitQuery(prototype.isOmitQuery())
+ .setServicePrincipalName(prototype.getServicePrincipalName())
+ .setUseCanonicalHostname(prototype.isUseCanonicalHostname())
+ .setCustomLoginConfig(prototype.getCustomLoginConfig())
+ .setLoginContextName(prototype.getLoginContextName());
+ }
+
+ public static Realm.Builder realm(AuthScheme scheme, String principal, String password) {
+ return new Realm.Builder(principal, password).setScheme(scheme);
+ }
+
+ public static Realm.Builder basicAuthRealm(String principal, String password) {
+ return realm(AuthScheme.BASIC, principal, password);
+ }
+
+ public static Realm.Builder digestAuthRealm(String principal, String password) {
+ return realm(AuthScheme.DIGEST, principal, password);
+ }
+
+ public static Realm.Builder ntlmAuthRealm(String principal, String password) {
+ return realm(AuthScheme.NTLM, principal, password);
+ }
}
diff --git a/client/src/main/java/org/asynchttpclient/HostStats.java b/client/src/main/java/org/asynchttpclient/HostStats.java
index b5fea52f65..9ec52805a9 100644
--- a/client/src/main/java/org/asynchttpclient/HostStats.java
+++ b/client/src/main/java/org/asynchttpclient/HostStats.java
@@ -1,15 +1,17 @@
/*
- * Copyright (c) 2014 AsyncHttpClient Project. All rights reserved.
+ * Copyright (c) 2014-2023 AsyncHttpClient Project. All rights reserved.
*
- * This program is licensed to you under the Apache License Version 2.0,
- * and you may not use this file except in compliance with the Apache License Version 2.0.
- * You may obtain a copy of the Apache License Version 2.0 at
- * http://www.apache.org/licenses/LICENSE-2.0.
+ * 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
*
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the Apache License Version 2.0 is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the Apache License Version 2.0 for the specific language governing permissions and limitations there under.
+ * 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 org.asynchttpclient;
@@ -20,55 +22,57 @@
*/
public class HostStats {
- private final long activeConnectionCount;
- private final long idleConnectionCount;
+ private final long activeConnectionCount;
+ private final long idleConnectionCount;
- public HostStats(long activeConnectionCount,
- long idleConnectionCount) {
- this.activeConnectionCount = activeConnectionCount;
- this.idleConnectionCount = idleConnectionCount;
- }
+ public HostStats(long activeConnectionCount, long idleConnectionCount) {
+ this.activeConnectionCount = activeConnectionCount;
+ this.idleConnectionCount = idleConnectionCount;
+ }
- /**
- * @return The sum of {@link #getHostActiveConnectionCount()} and {@link #getHostIdleConnectionCount()},
- * a long representing the total number of connections to this host.
- */
- public long getHostConnectionCount() {
- return activeConnectionCount + idleConnectionCount;
- }
+ /**
+ * @return The sum of {@link #getHostActiveConnectionCount()} and {@link #getHostIdleConnectionCount()},
+ * a long representing the total number of connections to this host.
+ */
+ public long getHostConnectionCount() {
+ return activeConnectionCount + idleConnectionCount;
+ }
- /**
- * @return A long representing the number of active connections to the host.
- */
- public long getHostActiveConnectionCount() {
- return activeConnectionCount;
- }
+ /**
+ * @return A long representing the number of active connections to the host.
+ */
+ public long getHostActiveConnectionCount() {
+ return activeConnectionCount;
+ }
- /**
- * @return A long representing the number of idle connections in the connection pool.
- */
- public long getHostIdleConnectionCount() {
- return idleConnectionCount;
- }
+ /**
+ * @return A long representing the number of idle connections in the connection pool.
+ */
+ public long getHostIdleConnectionCount() {
+ return idleConnectionCount;
+ }
- @Override
- public String toString() {
- return "There are " + getHostConnectionCount() +
- " total connections, " + getHostActiveConnectionCount() +
- " are active and " + getHostIdleConnectionCount() + " are idle.";
- }
+ @Override
+ public String toString() {
+ return "There are " + getHostConnectionCount() +
+ " total connections, " + getHostActiveConnectionCount() +
+ " are active and " + getHostIdleConnectionCount() + " are idle.";
+ }
- @Override
- public boolean equals(final Object o) {
- if (this == o) return true;
- if (o == null || getClass() != o.getClass()) return false;
- final HostStats hostStats = (HostStats) o;
- return activeConnectionCount == hostStats.activeConnectionCount &&
- idleConnectionCount == hostStats.idleConnectionCount;
- }
+ @Override
+ public boolean equals(final Object o) {
+ if (this == o) {
+ return true;
+ }
+ if (o == null || getClass() != o.getClass()) {
+ return false;
+ }
+ final HostStats hostStats = (HostStats) o;
+ return activeConnectionCount == hostStats.activeConnectionCount && idleConnectionCount == hostStats.idleConnectionCount;
+ }
- @Override
- public int hashCode() {
- return Objects.hash(activeConnectionCount, idleConnectionCount);
- }
+ @Override
+ public int hashCode() {
+ return Objects.hash(activeConnectionCount, idleConnectionCount);
+ }
}
diff --git a/client/src/main/java/org/asynchttpclient/HttpResponseBodyPart.java b/client/src/main/java/org/asynchttpclient/HttpResponseBodyPart.java
index 053aa28ff5..0be4dedb51 100644
--- a/client/src/main/java/org/asynchttpclient/HttpResponseBodyPart.java
+++ b/client/src/main/java/org/asynchttpclient/HttpResponseBodyPart.java
@@ -22,32 +22,32 @@
*/
public abstract class HttpResponseBodyPart {
- private final boolean last;
-
- public HttpResponseBodyPart(boolean last) {
- this.last = last;
- }
-
- /**
- * @return length of this part in bytes
- */
- public abstract int length();
-
- /**
- * @return the response body's part bytes received.
- */
- public abstract byte[] getBodyPartBytes();
-
- /**
- * @return a {@link ByteBuffer} that wraps the actual bytes read from the response's chunk.
- * The {@link ByteBuffer}'s capacity is equal to the number of bytes available.
- */
- public abstract ByteBuffer getBodyByteBuffer();
-
- /**
- * @return true if this is the last part.
- */
- public boolean isLast() {
- return last;
- }
+ private final boolean last;
+
+ protected HttpResponseBodyPart(boolean last) {
+ this.last = last;
+ }
+
+ /**
+ * @return length of this part in bytes
+ */
+ public abstract int length();
+
+ /**
+ * @return the response body's part bytes received.
+ */
+ public abstract byte[] getBodyPartBytes();
+
+ /**
+ * @return a {@link ByteBuffer} that wraps the actual bytes read from the response's chunk.
+ * The {@link ByteBuffer}'s capacity is equal to the number of bytes available.
+ */
+ public abstract ByteBuffer getBodyByteBuffer();
+
+ /**
+ * @return true if this is the last part.
+ */
+ public boolean isLast() {
+ return last;
+ }
}
diff --git a/client/src/main/java/org/asynchttpclient/HttpResponseStatus.java b/client/src/main/java/org/asynchttpclient/HttpResponseStatus.java
index 7cdd414655..60c82908ea 100644
--- a/client/src/main/java/org/asynchttpclient/HttpResponseStatus.java
+++ b/client/src/main/java/org/asynchttpclient/HttpResponseStatus.java
@@ -25,84 +25,84 @@
*/
public abstract class HttpResponseStatus {
- private final Uri uri;
+ private final Uri uri;
- public HttpResponseStatus(Uri uri) {
- this.uri = uri;
- }
+ protected HttpResponseStatus(Uri uri) {
+ this.uri = uri;
+ }
- /**
- * Return the request {@link Uri}
- *
- * @return the request {@link Uri}
- */
- public Uri getUri() {
- return uri;
- }
+ /**
+ * Return the request {@link Uri}
+ *
+ * @return the request {@link Uri}
+ */
+ public Uri getUri() {
+ return uri;
+ }
- /**
- * Return the response status code
- *
- * @return the response status code
- */
- public abstract int getStatusCode();
+ /**
+ * Return the response status code
+ *
+ * @return the response status code
+ */
+ public abstract int getStatusCode();
- /**
- * Return the response status text
- *
- * @return the response status text
- */
- public abstract String getStatusText();
+ /**
+ * Return the response status text
+ *
+ * @return the response status text
+ */
+ public abstract String getStatusText();
- /**
- * Protocol name from status line.
- *
- * @return Protocol name.
- */
- public abstract String getProtocolName();
+ /**
+ * Protocol name from status line.
+ *
+ * @return Protocol name.
+ */
+ public abstract String getProtocolName();
- /**
- * Protocol major version.
- *
- * @return Major version.
- */
- public abstract int getProtocolMajorVersion();
+ /**
+ * Protocol major version.
+ *
+ * @return Major version.
+ */
+ public abstract int getProtocolMajorVersion();
- /**
- * Protocol minor version.
- *
- * @return Minor version.
- */
- public abstract int getProtocolMinorVersion();
+ /**
+ * Protocol minor version.
+ *
+ * @return Minor version.
+ */
+ public abstract int getProtocolMinorVersion();
- /**
- * Full protocol name + version
- *
- * @return protocol name + version
- */
- public abstract String getProtocolText();
+ /**
+ * Full protocol name + version
+ *
+ * @return protocol name + version
+ */
+ public abstract String getProtocolText();
- /**
- * Get remote address client initiated request to.
- *
- * @return remote address client initiated request to, may be {@code null}
- * if asynchronous provider is unable to provide the remote address
- */
- public abstract SocketAddress getRemoteAddress();
+ /**
+ * Get remote address client initiated request to.
+ *
+ * @return remote address client initiated request to, may be {@code null}
+ * if asynchronous provider is unable to provide the remote address
+ */
+ public abstract SocketAddress getRemoteAddress();
- /**
- * Get local address client initiated request from.
- *
- * @return local address client initiated request from, may be {@code null}
- * if asynchronous provider is unable to provide the local address
- */
- public abstract SocketAddress getLocalAddress();
+ /**
+ * Get local address client initiated request from.
+ *
+ * @return local address client initiated request from, may be {@code null}
+ * if asynchronous provider is unable to provide the local address
+ */
+ public abstract SocketAddress getLocalAddress();
- /**
- * Code followed by text.
- */
- @Override
- public String toString() {
- return getStatusCode() + " " + getStatusText();
- }
+ /**
+ * Code followed by text.
+ */
+ @Override
+ public String toString() {
+ return getStatusCode() + " " + getStatusText();
+ }
}
diff --git a/client/src/main/java/org/asynchttpclient/ListenableFuture.java b/client/src/main/java/org/asynchttpclient/ListenableFuture.java
index d63ebc52c9..930d8d8c24 100755
--- a/client/src/main/java/org/asynchttpclient/ListenableFuture.java
+++ b/client/src/main/java/org/asynchttpclient/ListenableFuture.java
@@ -30,7 +30,11 @@
*/
package org.asynchttpclient;
-import java.util.concurrent.*;
+import java.util.concurrent.CompletableFuture;
+import java.util.concurrent.ExecutionException;
+import java.util.concurrent.Executor;
+import java.util.concurrent.Future;
+import java.util.concurrent.TimeUnit;
/**
* Extended {@link Future}
@@ -39,109 +43,109 @@
*/
public interface ListenableFuture extends Future {
- /**
- * Terminate and if there is no exception, mark this Future as done and release the internal lock.
- */
- void done();
-
- /**
- * Abort the current processing, and propagate the {@link Throwable} to the {@link AsyncHandler} or {@link Future}
- *
- * @param t the exception
- */
- void abort(Throwable t);
-
- /**
- * Touch the current instance to prevent external service to times out.
- */
- void touch();
-
- /**
- * Adds a listener and executor to the ListenableFuture.
- * The listener will be {@linkplain java.util.concurrent.Executor#execute(Runnable) passed
- * to the executor} for execution when the {@code Future}'s computation is
- * {@linkplain Future#isDone() complete}.
- *
- * Executor can be null
, in that case executor will be executed
- * in the thread where completion happens.
- *
- * There is no guaranteed ordering of execution of listeners, they may get
- * called in the order they were added and they may get called out of order,
- * but any listener added through this method is guaranteed to be called once
- * the computation is complete.
- *
- * @param listener the listener to run when the computation is complete.
- * @param exec the executor to run the listener in.
- * @return this Future
- */
- ListenableFuture addListener(Runnable listener, Executor exec);
-
- CompletableFuture toCompletableFuture();
-
- class CompletedFailure implements ListenableFuture {
-
- private final ExecutionException e;
-
- public CompletedFailure(Throwable t) {
- e = new ExecutionException(t);
+ /**
+ * Terminate and if there is no exception, mark this Future as done and release the internal lock.
+ */
+ void done();
+
+ /**
+ * Abort the current processing, and propagate the {@link Throwable} to the {@link AsyncHandler} or {@link Future}
+ *
+ * @param t the exception
+ */
+ void abort(Throwable t);
+
+ /**
+ * Touch the current instance to prevent external service to times out.
+ */
+ void touch();
+
+ /**
+ * Adds a listener and executor to the ListenableFuture.
+ * The listener will be {@linkplain Executor#execute(Runnable) passed
+ * to the executor} for execution when the {@code Future}'s computation is
+ * {@linkplain Future#isDone() complete}.
+ *
+ * Executor can be {@code null}, in that case executor will be executed
+ * in the thread where completion happens.
+ *
+ * There is no guaranteed ordering of execution of listeners, they may get
+ * called in the order they were added and they may get called out of order,
+ * but any listener added through this method is guaranteed to be called once
+ * the computation is complete.
+ *
+ * @param listener the listener to run when the computation is complete.
+ * @param exec the executor to run the listener in.
+ * @return this Future
+ */
+ ListenableFuture addListener(Runnable listener, Executor exec);
+
+ CompletableFuture toCompletableFuture();
+
+ class CompletedFailure implements ListenableFuture {
+
+ private final ExecutionException e;
+
+ public CompletedFailure(Throwable t) {
+ e = new ExecutionException(t);
+ }
+
+ public CompletedFailure(String message, Throwable t) {
+ e = new ExecutionException(message, t);
+ }
+
+ @Override
+ public boolean cancel(boolean mayInterruptIfRunning) {
+ return true;
+ }
+
+ @Override
+ public boolean isCancelled() {
+ return false;
+ }
+
+ @Override
+ public boolean isDone() {
+ return true;
+ }
+
+ @Override
+ public T get() throws ExecutionException {
+ throw e;
+ }
+
+ @Override
+ public T get(long timeout, TimeUnit unit) throws ExecutionException {
+ throw e;
+ }
+
+ @Override
+ public void done() {
+ }
+
+ @Override
+ public void abort(Throwable t) {
+ }
+
+ @Override
+ public void touch() {
+ }
+
+ @Override
+ public ListenableFuture addListener(Runnable listener, Executor exec) {
+ if (exec != null) {
+ exec.execute(listener);
+ } else {
+ listener.run();
+ }
+ return this;
+ }
+
+ @Override
+ public CompletableFuture toCompletableFuture() {
+ CompletableFuture future = new CompletableFuture<>();
+ future.completeExceptionally(e);
+ return future;
+ }
}
-
- public CompletedFailure(String message, Throwable t) {
- e = new ExecutionException(message, t);
- }
-
- @Override
- public boolean cancel(boolean mayInterruptIfRunning) {
- return true;
- }
-
- @Override
- public boolean isCancelled() {
- return false;
- }
-
- @Override
- public boolean isDone() {
- return true;
- }
-
- @Override
- public T get() throws ExecutionException {
- throw e;
- }
-
- @Override
- public T get(long timeout, TimeUnit unit) throws ExecutionException {
- throw e;
- }
-
- @Override
- public void done() {
- }
-
- @Override
- public void abort(Throwable t) {
- }
-
- @Override
- public void touch() {
- }
-
- @Override
- public ListenableFuture addListener(Runnable listener, Executor exec) {
- if (exec != null) {
- exec.execute(listener);
- } else {
- listener.run();
- }
- return this;
- }
-
- @Override
- public CompletableFuture toCompletableFuture() {
- CompletableFuture future = new CompletableFuture<>();
- future.completeExceptionally(e);
- return future;
- }
- }
}
diff --git a/client/src/main/java/org/asynchttpclient/Param.java b/client/src/main/java/org/asynchttpclient/Param.java
index 858c1158ed..397d5b5fa3 100644
--- a/client/src/main/java/org/asynchttpclient/Param.java
+++ b/client/src/main/java/org/asynchttpclient/Param.java
@@ -1,14 +1,17 @@
/*
- * Copyright (c) 2014 AsyncHttpClient Project. All rights reserved.
+ * Copyright (c) 2014-2023 AsyncHttpClient Project. All rights reserved.
*
- * This program is licensed to you under the Apache License Version 2.0,
- * and you may not use this file except in compliance with the Apache License Version 2.0.
- * You may obtain a copy of the Apache License Version 2.0 at http://www.apache.org/licenses/LICENSE-2.0.
+ * 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
*
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the Apache License Version 2.0 is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the Apache License Version 2.0 for the specific language governing permissions and limitations there under.
+ * 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 org.asynchttpclient;
@@ -23,61 +26,69 @@
*/
public class Param {
- private final String name;
- private final String value;
+ private final String name;
+ private final String value;
- public Param(String name, String value) {
- this.name = name;
- this.value = value;
- }
+ public Param(String name, String value) {
+ this.name = name;
+ this.value = value;
+ }
- public static List map2ParamList(Map> map) {
- if (map == null)
- return null;
+ public static List map2ParamList(Map> map) {
+ if (map == null) {
+ return null;
+ }
- List params = new ArrayList<>(map.size());
- for (Map.Entry> entries : map.entrySet()) {
- String name = entries.getKey();
- for (String value : entries.getValue())
- params.add(new Param(name, value));
+ List params = new ArrayList<>(map.size());
+ for (Map.Entry> entries : map.entrySet()) {
+ String name = entries.getKey();
+ for (String value : entries.getValue()) {
+ params.add(new Param(name, value));
+ }
+ }
+ return params;
}
- return params;
- }
- public String getName() {
- return name;
- }
+ public String getName() {
+ return name;
+ }
- public String getValue() {
- return value;
- }
+ public String getValue() {
+ return value;
+ }
- public int hashCode() {
- final int prime = 31;
- int result = 1;
- result = prime * result + ((name == null) ? 0 : name.hashCode());
- result = prime * result + ((value == null) ? 0 : value.hashCode());
- return result;
- }
+ @Override
+ public int hashCode() {
+ final int prime = 31;
+ int result = 1;
+ result = prime * result + (name == null ? 0 : name.hashCode());
+ result = prime * result + (value == null ? 0 : value.hashCode());
+ return result;
+ }
- public boolean equals(Object obj) {
- if (this == obj)
- return true;
- if (obj == null)
- return false;
- if (!(obj instanceof Param))
- return false;
- Param other = (Param) obj;
- if (name == null) {
- if (other.name != null)
- return false;
- } else if (!name.equals(other.name))
- return false;
- if (value == null) {
- if (other.value != null)
- return false;
- } else if (!value.equals(other.value))
- return false;
- return true;
- }
+ @Override
+ public boolean equals(Object obj) {
+ if (this == obj) {
+ return true;
+ }
+ if (obj == null) {
+ return false;
+ }
+ if (!(obj instanceof Param)) {
+ return false;
+ }
+ Param other = (Param) obj;
+ if (name == null) {
+ if (other.name != null) {
+ return false;
+ }
+ } else if (!name.equals(other.name)) {
+ return false;
+ }
+ if (value == null) {
+ return other.value == null;
+ } else {
+ return value.equals(other.value);
+ }
+ }
}
diff --git a/client/src/main/java/org/asynchttpclient/Realm.java b/client/src/main/java/org/asynchttpclient/Realm.java
index c6324fd0b4..6e4cbc8d29 100644
--- a/client/src/main/java/org/asynchttpclient/Realm.java
+++ b/client/src/main/java/org/asynchttpclient/Realm.java
@@ -26,7 +26,8 @@
import java.util.Map;
import java.util.concurrent.ThreadLocalRandom;
-import static java.nio.charset.StandardCharsets.*;
+import static java.nio.charset.StandardCharsets.ISO_8859_1;
+import static java.nio.charset.StandardCharsets.UTF_8;
import static org.asynchttpclient.util.Assertions.assertNotNull;
import static org.asynchttpclient.util.MessageDigestUtils.pooledMd5MessageDigest;
import static org.asynchttpclient.util.MiscUtils.isNonEmpty;
@@ -39,554 +40,558 @@
*/
public class Realm {
- private static final String DEFAULT_NC = "00000001";
- // MD5("")
- private static final String EMPTY_ENTITY_MD5 = "d41d8cd98f00b204e9800998ecf8427e";
-
- private final String principal;
- private final String password;
- private final AuthScheme scheme;
- private final String realmName;
- private final String nonce;
- private final String algorithm;
- private final String response;
- private final String opaque;
- private final String qop;
- private final String nc;
- private final String cnonce;
- private final Uri uri;
- private final boolean usePreemptiveAuth;
- private final Charset charset;
- private final String ntlmHost;
- private final String ntlmDomain;
- private final boolean useAbsoluteURI;
- private final boolean omitQuery;
- private final Map customLoginConfig;
- private final String servicePrincipalName;
- private final boolean useCanonicalHostname;
- private final String loginContextName;
-
- private Realm(AuthScheme scheme,
- String principal,
- String password,
- String realmName,
- String nonce,
- String algorithm,
- String response,
- String opaque,
- String qop,
- String nc,
- String cnonce,
- Uri uri,
- boolean usePreemptiveAuth,
- Charset charset,
- String ntlmDomain,
- String ntlmHost,
- boolean useAbsoluteURI,
- boolean omitQuery,
- String servicePrincipalName,
- boolean useCanonicalHostname,
- Map customLoginConfig,
- String loginContextName) {
-
- this.scheme = assertNotNull(scheme, "scheme");
- this.principal = principal;
- this.password = password;
- this.realmName = realmName;
- this.nonce = nonce;
- this.algorithm = algorithm;
- this.response = response;
- this.opaque = opaque;
- this.qop = qop;
- this.nc = nc;
- this.cnonce = cnonce;
- this.uri = uri;
- this.usePreemptiveAuth = usePreemptiveAuth;
- this.charset = charset;
- this.ntlmDomain = ntlmDomain;
- this.ntlmHost = ntlmHost;
- this.useAbsoluteURI = useAbsoluteURI;
- this.omitQuery = omitQuery;
- this.servicePrincipalName = servicePrincipalName;
- this.useCanonicalHostname = useCanonicalHostname;
- this.customLoginConfig = customLoginConfig;
- this.loginContextName = loginContextName;
- }
-
- public String getPrincipal() {
- return principal;
- }
-
- public String getPassword() {
- return password;
- }
-
- public AuthScheme getScheme() {
- return scheme;
- }
-
- public String getRealmName() {
- return realmName;
- }
-
- public String getNonce() {
- return nonce;
- }
-
- public String getAlgorithm() {
- return algorithm;
- }
-
- public String getResponse() {
- return response;
- }
-
- public String getOpaque() {
- return opaque;
- }
-
- public String getQop() {
- return qop;
- }
-
- public String getNc() {
- return nc;
- }
-
- public String getCnonce() {
- return cnonce;
- }
-
- public Uri getUri() {
- return uri;
- }
-
- public Charset getCharset() {
- return charset;
- }
-
- /**
- * Return true is preemptive authentication is enabled
- *
- * @return true is preemptive authentication is enabled
- */
- public boolean isUsePreemptiveAuth() {
- return usePreemptiveAuth;
- }
-
- /**
- * Return the NTLM domain to use. This value should map the JDK
- *
- * @return the NTLM domain
- */
- public String getNtlmDomain() {
- return ntlmDomain;
- }
-
- /**
- * Return the NTLM host.
- *
- * @return the NTLM host
- */
- public String getNtlmHost() {
- return ntlmHost;
- }
-
- public boolean isUseAbsoluteURI() {
- return useAbsoluteURI;
- }
-
- public boolean isOmitQuery() {
- return omitQuery;
- }
-
- public Map getCustomLoginConfig() {
- return customLoginConfig;
- }
-
- public String getServicePrincipalName() {
- return servicePrincipalName;
- }
-
- public boolean isUseCanonicalHostname() {
- return useCanonicalHostname;
- }
-
- public String getLoginContextName() {
- return loginContextName;
- }
-
- @Override
- public String toString() {
- return "Realm{" +
- "principal='" + principal + '\'' +
- ", password='" + password + '\'' +
- ", scheme=" + scheme +
- ", realmName='" + realmName + '\'' +
- ", nonce='" + nonce + '\'' +
- ", algorithm='" + algorithm + '\'' +
- ", response='" + response + '\'' +
- ", opaque='" + opaque + '\'' +
- ", qop='" + qop + '\'' +
- ", nc='" + nc + '\'' +
- ", cnonce='" + cnonce + '\'' +
- ", uri=" + uri +
- ", usePreemptiveAuth=" + usePreemptiveAuth +
- ", charset=" + charset +
- ", ntlmHost='" + ntlmHost + '\'' +
- ", ntlmDomain='" + ntlmDomain + '\'' +
- ", useAbsoluteURI=" + useAbsoluteURI +
- ", omitQuery=" + omitQuery +
- ", customLoginConfig=" + customLoginConfig +
- ", servicePrincipalName='" + servicePrincipalName + '\'' +
- ", useCanonicalHostname=" + useCanonicalHostname +
- ", loginContextName='" + loginContextName + '\'' +
- '}';
- }
-
- public enum AuthScheme {
- BASIC, DIGEST, NTLM, SPNEGO, KERBEROS
- }
-
- /**
- * A builder for {@link Realm}
- */
- public static class Builder {
+ private static final String DEFAULT_NC = "00000001";
+ // MD5("")
+ private static final String EMPTY_ENTITY_MD5 = "d41d8cd98f00b204e9800998ecf8427e";
private final String principal;
private final String password;
- private AuthScheme scheme;
- private String realmName;
- private String nonce;
- private String algorithm;
- private String response;
- private String opaque;
- private String qop;
- private String nc = DEFAULT_NC;
- private String cnonce;
- private Uri uri;
- private String methodName = "GET";
- private boolean usePreemptive;
- private String ntlmDomain = System.getProperty("http.auth.ntlm.domain");
- private Charset charset = UTF_8;
- private String ntlmHost = "localhost";
- private boolean useAbsoluteURI = false;
- private boolean omitQuery;
- /**
- * Kerberos/Spnego properties
- */
- private Map customLoginConfig;
- private String servicePrincipalName;
- private boolean useCanonicalHostname;
- private String loginContextName;
-
- public Builder() {
- this.principal = null;
- this.password = null;
- }
-
- public Builder(String principal, String password) {
- this.principal = principal;
- this.password = password;
- }
-
- public Builder setNtlmDomain(String ntlmDomain) {
- this.ntlmDomain = ntlmDomain;
- return this;
- }
-
- public Builder setNtlmHost(String host) {
- this.ntlmHost = host;
- return this;
- }
-
- public Builder setScheme(AuthScheme scheme) {
- this.scheme = scheme;
- return this;
- }
-
- public Builder setRealmName(String realmName) {
- this.realmName = realmName;
- return this;
- }
-
- public Builder setNonce(String nonce) {
- this.nonce = nonce;
- return this;
- }
-
- public Builder setAlgorithm(String algorithm) {
- this.algorithm = algorithm;
- return this;
- }
-
- public Builder setResponse(String response) {
- this.response = response;
- return this;
- }
-
- public Builder setOpaque(String opaque) {
- this.opaque = opaque;
- return this;
- }
-
- public Builder setQop(String qop) {
- if (isNonEmpty(qop)) {
+ private final AuthScheme scheme;
+ private final String realmName;
+ private final String nonce;
+ private final String algorithm;
+ private final String response;
+ private final String opaque;
+ private final String qop;
+ private final String nc;
+ private final String cnonce;
+ private final Uri uri;
+ private final boolean usePreemptiveAuth;
+ private final Charset charset;
+ private final String ntlmHost;
+ private final String ntlmDomain;
+ private final boolean useAbsoluteURI;
+ private final boolean omitQuery;
+ private final Map customLoginConfig;
+ private final String servicePrincipalName;
+ private final boolean useCanonicalHostname;
+ private final String loginContextName;
+
+ private Realm(AuthScheme scheme,
+ String principal,
+ String password,
+ String realmName,
+ String nonce,
+ String algorithm,
+ String response,
+ String opaque,
+ String qop,
+ String nc,
+ String cnonce,
+ Uri uri,
+ boolean usePreemptiveAuth,
+ Charset charset,
+ String ntlmDomain,
+ String ntlmHost,
+ boolean useAbsoluteURI,
+ boolean omitQuery,
+ String servicePrincipalName,
+ boolean useCanonicalHostname,
+ Map customLoginConfig,
+ String loginContextName) {
+
+ this.scheme = assertNotNull(scheme, "scheme");
+ this.principal = principal;
+ this.password = password;
+ this.realmName = realmName;
+ this.nonce = nonce;
+ this.algorithm = algorithm;
+ this.response = response;
+ this.opaque = opaque;
this.qop = qop;
- }
- return this;
+ this.nc = nc;
+ this.cnonce = cnonce;
+ this.uri = uri;
+ this.usePreemptiveAuth = usePreemptiveAuth;
+ this.charset = charset;
+ this.ntlmDomain = ntlmDomain;
+ this.ntlmHost = ntlmHost;
+ this.useAbsoluteURI = useAbsoluteURI;
+ this.omitQuery = omitQuery;
+ this.servicePrincipalName = servicePrincipalName;
+ this.useCanonicalHostname = useCanonicalHostname;
+ this.customLoginConfig = customLoginConfig;
+ this.loginContextName = loginContextName;
}
- public Builder setNc(String nc) {
- this.nc = nc;
- return this;
+ public String getPrincipal() {
+ return principal;
}
- public Builder setUri(Uri uri) {
- this.uri = uri;
- return this;
+ public String getPassword() {
+ return password;
}
- public Builder setMethodName(String methodName) {
- this.methodName = methodName;
- return this;
+ public AuthScheme getScheme() {
+ return scheme;
}
- public Builder setUsePreemptiveAuth(boolean usePreemptiveAuth) {
- this.usePreemptive = usePreemptiveAuth;
- return this;
+ public String getRealmName() {
+ return realmName;
}
- public Builder setUseAbsoluteURI(boolean useAbsoluteURI) {
- this.useAbsoluteURI = useAbsoluteURI;
- return this;
+ public String getNonce() {
+ return nonce;
}
- public Builder setOmitQuery(boolean omitQuery) {
- this.omitQuery = omitQuery;
- return this;
+ public String getAlgorithm() {
+ return algorithm;
}
- public Builder setCharset(Charset charset) {
- this.charset = charset;
- return this;
+ public String getResponse() {
+ return response;
}
- public Builder setCustomLoginConfig(Map customLoginConfig) {
- this.customLoginConfig = customLoginConfig;
- return this;
+ public String getOpaque() {
+ return opaque;
}
- public Builder setServicePrincipalName(String servicePrincipalName) {
- this.servicePrincipalName = servicePrincipalName;
- return this;
+ public String getQop() {
+ return qop;
}
- public Builder setUseCanonicalHostname(boolean useCanonicalHostname) {
- this.useCanonicalHostname = useCanonicalHostname;
- return this;
+ public String getNc() {
+ return nc;
}
- public Builder setLoginContextName(String loginContextName) {
- this.loginContextName = loginContextName;
- return this;
+ public String getCnonce() {
+ return cnonce;
}
- private String parseRawQop(String rawQop) {
- String[] rawServerSupportedQops = rawQop.split(",");
- String[] serverSupportedQops = new String[rawServerSupportedQops.length];
- for (int i = 0; i < rawServerSupportedQops.length; i++) {
- serverSupportedQops[i] = rawServerSupportedQops[i].trim();
- }
-
- // prefer auth over auth-int
- for (String rawServerSupportedQop : serverSupportedQops) {
- if (rawServerSupportedQop.equals("auth"))
- return rawServerSupportedQop;
- }
-
- for (String rawServerSupportedQop : serverSupportedQops) {
- if (rawServerSupportedQop.equals("auth-int"))
- return rawServerSupportedQop;
- }
-
- return null;
+ public Uri getUri() {
+ return uri;
}
- public Builder parseWWWAuthenticateHeader(String headerLine) {
- setRealmName(match(headerLine, "realm"))
- .setNonce(match(headerLine, "nonce"))
- .setOpaque(match(headerLine, "opaque"))
- .setScheme(isNonEmpty(nonce) ? AuthScheme.DIGEST : AuthScheme.BASIC);
- String algorithm = match(headerLine, "algorithm");
- if (isNonEmpty(algorithm)) {
- setAlgorithm(algorithm);
- }
-
- // FIXME qop is different with proxy?
- String rawQop = match(headerLine, "qop");
- if (rawQop != null) {
- setQop(parseRawQop(rawQop));
- }
-
- return this;
+ public Charset getCharset() {
+ return charset;
}
- public Builder parseProxyAuthenticateHeader(String headerLine) {
- setRealmName(match(headerLine, "realm"))
- .setNonce(match(headerLine, "nonce"))
- .setOpaque(match(headerLine, "opaque"))
- .setScheme(isNonEmpty(nonce) ? AuthScheme.DIGEST : AuthScheme.BASIC);
- String algorithm = match(headerLine, "algorithm");
- if (isNonEmpty(algorithm)) {
- setAlgorithm(algorithm);
- }
- // FIXME qop is different with proxy?
- setQop(match(headerLine, "qop"));
-
- return this;
+ /**
+ * Return true is preemptive authentication is enabled
+ *
+ * @return true is preemptive authentication is enabled
+ */
+ public boolean isUsePreemptiveAuth() {
+ return usePreemptiveAuth;
}
- private void newCnonce(MessageDigest md) {
- byte[] b = new byte[8];
- ThreadLocalRandom.current().nextBytes(b);
- b = md.digest(b);
- cnonce = toHexString(b);
+ /**
+ * Return the NTLM domain to use. This value should map the JDK
+ *
+ * @return the NTLM domain
+ */
+ public String getNtlmDomain() {
+ return ntlmDomain;
}
/**
- * TODO: A Pattern/Matcher may be better.
+ * Return the NTLM host.
+ *
+ * @return the NTLM host
*/
- private String match(String headerLine, String token) {
- if (headerLine == null) {
- return null;
- }
-
- int match = headerLine.indexOf(token);
- if (match <= 0)
- return null;
-
- // = to skip
- match += token.length() + 1;
- int trailingComa = headerLine.indexOf(",", match);
- String value = headerLine.substring(match, trailingComa > 0 ? trailingComa : headerLine.length());
- value = value.length() > 0 && value.charAt(value.length() - 1) == '"'
- ? value.substring(0, value.length() - 1)
- : value;
- return value.charAt(0) == '"' ? value.substring(1) : value;
+ public String getNtlmHost() {
+ return ntlmHost;
}
- private byte[] md5FromRecycledStringBuilder(StringBuilder sb, MessageDigest md) {
- md.update(StringUtils.charSequence2ByteBuffer(sb, ISO_8859_1));
- sb.setLength(0);
- return md.digest();
+ public boolean isUseAbsoluteURI() {
+ return useAbsoluteURI;
}
- private byte[] ha1(StringBuilder sb, MessageDigest md) {
- // if algorithm is "MD5" or is unspecified => A1 = username ":" realm-value ":"
- // passwd
- // if algorithm is "MD5-sess" => A1 = MD5( username-value ":" realm-value ":"
- // passwd ) ":" nonce-value ":" cnonce-value
-
- sb.append(principal).append(':').append(realmName).append(':').append(password);
- byte[] core = md5FromRecycledStringBuilder(sb, md);
-
- if (algorithm == null || algorithm.equals("MD5")) {
- // A1 = username ":" realm-value ":" passwd
- return core;
- } else if ("MD5-sess".equals(algorithm)) {
- // A1 = MD5(username ":" realm-value ":" passwd ) ":" nonce ":" cnonce
- appendBase16(sb, core);
- sb.append(':').append(nonce).append(':').append(cnonce);
- return md5FromRecycledStringBuilder(sb, md);
- }
-
- throw new UnsupportedOperationException("Digest algorithm not supported: " + algorithm);
+ public boolean isOmitQuery() {
+ return omitQuery;
}
- private byte[] ha2(StringBuilder sb, String digestUri, MessageDigest md) {
-
- // if qop is "auth" or is unspecified => A2 = Method ":" digest-uri-value
- // if qop is "auth-int" => A2 = Method ":" digest-uri-value ":" H(entity-body)
- sb.append(methodName).append(':').append(digestUri);
- if ("auth-int".equals(qop)) {
- // when qop == "auth-int", A2 = Method ":" digest-uri-value ":" H(entity-body)
- // but we don't have the request body here
- // we would need a new API
- sb.append(':').append(EMPTY_ENTITY_MD5);
-
- } else if (qop != null && !qop.equals("auth")) {
- throw new UnsupportedOperationException("Digest qop not supported: " + qop);
- }
-
- return md5FromRecycledStringBuilder(sb, md);
+ public Map getCustomLoginConfig() {
+ return customLoginConfig;
}
- private void appendMiddlePart(StringBuilder sb) {
- // request-digest = MD5(H(A1) ":" nonce ":" nc ":" cnonce ":" qop ":" H(A2))
- sb.append(':').append(nonce).append(':');
- if ("auth".equals(qop) || "auth-int".equals(qop)) {
- sb.append(nc).append(':').append(cnonce).append(':').append(qop).append(':');
- }
+ public String getServicePrincipalName() {
+ return servicePrincipalName;
}
- private void newResponse(MessageDigest md) {
- // when using preemptive auth, the request uri is missing
- if (uri != null) {
- // BEWARE: compute first as it uses the cached StringBuilder
- String digestUri = AuthenticatorUtils.computeRealmURI(uri, useAbsoluteURI, omitQuery);
-
- StringBuilder sb = StringBuilderPool.DEFAULT.stringBuilder();
+ public boolean isUseCanonicalHostname() {
+ return useCanonicalHostname;
+ }
- // WARNING: DON'T MOVE, BUFFER IS RECYCLED!!!!
- byte[] ha1 = ha1(sb, md);
- byte[] ha2 = ha2(sb, digestUri, md);
+ public String getLoginContextName() {
+ return loginContextName;
+ }
- appendBase16(sb, ha1);
- appendMiddlePart(sb);
- appendBase16(sb, ha2);
+ @Override
+ public String toString() {
+ return "Realm{" +
+ "principal='" + principal + '\'' +
+ ", password='" + password + '\'' +
+ ", scheme=" + scheme +
+ ", realmName='" + realmName + '\'' +
+ ", nonce='" + nonce + '\'' +
+ ", algorithm='" + algorithm + '\'' +
+ ", response='" + response + '\'' +
+ ", opaque='" + opaque + '\'' +
+ ", qop='" + qop + '\'' +
+ ", nc='" + nc + '\'' +
+ ", cnonce='" + cnonce + '\'' +
+ ", uri=" + uri +
+ ", usePreemptiveAuth=" + usePreemptiveAuth +
+ ", charset=" + charset +
+ ", ntlmHost='" + ntlmHost + '\'' +
+ ", ntlmDomain='" + ntlmDomain + '\'' +
+ ", useAbsoluteURI=" + useAbsoluteURI +
+ ", omitQuery=" + omitQuery +
+ ", customLoginConfig=" + customLoginConfig +
+ ", servicePrincipalName='" + servicePrincipalName + '\'' +
+ ", useCanonicalHostname=" + useCanonicalHostname +
+ ", loginContextName='" + loginContextName + '\'' +
+ '}';
+ }
- byte[] responseDigest = md5FromRecycledStringBuilder(sb, md);
- response = toHexString(responseDigest);
- }
+ public enum AuthScheme {
+ BASIC, DIGEST, NTLM, SPNEGO, KERBEROS
}
/**
- * Build a {@link Realm}
- *
- * @return a {@link Realm}
+ * A builder for {@link Realm}
*/
- public Realm build() {
-
- // Avoid generating
- if (isNonEmpty(nonce)) {
- MessageDigest md = pooledMd5MessageDigest();
- newCnonce(md);
- newResponse(md);
- }
-
- return new Realm(scheme,
- principal,
- password,
- realmName,
- nonce,
- algorithm,
- response,
- opaque,
- qop,
- nc,
- cnonce,
- uri,
- usePreemptive,
- charset,
- ntlmDomain,
- ntlmHost,
- useAbsoluteURI,
- omitQuery,
- servicePrincipalName,
- useCanonicalHostname,
- customLoginConfig,
- loginContextName);
+ public static class Builder {
+
+ private final String principal;
+ private final String password;
+ private AuthScheme scheme;
+ private String realmName;
+ private String nonce;
+ private String algorithm;
+ private String response;
+ private String opaque;
+ private String qop;
+ private String nc = DEFAULT_NC;
+ private String cnonce;
+ private Uri uri;
+ private String methodName = "GET";
+ private boolean usePreemptive;
+ private String ntlmDomain = System.getProperty("http.auth.ntlm.domain");
+ private Charset charset = UTF_8;
+ private String ntlmHost = "localhost";
+ private boolean useAbsoluteURI;
+ private boolean omitQuery;
+ /**
+ * Kerberos/Spnego properties
+ */
+ private Map customLoginConfig;
+ private String servicePrincipalName;
+ private boolean useCanonicalHostname;
+ private String loginContextName;
+
+ public Builder() {
+ principal = null;
+ password = null;
+ }
+
+ public Builder(String principal, String password) {
+ this.principal = principal;
+ this.password = password;
+ }
+
+ public Builder setNtlmDomain(String ntlmDomain) {
+ this.ntlmDomain = ntlmDomain;
+ return this;
+ }
+
+ public Builder setNtlmHost(String host) {
+ ntlmHost = host;
+ return this;
+ }
+
+ public Builder setScheme(AuthScheme scheme) {
+ this.scheme = scheme;
+ return this;
+ }
+
+ public Builder setRealmName(String realmName) {
+ this.realmName = realmName;
+ return this;
+ }
+
+ public Builder setNonce(String nonce) {
+ this.nonce = nonce;
+ return this;
+ }
+
+ public Builder setAlgorithm(String algorithm) {
+ this.algorithm = algorithm;
+ return this;
+ }
+
+ public Builder setResponse(String response) {
+ this.response = response;
+ return this;
+ }
+
+ public Builder setOpaque(String opaque) {
+ this.opaque = opaque;
+ return this;
+ }
+
+ public Builder setQop(String qop) {
+ if (isNonEmpty(qop)) {
+ this.qop = qop;
+ }
+ return this;
+ }
+
+ public Builder setNc(String nc) {
+ this.nc = nc;
+ return this;
+ }
+
+ public Builder setUri(Uri uri) {
+ this.uri = uri;
+ return this;
+ }
+
+ public Builder setMethodName(String methodName) {
+ this.methodName = methodName;
+ return this;
+ }
+
+ public Builder setUsePreemptiveAuth(boolean usePreemptiveAuth) {
+ usePreemptive = usePreemptiveAuth;
+ return this;
+ }
+
+ public Builder setUseAbsoluteURI(boolean useAbsoluteURI) {
+ this.useAbsoluteURI = useAbsoluteURI;
+ return this;
+ }
+
+ public Builder setOmitQuery(boolean omitQuery) {
+ this.omitQuery = omitQuery;
+ return this;
+ }
+
+ public Builder setCharset(Charset charset) {
+ this.charset = charset;
+ return this;
+ }
+
+ public Builder setCustomLoginConfig(Map customLoginConfig) {
+ this.customLoginConfig = customLoginConfig;
+ return this;
+ }
+
+ public Builder setServicePrincipalName(String servicePrincipalName) {
+ this.servicePrincipalName = servicePrincipalName;
+ return this;
+ }
+
+ public Builder setUseCanonicalHostname(boolean useCanonicalHostname) {
+ this.useCanonicalHostname = useCanonicalHostname;
+ return this;
+ }
+
+ public Builder setLoginContextName(String loginContextName) {
+ this.loginContextName = loginContextName;
+ return this;
+ }
+
+ private static String parseRawQop(String rawQop) {
+ String[] rawServerSupportedQops = rawQop.split(",");
+ String[] serverSupportedQops = new String[rawServerSupportedQops.length];
+ for (int i = 0; i < rawServerSupportedQops.length; i++) {
+ serverSupportedQops[i] = rawServerSupportedQops[i].trim();
+ }
+
+ // prefer auth over auth-int
+ for (String rawServerSupportedQop : serverSupportedQops) {
+ if ("auth".equals(rawServerSupportedQop)) {
+ return rawServerSupportedQop;
+ }
+ }
+
+ for (String rawServerSupportedQop : serverSupportedQops) {
+ if ("auth-int".equals(rawServerSupportedQop)) {
+ return rawServerSupportedQop;
+ }
+ }
+
+ return null;
+ }
+
+ public Builder parseWWWAuthenticateHeader(String headerLine) {
+ setRealmName(match(headerLine, "realm"))
+ .setNonce(match(headerLine, "nonce"))
+ .setOpaque(match(headerLine, "opaque"))
+ .setScheme(isNonEmpty(nonce) ? AuthScheme.DIGEST : AuthScheme.BASIC);
+ String algorithm = match(headerLine, "algorithm");
+ if (isNonEmpty(algorithm)) {
+ setAlgorithm(algorithm);
+ }
+
+ // FIXME qop is different with proxy?
+ String rawQop = match(headerLine, "qop");
+ if (rawQop != null) {
+ setQop(parseRawQop(rawQop));
+ }
+
+ return this;
+ }
+
+ public Builder parseProxyAuthenticateHeader(String headerLine) {
+ setRealmName(match(headerLine, "realm"))
+ .setNonce(match(headerLine, "nonce"))
+ .setOpaque(match(headerLine, "opaque"))
+ .setScheme(isNonEmpty(nonce) ? AuthScheme.DIGEST : AuthScheme.BASIC);
+ String algorithm = match(headerLine, "algorithm");
+ if (isNonEmpty(algorithm)) {
+ setAlgorithm(algorithm);
+ }
+ // FIXME qop is different with proxy?
+ setQop(match(headerLine, "qop"));
+
+ return this;
+ }
+
+ private void newCnonce(MessageDigest md) {
+ byte[] b = new byte[8];
+ ThreadLocalRandom.current().nextBytes(b);
+ b = md.digest(b);
+ cnonce = toHexString(b);
+ }
+
+ /**
+ * TODO: A Pattern/Matcher may be better.
+ */
+ private static String match(String headerLine, String token) {
+ if (headerLine == null) {
+ return null;
+ }
+
+ int match = headerLine.indexOf(token);
+ if (match <= 0) {
+ return null;
+ }
+
+ // = to skip
+ match += token.length() + 1;
+ int trailingComa = headerLine.indexOf(',', match);
+ String value = headerLine.substring(match, trailingComa > 0 ? trailingComa : headerLine.length());
+ value = value.length() > 0 && value.charAt(value.length() - 1) == '"'
+ ? value.substring(0, value.length() - 1)
+ : value;
+ return value.charAt(0) == '"' ? value.substring(1) : value;
+ }
+
+ private static byte[] md5FromRecycledStringBuilder(StringBuilder sb, MessageDigest md) {
+ md.update(StringUtils.charSequence2ByteBuffer(sb, ISO_8859_1));
+ sb.setLength(0);
+ return md.digest();
+ }
+
+ private byte[] ha1(StringBuilder sb, MessageDigest md) {
+ // if algorithm is "MD5" or is unspecified => A1 = username ":" realm-value ":"
+ // passwd
+ // if algorithm is "MD5-sess" => A1 = MD5( username-value ":" realm-value ":"
+ // passwd ) ":" nonce-value ":" cnonce-value
+
+ sb.append(principal).append(':').append(realmName).append(':').append(password);
+ byte[] core = md5FromRecycledStringBuilder(sb, md);
+
+ if (algorithm == null || "MD5".equals(algorithm)) {
+ // A1 = username ":" realm-value ":" passwd
+ return core;
+ }
+ if ("MD5-sess".equals(algorithm)) {
+ // A1 = MD5(username ":" realm-value ":" passwd ) ":" nonce ":" cnonce
+ appendBase16(sb, core);
+ sb.append(':').append(nonce).append(':').append(cnonce);
+ return md5FromRecycledStringBuilder(sb, md);
+ }
+
+ throw new UnsupportedOperationException("Digest algorithm not supported: " + algorithm);
+ }
+
+ private byte[] ha2(StringBuilder sb, String digestUri, MessageDigest md) {
+
+ // if qop is "auth" or is unspecified => A2 = Method ":" digest-uri-value
+ // if qop is "auth-int" => A2 = Method ":" digest-uri-value ":" H(entity-body)
+ sb.append(methodName).append(':').append(digestUri);
+ if ("auth-int".equals(qop)) {
+ // when qop == "auth-int", A2 = Method ":" digest-uri-value ":" H(entity-body)
+ // but we don't have the request body here
+ // we would need a new API
+ sb.append(':').append(EMPTY_ENTITY_MD5);
+
+ } else if (qop != null && !"auth".equals(qop)) {
+ throw new UnsupportedOperationException("Digest qop not supported: " + qop);
+ }
+
+ return md5FromRecycledStringBuilder(sb, md);
+ }
+
+ private void appendMiddlePart(StringBuilder sb) {
+ // request-digest = MD5(H(A1) ":" nonce ":" nc ":" cnonce ":" qop ":" H(A2))
+ sb.append(':').append(nonce).append(':');
+ if ("auth".equals(qop) || "auth-int".equals(qop)) {
+ sb.append(nc).append(':').append(cnonce).append(':').append(qop).append(':');
+ }
+ }
+
+ private void newResponse(MessageDigest md) {
+ // when using preemptive auth, the request uri is missing
+ if (uri != null) {
+ // BEWARE: compute first as it uses the cached StringBuilder
+ String digestUri = AuthenticatorUtils.computeRealmURI(uri, useAbsoluteURI, omitQuery);
+
+ StringBuilder sb = StringBuilderPool.DEFAULT.stringBuilder();
+
+ // WARNING: DON'T MOVE, BUFFER IS RECYCLED!!!!
+ byte[] ha1 = ha1(sb, md);
+ byte[] ha2 = ha2(sb, digestUri, md);
+
+ appendBase16(sb, ha1);
+ appendMiddlePart(sb);
+ appendBase16(sb, ha2);
+
+ byte[] responseDigest = md5FromRecycledStringBuilder(sb, md);
+ response = toHexString(responseDigest);
+ }
+ }
+
+ /**
+ * Build a {@link Realm}
+ *
+ * @return a {@link Realm}
+ */
+ public Realm build() {
+
+ // Avoid generating
+ if (isNonEmpty(nonce)) {
+ MessageDigest md = pooledMd5MessageDigest();
+ newCnonce(md);
+ newResponse(md);
+ }
+
+ return new Realm(scheme,
+ principal,
+ password,
+ realmName,
+ nonce,
+ algorithm,
+ response,
+ opaque,
+ qop,
+ nc,
+ cnonce,
+ uri,
+ usePreemptive,
+ charset,
+ ntlmDomain,
+ ntlmHost,
+ useAbsoluteURI,
+ omitQuery,
+ servicePrincipalName,
+ useCanonicalHostname,
+ customLoginConfig,
+ loginContextName);
+ }
}
- }
}
diff --git a/client/src/main/java/org/asynchttpclient/Request.java b/client/src/main/java/org/asynchttpclient/Request.java
index cf6a82dee2..a5915c123a 100644
--- a/client/src/main/java/org/asynchttpclient/Request.java
+++ b/client/src/main/java/org/asynchttpclient/Request.java
@@ -46,146 +46,146 @@
*/
public interface Request {
- /**
- * @return the request's HTTP method (GET, POST, etc.)
- */
- String getMethod();
-
- /**
- * @return the uri
- */
- Uri getUri();
-
- /**
- * @return the url (the uri's String form)
- */
- String getUrl();
-
- /**
- * @return the InetAddress to be used to bypass uri's hostname resolution
- */
- InetAddress getAddress();
-
- /**
- * @return the local address to bind from
- */
- InetAddress getLocalAddress();
-
- /**
- * @return the HTTP headers
- */
- HttpHeaders getHeaders();
-
- /**
- * @return the HTTP cookies
- */
- List getCookies();
-
- /**
- * @return the request's body byte array (only non null if it was set this way)
- */
- byte[] getByteData();
-
- /**
- * @return the request's body array of byte arrays (only non null if it was set this way)
- */
- List getCompositeByteData();
-
- /**
- * @return the request's body string (only non null if it was set this way)
- */
- String getStringData();
-
- /**
- * @return the request's body ByteBuffer (only non null if it was set this way)
- */
- ByteBuffer getByteBufferData();
-
- /**
- * @return the request's body InputStream (only non null if it was set this way)
- */
- InputStream getStreamData();
-
- /**
- * @return the request's body BodyGenerator (only non null if it was set this way)
- */
- BodyGenerator getBodyGenerator();
-
- /**
- * @return the request's form parameters
- */
- List getFormParams();
-
- /**
- * @return the multipart parts
- */
- List getBodyParts();
-
- /**
- * @return the virtual host to connect to
- */
- String getVirtualHost();
-
- /**
- * @return the query params resolved from the url/uri
- */
- List getQueryParams();
-
- /**
- * @return the proxy server to be used to perform this request (overrides the one defined in config)
- */
- ProxyServer getProxyServer();
-
- /**
- * @return the realm to be used to perform this request (overrides the one defined in config)
- */
- Realm getRealm();
-
- /**
- * @return the file to be uploaded
- */
- File getFile();
-
- /**
- * @return if this request is to follow redirects. Non null values means "override config value".
- */
- Boolean getFollowRedirect();
-
- /**
- * @return the request timeout. Non zero values means "override config value".
- */
- int getRequestTimeout();
-
- /**
- * @return the read timeout. Non zero values means "override config value".
- */
- int getReadTimeout();
-
- /**
- * @return the range header value, or 0 is not set.
- */
- long getRangeOffset();
-
- /**
- * @return the charset value used when decoding the request's body.
- */
- Charset getCharset();
-
- /**
- * @return the strategy to compute ChannelPool's keys
- */
- ChannelPoolPartitioning getChannelPoolPartitioning();
-
- /**
- * @return the NameResolver to be used to resolve hostnams's IP
- */
- NameResolver getNameResolver();
-
- /**
- * @return a new request builder using this request as a prototype
- */
- @SuppressWarnings("deprecation")
- default RequestBuilder toBuilder() {
- return new RequestBuilder(this);
- }
+ /**
+ * @return the request's HTTP method (GET, POST, etc.)
+ */
+ String getMethod();
+
+ /**
+ * @return the uri
+ */
+ Uri getUri();
+
+ /**
+ * @return the url (the uri's String form)
+ */
+ String getUrl();
+
+ /**
+ * @return the InetAddress to be used to bypass uri's hostname resolution
+ */
+ InetAddress getAddress();
+
+ /**
+ * @return the local address to bind from
+ */
+ InetAddress getLocalAddress();
+
+ /**
+ * @return the HTTP headers
+ */
+ HttpHeaders getHeaders();
+
+ /**
+ * @return the HTTP cookies
+ */
+ List getCookies();
+
+ /**
+ * @return the request's body byte array (only non null if it was set this way)
+ */
+ byte[] getByteData();
+
+ /**
+ * @return the request's body array of byte arrays (only non null if it was set this way)
+ */
+ List getCompositeByteData();
+
+ /**
+ * @return the request's body string (only non null if it was set this way)
+ */
+ String getStringData();
+
+ /**
+ * @return the request's body ByteBuffer (only non null if it was set this way)
+ */
+ ByteBuffer getByteBufferData();
+
+ /**
+ * @return the request's body InputStream (only non null if it was set this way)
+ */
+ InputStream getStreamData();
+
+ /**
+ * @return the request's body BodyGenerator (only non null if it was set this way)
+ */
+ BodyGenerator getBodyGenerator();
+
+ /**
+ * @return the request's form parameters
+ */
+ List getFormParams();
+
+ /**
+ * @return the multipart parts
+ */
+ List getBodyParts();
+
+ /**
+ * @return the virtual host to connect to
+ */
+ String getVirtualHost();
+
+ /**
+ * @return the query params resolved from the url/uri
+ */
+ List getQueryParams();
+
+ /**
+ * @return the proxy server to be used to perform this request (overrides the one defined in config)
+ */
+ ProxyServer getProxyServer();
+
+ /**
+ * @return the realm to be used to perform this request (overrides the one defined in config)
+ */
+ Realm getRealm();
+
+ /**
+ * @return the file to be uploaded
+ */
+ File getFile();
+
+ /**
+ * @return if this request is to follow redirects. Non null values means "override config value".
+ */
+ Boolean getFollowRedirect();
+
+ /**
+ * @return the request timeout. Non zero values means "override config value".
+ */
+ int getRequestTimeout();
+
+ /**
+ * @return the read timeout. Non zero values means "override config value".
+ */
+ int getReadTimeout();
+
+ /**
+ * @return the range header value, or 0 is not set.
+ */
+ long getRangeOffset();
+
+ /**
+ * @return the charset value used when decoding the request's body.
+ */
+ Charset getCharset();
+
+ /**
+ * @return the strategy to compute ChannelPool's keys
+ */
+ ChannelPoolPartitioning getChannelPoolPartitioning();
+
+ /**
+ * @return the NameResolver to be used to resolve hostnams's IP
+ */
+ NameResolver getNameResolver();
+
+ /**
+ * @return a new request builder using this request as a prototype
+ */
+ @SuppressWarnings("deprecation")
+ default RequestBuilder toBuilder() {
+ return new RequestBuilder(this);
+ }
}
diff --git a/client/src/main/java/org/asynchttpclient/RequestBuilder.java b/client/src/main/java/org/asynchttpclient/RequestBuilder.java
index 4761f0c2c4..fed545a6f4 100644
--- a/client/src/main/java/org/asynchttpclient/RequestBuilder.java
+++ b/client/src/main/java/org/asynchttpclient/RequestBuilder.java
@@ -23,32 +23,32 @@
*/
public class RequestBuilder extends RequestBuilderBase {
- public RequestBuilder() {
- this(GET);
- }
-
- public RequestBuilder(String method) {
- this(method, false);
- }
-
- public RequestBuilder(String method, boolean disableUrlEncoding) {
- super(method, disableUrlEncoding);
- }
-
- public RequestBuilder(String method, boolean disableUrlEncoding, boolean validateHeaders) {
- super(method, disableUrlEncoding, validateHeaders);
- }
-
- /**
- * @deprecated Use request.toBuilder() instead
- */
- @Deprecated
- public RequestBuilder(Request prototype) {
- super(prototype);
- }
-
- @Deprecated
- public RequestBuilder(Request prototype, boolean disableUrlEncoding, boolean validateHeaders) {
- super(prototype, disableUrlEncoding, validateHeaders);
- }
+ public RequestBuilder() {
+ this(GET);
+ }
+
+ public RequestBuilder(String method) {
+ this(method, false);
+ }
+
+ public RequestBuilder(String method, boolean disableUrlEncoding) {
+ super(method, disableUrlEncoding);
+ }
+
+ public RequestBuilder(String method, boolean disableUrlEncoding, boolean validateHeaders) {
+ super(method, disableUrlEncoding, validateHeaders);
+ }
+
+ /**
+ * @deprecated Use request.toBuilder() instead
+ */
+ @Deprecated
+ public RequestBuilder(Request prototype) {
+ super(prototype);
+ }
+
+ @Deprecated
+ public RequestBuilder(Request prototype, boolean disableUrlEncoding, boolean validateHeaders) {
+ super(prototype, disableUrlEncoding, validateHeaders);
+ }
}
diff --git a/client/src/main/java/org/asynchttpclient/RequestBuilderBase.java b/client/src/main/java/org/asynchttpclient/RequestBuilderBase.java
index 35c8145776..0471d1c3a9 100644
--- a/client/src/main/java/org/asynchttpclient/RequestBuilderBase.java
+++ b/client/src/main/java/org/asynchttpclient/RequestBuilderBase.java
@@ -25,11 +25,9 @@
import org.asynchttpclient.channel.ChannelPoolPartitioning;
import org.asynchttpclient.proxy.ProxyServer;
import org.asynchttpclient.request.body.generator.BodyGenerator;
-import org.asynchttpclient.request.body.generator.ReactiveStreamsBodyGenerator;
import org.asynchttpclient.request.body.multipart.Part;
import org.asynchttpclient.uri.Uri;
import org.asynchttpclient.util.UriEncoder;
-import org.reactivestreams.Publisher;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@@ -38,7 +36,11 @@
import java.net.InetAddress;
import java.nio.ByteBuffer;
import java.nio.charset.Charset;
-import java.util.*;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.List;
+import java.util.Map;
import static io.netty.handler.codec.http.HttpHeaderNames.CONTENT_TYPE;
import static java.nio.charset.StandardCharsets.UTF_8;
@@ -53,595 +55,603 @@
*/
public abstract class RequestBuilderBase> {
- private final static Logger LOGGER = LoggerFactory.getLogger(RequestBuilderBase.class);
- private static final Uri DEFAULT_REQUEST_URL = Uri.create("http://localhost");
- public static NameResolver DEFAULT_NAME_RESOLVER = new DefaultNameResolver(ImmediateEventExecutor.INSTANCE);
- // builder only fields
- protected UriEncoder uriEncoder;
- protected List queryParams;
- protected SignatureCalculator signatureCalculator;
-
- // request fields
- protected String method;
- protected Uri uri;
- protected InetAddress address;
- protected InetAddress localAddress;
- protected HttpHeaders headers;
- protected ArrayList cookies;
- protected byte[] byteData;
- protected List compositeByteData;
- protected String stringData;
- protected ByteBuffer byteBufferData;
- protected InputStream streamData;
- protected BodyGenerator bodyGenerator;
- protected List formParams;
- protected List bodyParts;
- protected String virtualHost;
- protected ProxyServer proxyServer;
- protected Realm realm;
- protected File file;
- protected Boolean followRedirect;
- protected int requestTimeout;
- protected int readTimeout;
- protected long rangeOffset;
- protected Charset charset;
- protected ChannelPoolPartitioning channelPoolPartitioning = ChannelPoolPartitioning.PerHostChannelPoolPartitioning.INSTANCE;
- protected NameResolver nameResolver = DEFAULT_NAME_RESOLVER;
-
- protected RequestBuilderBase(String method, boolean disableUrlEncoding) {
- this(method, disableUrlEncoding, true);
- }
-
- protected RequestBuilderBase(String method, boolean disableUrlEncoding, boolean validateHeaders) {
- this.method = method;
- this.uriEncoder = UriEncoder.uriEncoder(disableUrlEncoding);
- this.headers = new DefaultHttpHeaders(validateHeaders);
- }
-
- protected RequestBuilderBase(Request prototype) {
- this(prototype, false, false);
- }
-
- protected RequestBuilderBase(Request prototype, boolean disableUrlEncoding, boolean validateHeaders) {
- this.method = prototype.getMethod();
- this.uriEncoder = UriEncoder.uriEncoder(disableUrlEncoding);
- this.uri = prototype.getUri();
- this.address = prototype.getAddress();
- this.localAddress = prototype.getLocalAddress();
- this.headers = new DefaultHttpHeaders(validateHeaders);
- this.headers.add(prototype.getHeaders());
- if (isNonEmpty(prototype.getCookies())) {
- this.cookies = new ArrayList<>(prototype.getCookies());
- }
- this.byteData = prototype.getByteData();
- this.compositeByteData = prototype.getCompositeByteData();
- this.stringData = prototype.getStringData();
- this.byteBufferData = prototype.getByteBufferData();
- this.streamData = prototype.getStreamData();
- this.bodyGenerator = prototype.getBodyGenerator();
- if (isNonEmpty(prototype.getFormParams())) {
- this.formParams = new ArrayList<>(prototype.getFormParams());
- }
- if (isNonEmpty(prototype.getBodyParts())) {
- this.bodyParts = new ArrayList<>(prototype.getBodyParts());
- }
- this.virtualHost = prototype.getVirtualHost();
- this.proxyServer = prototype.getProxyServer();
- this.realm = prototype.getRealm();
- this.file = prototype.getFile();
- this.followRedirect = prototype.getFollowRedirect();
- this.requestTimeout = prototype.getRequestTimeout();
- this.readTimeout = prototype.getReadTimeout();
- this.rangeOffset = prototype.getRangeOffset();
- this.charset = prototype.getCharset();
- this.channelPoolPartitioning = prototype.getChannelPoolPartitioning();
- this.nameResolver = prototype.getNameResolver();
- }
-
- @SuppressWarnings("unchecked")
- private T asDerivedType() {
- return (T) this;
- }
-
- public T setUrl(String url) {
- return setUri(Uri.create(url));
- }
-
- public T setUri(Uri uri) {
- this.uri = uri;
- return asDerivedType();
- }
-
- public T setAddress(InetAddress address) {
- this.address = address;
- return asDerivedType();
- }
-
- public T setLocalAddress(InetAddress address) {
- this.localAddress = address;
- return asDerivedType();
- }
-
- public T setVirtualHost(String virtualHost) {
- this.virtualHost = virtualHost;
- return asDerivedType();
- }
-
- /**
- * Remove all added headers
- *
- * @return {@code this}
- */
- public T clearHeaders() {
- this.headers.clear();
- return asDerivedType();
- }
-
- /**
- * @param name header name
- * @param value header value to set
- * @return {@code this}
- * @see #setHeader(CharSequence, Object)
- */
- public T setHeader(CharSequence name, String value) {
- return setHeader(name, (Object) value);
- }
-
- /**
- * Set uni-value header for the request
- *
- * @param name header name
- * @param value header value to set
- * @return {@code this}
- */
- public T setHeader(CharSequence name, Object value) {
- this.headers.set(name, value);
- return asDerivedType();
- }
-
- /**
- * Set multi-values header for the request
- *
- * @param name header name
- * @param values {@code Iterable} with multiple header values to set
- * @return {@code this}
- */
- public T setHeader(CharSequence name, Iterable> values) {
- this.headers.set(name, values);
- return asDerivedType();
- }
-
- /**
- * @param name header name
- * @param value header value to add
- * @return {@code this}
- * @see #addHeader(CharSequence, Object)
- */
- public T addHeader(CharSequence name, String value) {
- return addHeader(name, (Object) value);
- }
-
- /**
- * Add a header value for the request. If a header with {@code name} was setup for this request already -
- * call will add one more header value and convert it to multi-value header
- *
- * @param name header name
- * @param value header value to add
- * @return {@code this}
- */
- public T addHeader(CharSequence name, Object value) {
- if (value == null) {
- LOGGER.warn("Value was null, set to \"\"");
- value = "";
- }
-
- this.headers.add(name, value);
- return asDerivedType();
- }
-
- /**
- * Add header values for the request. If a header with {@code name} was setup for this request already -
- * call will add more header values and convert it to multi-value header
- *
- * @param name header name
- * @param values {@code Iterable} with multiple header values to add
- * @return {@code}
- */
- public T addHeader(CharSequence name, Iterable> values) {
- this.headers.add(name, values);
- return asDerivedType();
- }
-
- public T setHeaders(HttpHeaders headers) {
- if (headers == null)
- this.headers.clear();
- else
- this.headers = headers;
- return asDerivedType();
- }
-
- /**
- * Set request headers using a map {@code headers} of pair (Header name, Header values)
- * This method could be used to setup multi-valued headers
- *
- * @param headers map of header names as the map keys and header values {@link Iterable} as the map values
- * @return {@code this}
- */
- public T setHeaders(Map extends CharSequence, ? extends Iterable>> headers) {
- clearHeaders();
- if (headers != null) {
- headers.forEach((name, values) -> this.headers.add(name, values));
- }
- return asDerivedType();
- }
-
- /**
- * Set single-value request headers using a map {@code headers} of pairs (Header name, Header value).
- * To set headers with multiple values use {@link #setHeaders(Map)}
- *
- * @param headers map of header names as the map keys and header values as the map values
- * @return {@code this}
- */
- public T setSingleHeaders(Map extends CharSequence, ?> headers) {
- clearHeaders();
- if (headers != null) {
- headers.forEach((name, value) -> this.headers.add(name, value));
- }
- return asDerivedType();
- }
-
- private void lazyInitCookies() {
- if (this.cookies == null)
- this.cookies = new ArrayList<>(3);
- }
-
- public T setCookies(Collection cookies) {
- this.cookies = new ArrayList<>(cookies);
- return asDerivedType();
- }
-
- public T addCookie(Cookie cookie) {
- lazyInitCookies();
- this.cookies.add(cookie);
- return asDerivedType();
- }
-
- /**
- * Add/replace a cookie based on its name
- * @param cookie the new cookie
- * @return this
- */
- public T addOrReplaceCookie(Cookie cookie) {
- String cookieKey = cookie.name();
- boolean replace = false;
- int index = 0;
- lazyInitCookies();
- for (Cookie c : this.cookies) {
- if (c.name().equals(cookieKey)) {
- replace = true;
- break;
- }
-
- index++;
- }
- if (replace)
- this.cookies.set(index, cookie);
- else
- this.cookies.add(cookie);
- return asDerivedType();
- }
-
- public void resetCookies() {
- if (this.cookies != null)
- this.cookies.clear();
- }
-
- public void resetQuery() {
- queryParams = null;
- if (this.uri != null)
- this.uri = this.uri.withNewQuery(null);
- }
-
- public void resetFormParams() {
- this.formParams = null;
- }
-
- public void resetNonMultipartData() {
- this.byteData = null;
- this.compositeByteData = null;
- this.byteBufferData = null;
- this.stringData = null;
- this.streamData = null;
- this.bodyGenerator = null;
- }
-
- public void resetMultipartData() {
- this.bodyParts = null;
- }
-
- public T setBody(File file) {
- this.file = file;
- return asDerivedType();
- }
-
- private void resetBody() {
- resetFormParams();
- resetNonMultipartData();
- resetMultipartData();
- }
-
- public T setBody(byte[] data) {
- resetBody();
- this.byteData = data;
- return asDerivedType();
- }
-
- public T setBody(List data) {
- resetBody();
- this.compositeByteData = data;
- return asDerivedType();
- }
-
- public T setBody(String data) {
- resetBody();
- this.stringData = data;
- return asDerivedType();
- }
-
- public T setBody(ByteBuffer data) {
- resetBody();
- this.byteBufferData = data;
- return asDerivedType();
- }
-
- public T setBody(InputStream stream) {
- resetBody();
- this.streamData = stream;
- return asDerivedType();
- }
-
- public T setBody(Publisher publisher) {
- return setBody(publisher, -1L);
- }
-
- public T setBody(Publisher publisher, long contentLength) {
- return setBody(new ReactiveStreamsBodyGenerator(publisher, contentLength));
- }
-
- public T setBody(BodyGenerator bodyGenerator) {
- this.bodyGenerator = bodyGenerator;
- return asDerivedType();
- }
-
- public T addQueryParam(String name, String value) {
- if (queryParams == null)
- queryParams = new ArrayList<>(1);
- queryParams.add(new Param(name, value));
- return asDerivedType();
- }
-
- public T addQueryParams(List params) {
- if (queryParams == null)
- queryParams = params;
- else
- queryParams.addAll(params);
- return asDerivedType();
- }
-
- public T setQueryParams(Map> map) {
- return setQueryParams(Param.map2ParamList(map));
- }
-
- public T setQueryParams(List params) {
- // reset existing query
- if (this.uri != null && isNonEmpty(this.uri.getQuery()))
- this.uri = this.uri.withNewQuery(null);
- queryParams = params;
- return asDerivedType();
- }
-
- public T addFormParam(String name, String value) {
- resetNonMultipartData();
- resetMultipartData();
- if (this.formParams == null)
- this.formParams = new ArrayList<>(1);
- this.formParams.add(new Param(name, value));
- return asDerivedType();
- }
-
- public T setFormParams(Map> map) {
- return setFormParams(Param.map2ParamList(map));
- }
-
- public T setFormParams(List params) {
- resetNonMultipartData();
- resetMultipartData();
- this.formParams = params;
- return asDerivedType();
- }
-
- public T addBodyPart(Part bodyPart) {
- resetFormParams();
- resetNonMultipartData();
- if (this.bodyParts == null)
- this.bodyParts = new ArrayList<>();
- this.bodyParts.add(bodyPart);
- return asDerivedType();
- }
-
- public T setBodyParts(List bodyParts) {
- this.bodyParts = new ArrayList<>(bodyParts);
- return asDerivedType();
- }
-
- public T setProxyServer(ProxyServer proxyServer) {
- this.proxyServer = proxyServer;
- return asDerivedType();
- }
-
- public T setProxyServer(ProxyServer.Builder proxyServerBuilder) {
- this.proxyServer = proxyServerBuilder.build();
- return asDerivedType();
- }
-
- public T setRealm(Realm.Builder realm) {
- this.realm = realm.build();
- return asDerivedType();
- }
-
- public T setRealm(Realm realm) {
- this.realm = realm;
- return asDerivedType();
- }
-
- public T setFollowRedirect(boolean followRedirect) {
- this.followRedirect = followRedirect;
- return asDerivedType();
- }
-
- public T setRequestTimeout(int requestTimeout) {
- this.requestTimeout = requestTimeout;
- return asDerivedType();
- }
-
- public T setReadTimeout(int readTimeout) {
- this.readTimeout = readTimeout;
- return asDerivedType();
- }
-
- public T setRangeOffset(long rangeOffset) {
- this.rangeOffset = rangeOffset;
- return asDerivedType();
- }
-
- public T setMethod(String method) {
- this.method = method;
- return asDerivedType();
- }
-
- public T setCharset(Charset charset) {
- this.charset = charset;
- return asDerivedType();
- }
-
- public T setChannelPoolPartitioning(ChannelPoolPartitioning channelPoolPartitioning) {
- this.channelPoolPartitioning = channelPoolPartitioning;
- return asDerivedType();
- }
-
- public T setNameResolver(NameResolver nameResolver) {
- this.nameResolver = nameResolver;
- return asDerivedType();
- }
-
- public T setSignatureCalculator(SignatureCalculator signatureCalculator) {
- this.signatureCalculator = signatureCalculator;
- return asDerivedType();
- }
-
- private RequestBuilderBase> executeSignatureCalculator() {
- if (signatureCalculator == null)
- return this;
-
- // build a first version of the request, without signatureCalculator in play
- RequestBuilder rb = new RequestBuilder(this.method);
- // make copy of mutable collections so we don't risk affecting
- // original RequestBuilder
- // call setFormParams first as it resets other fields
- if (this.formParams != null)
- rb.setFormParams(this.formParams);
- if (this.headers != null)
- rb.headers.add(this.headers);
- if (this.cookies != null)
- rb.setCookies(this.cookies);
- if (this.bodyParts != null)
- rb.setBodyParts(this.bodyParts);
-
- // copy all other fields
- // but rb.signatureCalculator, that's the whole point here
- rb.uriEncoder = this.uriEncoder;
- rb.queryParams = this.queryParams;
- rb.uri = this.uri;
- rb.address = this.address;
- rb.localAddress = this.localAddress;
- rb.byteData = this.byteData;
- rb.compositeByteData = this.compositeByteData;
- rb.stringData = this.stringData;
- rb.byteBufferData = this.byteBufferData;
- rb.streamData = this.streamData;
- rb.bodyGenerator = this.bodyGenerator;
- rb.virtualHost = this.virtualHost;
- rb.proxyServer = this.proxyServer;
- rb.realm = this.realm;
- rb.file = this.file;
- rb.followRedirect = this.followRedirect;
- rb.requestTimeout = this.requestTimeout;
- rb.rangeOffset = this.rangeOffset;
- rb.charset = this.charset;
- rb.channelPoolPartitioning = this.channelPoolPartitioning;
- rb.nameResolver = this.nameResolver;
- Request unsignedRequest = rb.build();
- signatureCalculator.calculateAndAddSignature(unsignedRequest, rb);
- return rb;
- }
-
- private void updateCharset() {
- String contentTypeHeader = headers.get(CONTENT_TYPE);
- Charset contentTypeCharset = extractContentTypeCharsetAttribute(contentTypeHeader);
- charset = withDefault(contentTypeCharset, withDefault(charset, UTF_8));
- if (contentTypeHeader != null && contentTypeHeader.regionMatches(true, 0, "text/", 0, 5) && contentTypeCharset == null) {
- // add explicit charset to content-type header
- headers.set(CONTENT_TYPE, contentTypeHeader + "; charset=" + charset.name());
- }
- }
-
- private Uri computeUri() {
-
- Uri tempUri = this.uri;
- if (tempUri == null) {
- LOGGER.debug("setUrl hasn't been invoked. Using {}", DEFAULT_REQUEST_URL);
- tempUri = DEFAULT_REQUEST_URL;
- } else {
- Uri.validateSupportedScheme(tempUri);
- }
-
- return uriEncoder.encode(tempUri, queryParams);
- }
-
- public Request build() {
- updateCharset();
- RequestBuilderBase> rb = executeSignatureCalculator();
- Uri finalUri = rb.computeUri();
-
- // make copies of mutable internal collections
- List cookiesCopy = rb.cookies == null ? Collections.emptyList() : new ArrayList<>(rb.cookies);
- List formParamsCopy = rb.formParams == null ? Collections.emptyList() : new ArrayList<>(rb.formParams);
- List bodyPartsCopy = rb.bodyParts == null ? Collections.emptyList() : new ArrayList<>(rb.bodyParts);
-
- return new DefaultRequest(rb.method,
- finalUri,
- rb.address,
- rb.localAddress,
- rb.headers,
- cookiesCopy,
- rb.byteData,
- rb.compositeByteData,
- rb.stringData,
- rb.byteBufferData,
- rb.streamData,
- rb.bodyGenerator,
- formParamsCopy,
- bodyPartsCopy,
- rb.virtualHost,
- rb.proxyServer,
- rb.realm,
- rb.file,
- rb.followRedirect,
- rb.requestTimeout,
- rb.readTimeout,
- rb.rangeOffset,
- rb.charset,
- rb.channelPoolPartitioning,
- rb.nameResolver);
- }
+ private static final Logger LOGGER = LoggerFactory.getLogger(RequestBuilderBase.class);
+ private static final Uri DEFAULT_REQUEST_URL = Uri.create("http://localhost");
+ public static NameResolver DEFAULT_NAME_RESOLVER = new DefaultNameResolver(ImmediateEventExecutor.INSTANCE);
+ // builder only fields
+ protected UriEncoder uriEncoder;
+ protected List queryParams;
+ protected SignatureCalculator signatureCalculator;
+
+ // request fields
+ protected String method;
+ protected Uri uri;
+ protected InetAddress address;
+ protected InetAddress localAddress;
+ protected HttpHeaders headers;
+ protected ArrayList cookies;
+ protected byte[] byteData;
+ protected List compositeByteData;
+ protected String stringData;
+ protected ByteBuffer byteBufferData;
+ protected InputStream streamData;
+ protected BodyGenerator bodyGenerator;
+ protected List formParams;
+ protected List bodyParts;
+ protected String virtualHost;
+ protected ProxyServer proxyServer;
+ protected Realm realm;
+ protected File file;
+ protected Boolean followRedirect;
+ protected int requestTimeout;
+ protected int readTimeout;
+ protected long rangeOffset;
+ protected Charset charset;
+ protected ChannelPoolPartitioning channelPoolPartitioning = ChannelPoolPartitioning.PerHostChannelPoolPartitioning.INSTANCE;
+ protected NameResolver nameResolver = DEFAULT_NAME_RESOLVER;
+
+ protected RequestBuilderBase(String method, boolean disableUrlEncoding) {
+ this(method, disableUrlEncoding, true);
+ }
+
+ protected RequestBuilderBase(String method, boolean disableUrlEncoding, boolean validateHeaders) {
+ this.method = method;
+ uriEncoder = UriEncoder.uriEncoder(disableUrlEncoding);
+ headers = new DefaultHttpHeaders(validateHeaders);
+ }
+
+ protected RequestBuilderBase(Request prototype) {
+ this(prototype, false, false);
+ }
+
+ protected RequestBuilderBase(Request prototype, boolean disableUrlEncoding, boolean validateHeaders) {
+ method = prototype.getMethod();
+ uriEncoder = UriEncoder.uriEncoder(disableUrlEncoding);
+ uri = prototype.getUri();
+ address = prototype.getAddress();
+ localAddress = prototype.getLocalAddress();
+ headers = new DefaultHttpHeaders(validateHeaders);
+ headers.add(prototype.getHeaders());
+ if (isNonEmpty(prototype.getCookies())) {
+ cookies = new ArrayList<>(prototype.getCookies());
+ }
+ byteData = prototype.getByteData();
+ compositeByteData = prototype.getCompositeByteData();
+ stringData = prototype.getStringData();
+ byteBufferData = prototype.getByteBufferData();
+ streamData = prototype.getStreamData();
+ bodyGenerator = prototype.getBodyGenerator();
+ if (isNonEmpty(prototype.getFormParams())) {
+ formParams = new ArrayList<>(prototype.getFormParams());
+ }
+ if (isNonEmpty(prototype.getBodyParts())) {
+ bodyParts = new ArrayList<>(prototype.getBodyParts());
+ }
+ virtualHost = prototype.getVirtualHost();
+ proxyServer = prototype.getProxyServer();
+ realm = prototype.getRealm();
+ file = prototype.getFile();
+ followRedirect = prototype.getFollowRedirect();
+ requestTimeout = prototype.getRequestTimeout();
+ readTimeout = prototype.getReadTimeout();
+ rangeOffset = prototype.getRangeOffset();
+ charset = prototype.getCharset();
+ channelPoolPartitioning = prototype.getChannelPoolPartitioning();
+ nameResolver = prototype.getNameResolver();
+ }
+
+ @SuppressWarnings("unchecked")
+ private T asDerivedType() {
+ return (T) this;
+ }
+
+ public T setUrl(String url) {
+ return setUri(Uri.create(url));
+ }
+
+ public T setUri(Uri uri) {
+ this.uri = uri;
+ return asDerivedType();
+ }
+
+ public T setAddress(InetAddress address) {
+ this.address = address;
+ return asDerivedType();
+ }
+
+ public T setLocalAddress(InetAddress address) {
+ localAddress = address;
+ return asDerivedType();
+ }
+
+ public T setVirtualHost(String virtualHost) {
+ this.virtualHost = virtualHost;
+ return asDerivedType();
+ }
+
+ /**
+ * Remove all added headers
+ *
+ * @return {@code this}
+ */
+ public T clearHeaders() {
+ headers.clear();
+ return asDerivedType();
+ }
+
+ /**
+ * @param name header name
+ * @param value header value to set
+ * @return {@code this}
+ * @see #setHeader(CharSequence, Object)
+ */
+ public T setHeader(CharSequence name, String value) {
+ return setHeader(name, (Object) value);
+ }
+
+ /**
+ * Set uni-value header for the request
+ *
+ * @param name header name
+ * @param value header value to set
+ * @return {@code this}
+ */
+ public T setHeader(CharSequence name, Object value) {
+ headers.set(name, value);
+ return asDerivedType();
+ }
+
+ /**
+ * Set multi-values header for the request
+ *
+ * @param name header name
+ * @param values {@code Iterable} with multiple header values to set
+ * @return {@code this}
+ */
+ public T setHeader(CharSequence name, Iterable> values) {
+ headers.set(name, values);
+ return asDerivedType();
+ }
+
+ /**
+ * @param name header name
+ * @param value header value to add
+ * @return {@code this}
+ * @see #addHeader(CharSequence, Object)
+ */
+ public T addHeader(CharSequence name, String value) {
+ return addHeader(name, (Object) value);
+ }
+
+ /**
+ * Add a header value for the request. If a header with {@code name} was setup for this request already -
+ * call will add one more header value and convert it to multi-value header
+ *
+ * @param name header name
+ * @param value header value to add
+ * @return {@code this}
+ */
+ public T addHeader(CharSequence name, Object value) {
+ if (value == null) {
+ LOGGER.warn("Value was null, set to \"\"");
+ value = "";
+ }
+
+ headers.add(name, value);
+ return asDerivedType();
+ }
+
+ /**
+ * Add header values for the request. If a header with {@code name} was setup for this request already -
+ * call will add more header values and convert it to multi-value header
+ *
+ * @param name header name
+ * @param values {@code Iterable} with multiple header values to add
+ * @return {@code}
+ */
+ public T addHeader(CharSequence name, Iterable> values) {
+ headers.add(name, values);
+ return asDerivedType();
+ }
+
+ public T setHeaders(HttpHeaders headers) {
+ if (headers == null) {
+ this.headers.clear();
+ } else {
+ this.headers = headers;
+ }
+ return asDerivedType();
+ }
+
+ /**
+ * Set request headers using a map {@code headers} of pair (Header name, Header values)
+ * This method could be used to setup multi-valued headers
+ *
+ * @param headers map of header names as the map keys and header values {@link Iterable} as the map values
+ * @return {@code this}
+ */
+ public T setHeaders(Map extends CharSequence, ? extends Iterable>> headers) {
+ clearHeaders();
+ if (headers != null) {
+ headers.forEach((name, values) -> this.headers.add(name, values));
+ }
+ return asDerivedType();
+ }
+
+ /**
+ * Set single-value request headers using a map {@code headers} of pairs (Header name, Header value).
+ * To set headers with multiple values use {@link #setHeaders(Map)}
+ *
+ * @param headers map of header names as the map keys and header values as the map values
+ * @return {@code this}
+ */
+ public T setSingleHeaders(Map extends CharSequence, ?> headers) {
+ clearHeaders();
+ if (headers != null) {
+ headers.forEach((name, value) -> this.headers.add(name, value));
+ }
+ return asDerivedType();
+ }
+
+ private void lazyInitCookies() {
+ if (cookies == null) {
+ cookies = new ArrayList<>(3);
+ }
+ }
+
+ public T setCookies(Collection cookies) {
+ this.cookies = new ArrayList<>(cookies);
+ return asDerivedType();
+ }
+
+ public T addCookie(Cookie cookie) {
+ lazyInitCookies();
+ cookies.add(cookie);
+ return asDerivedType();
+ }
+
+ /**
+ * Add/replace a cookie based on its name
+ *
+ * @param cookie the new cookie
+ * @return this
+ */
+ public T addOrReplaceCookie(Cookie cookie) {
+ String cookieKey = cookie.name();
+ boolean replace = false;
+ int index = 0;
+ lazyInitCookies();
+ for (Cookie c : cookies) {
+ if (c.name().equals(cookieKey)) {
+ replace = true;
+ break;
+ }
+
+ index++;
+ }
+ if (replace) {
+ cookies.set(index, cookie);
+ } else {
+ cookies.add(cookie);
+ }
+ return asDerivedType();
+ }
+
+ public void resetCookies() {
+ if (cookies != null) {
+ cookies.clear();
+ }
+ }
+
+ public void resetQuery() {
+ queryParams = null;
+ if (uri != null) {
+ uri = uri.withNewQuery(null);
+ }
+ }
+
+ public void resetFormParams() {
+ formParams = null;
+ }
+
+ public void resetNonMultipartData() {
+ byteData = null;
+ compositeByteData = null;
+ byteBufferData = null;
+ stringData = null;
+ streamData = null;
+ bodyGenerator = null;
+ }
+
+ public void resetMultipartData() {
+ bodyParts = null;
+ }
+
+ public T setBody(File file) {
+ this.file = file;
+ return asDerivedType();
+ }
+
+ private void resetBody() {
+ resetFormParams();
+ resetNonMultipartData();
+ resetMultipartData();
+ }
+
+ public T setBody(byte[] data) {
+ resetBody();
+ byteData = data;
+ return asDerivedType();
+ }
+
+ public T setBody(List data) {
+ resetBody();
+ compositeByteData = data;
+ return asDerivedType();
+ }
+
+ public T setBody(String data) {
+ resetBody();
+ stringData = data;
+ return asDerivedType();
+ }
+
+ public T setBody(ByteBuffer data) {
+ resetBody();
+ byteBufferData = data;
+ return asDerivedType();
+ }
+
+ public T setBody(InputStream stream) {
+ resetBody();
+ streamData = stream;
+ return asDerivedType();
+ }
+
+ public T setBody(BodyGenerator bodyGenerator) {
+ this.bodyGenerator = bodyGenerator;
+ return asDerivedType();
+ }
+
+ public T addQueryParam(String name, String value) {
+ if (queryParams == null) {
+ queryParams = new ArrayList<>(1);
+ }
+ queryParams.add(new Param(name, value));
+ return asDerivedType();
+ }
+
+ public T addQueryParams(List params) {
+ if (queryParams == null) {
+ queryParams = params;
+ } else {
+ queryParams.addAll(params);
+ }
+ return asDerivedType();
+ }
+
+ public T setQueryParams(Map> map) {
+ return setQueryParams(Param.map2ParamList(map));
+ }
+
+ public T setQueryParams(List params) {
+ // reset existing query
+ if (uri != null && isNonEmpty(uri.getQuery())) {
+ uri = uri.withNewQuery(null);
+ }
+ queryParams = params;
+ return asDerivedType();
+ }
+
+ public T addFormParam(String name, String value) {
+ resetNonMultipartData();
+ resetMultipartData();
+ if (formParams == null) {
+ formParams = new ArrayList<>(1);
+ }
+ formParams.add(new Param(name, value));
+ return asDerivedType();
+ }
+
+ public T setFormParams(Map> map) {
+ return setFormParams(Param.map2ParamList(map));
+ }
+
+ public T setFormParams(List params) {
+ resetNonMultipartData();
+ resetMultipartData();
+ formParams = params;
+ return asDerivedType();
+ }
+
+ public T addBodyPart(Part bodyPart) {
+ resetFormParams();
+ resetNonMultipartData();
+ if (bodyParts == null) {
+ bodyParts = new ArrayList<>();
+ }
+ bodyParts.add(bodyPart);
+ return asDerivedType();
+ }
+
+ public T setBodyParts(List bodyParts) {
+ this.bodyParts = new ArrayList<>(bodyParts);
+ return asDerivedType();
+ }
+
+ public T setProxyServer(ProxyServer proxyServer) {
+ this.proxyServer = proxyServer;
+ return asDerivedType();
+ }
+
+ public T setProxyServer(ProxyServer.Builder proxyServerBuilder) {
+ proxyServer = proxyServerBuilder.build();
+ return asDerivedType();
+ }
+
+ public T setRealm(Realm.Builder realm) {
+ this.realm = realm.build();
+ return asDerivedType();
+ }
+
+ public T setRealm(Realm realm) {
+ this.realm = realm;
+ return asDerivedType();
+ }
+
+ public T setFollowRedirect(boolean followRedirect) {
+ this.followRedirect = followRedirect;
+ return asDerivedType();
+ }
+
+ public T setRequestTimeout(int requestTimeout) {
+ this.requestTimeout = requestTimeout;
+ return asDerivedType();
+ }
+
+ public T setReadTimeout(int readTimeout) {
+ this.readTimeout = readTimeout;
+ return asDerivedType();
+ }
+
+ public T setRangeOffset(long rangeOffset) {
+ this.rangeOffset = rangeOffset;
+ return asDerivedType();
+ }
+
+ public T setMethod(String method) {
+ this.method = method;
+ return asDerivedType();
+ }
+
+ public T setCharset(Charset charset) {
+ this.charset = charset;
+ return asDerivedType();
+ }
+
+ public T setChannelPoolPartitioning(ChannelPoolPartitioning channelPoolPartitioning) {
+ this.channelPoolPartitioning = channelPoolPartitioning;
+ return asDerivedType();
+ }
+
+ public T setNameResolver(NameResolver nameResolver) {
+ this.nameResolver = nameResolver;
+ return asDerivedType();
+ }
+
+ public T setSignatureCalculator(SignatureCalculator signatureCalculator) {
+ this.signatureCalculator = signatureCalculator;
+ return asDerivedType();
+ }
+
+ private RequestBuilderBase> executeSignatureCalculator() {
+ if (signatureCalculator == null) {
+ return this;
+ }
+
+ // build a first version of the request, without signatureCalculator in play
+ RequestBuilder rb = new RequestBuilder(method);
+ // make copy of mutable collections so we don't risk affecting
+ // original RequestBuilder
+ // call setFormParams first as it resets other fields
+ if (formParams != null) {
+ rb.setFormParams(formParams);
+ }
+ if (headers != null) {
+ rb.headers.add(headers);
+ }
+ if (cookies != null) {
+ rb.setCookies(cookies);
+ }
+ if (bodyParts != null) {
+ rb.setBodyParts(bodyParts);
+ }
+
+ // copy all other fields
+ // but rb.signatureCalculator, that's the whole point here
+ rb.uriEncoder = uriEncoder;
+ rb.queryParams = queryParams;
+ rb.uri = uri;
+ rb.address = address;
+ rb.localAddress = localAddress;
+ rb.byteData = byteData;
+ rb.compositeByteData = compositeByteData;
+ rb.stringData = stringData;
+ rb.byteBufferData = byteBufferData;
+ rb.streamData = streamData;
+ rb.bodyGenerator = bodyGenerator;
+ rb.virtualHost = virtualHost;
+ rb.proxyServer = proxyServer;
+ rb.realm = realm;
+ rb.file = file;
+ rb.followRedirect = followRedirect;
+ rb.requestTimeout = requestTimeout;
+ rb.rangeOffset = rangeOffset;
+ rb.charset = charset;
+ rb.channelPoolPartitioning = channelPoolPartitioning;
+ rb.nameResolver = nameResolver;
+ Request unsignedRequest = rb.build();
+ signatureCalculator.calculateAndAddSignature(unsignedRequest, rb);
+ return rb;
+ }
+
+ private void updateCharset() {
+ String contentTypeHeader = headers.get(CONTENT_TYPE);
+ Charset contentTypeCharset = extractContentTypeCharsetAttribute(contentTypeHeader);
+ charset = withDefault(contentTypeCharset, withDefault(charset, UTF_8));
+ if (contentTypeHeader != null && contentTypeHeader.regionMatches(true, 0, "text/", 0, 5) && contentTypeCharset == null) {
+ // add explicit charset to content-type header
+ headers.set(CONTENT_TYPE, contentTypeHeader + "; charset=" + charset.name());
+ }
+ }
+
+ private Uri computeUri() {
+
+ Uri tempUri = uri;
+ if (tempUri == null) {
+ LOGGER.debug("setUrl hasn't been invoked. Using {}", DEFAULT_REQUEST_URL);
+ tempUri = DEFAULT_REQUEST_URL;
+ } else {
+ Uri.validateSupportedScheme(tempUri);
+ }
+
+ return uriEncoder.encode(tempUri, queryParams);
+ }
+
+ public Request build() {
+ updateCharset();
+ RequestBuilderBase> rb = executeSignatureCalculator();
+ Uri finalUri = rb.computeUri();
+
+ // make copies of mutable internal collections
+ List cookiesCopy = rb.cookies == null ? Collections.emptyList() : new ArrayList<>(rb.cookies);
+ List formParamsCopy = rb.formParams == null ? Collections.emptyList() : new ArrayList<>(rb.formParams);
+ List bodyPartsCopy = rb.bodyParts == null ? Collections.emptyList() : new ArrayList<>(rb.bodyParts);
+
+ return new DefaultRequest(rb.method,
+ finalUri,
+ rb.address,
+ rb.localAddress,
+ rb.headers,
+ cookiesCopy,
+ rb.byteData,
+ rb.compositeByteData,
+ rb.stringData,
+ rb.byteBufferData,
+ rb.streamData,
+ rb.bodyGenerator,
+ formParamsCopy,
+ bodyPartsCopy,
+ rb.virtualHost,
+ rb.proxyServer,
+ rb.realm,
+ rb.file,
+ rb.followRedirect,
+ rb.requestTimeout,
+ rb.readTimeout,
+ rb.rangeOffset,
+ rb.charset,
+ rb.channelPoolPartitioning,
+ rb.nameResolver);
+ }
}
diff --git a/client/src/main/java/org/asynchttpclient/Response.java b/client/src/main/java/org/asynchttpclient/Response.java
index 99f033e995..78a257e9c9 100644
--- a/client/src/main/java/org/asynchttpclient/Response.java
+++ b/client/src/main/java/org/asynchttpclient/Response.java
@@ -32,184 +32,186 @@
* Represents the asynchronous HTTP response callback for an {@link AsyncCompletionHandler}
*/
public interface Response {
- /**
- * Returns the status code for the request.
- *
- * @return The status code
- */
- int getStatusCode();
-
- /**
- * Returns the status text for the request.
- *
- * @return The status text
- */
- String getStatusText();
-
- /**
- * Return the entire response body as a byte[].
- *
- * @return the entire response body as a byte[].
- */
- byte[] getResponseBodyAsBytes();
-
- /**
- * Return the entire response body as a ByteBuffer.
- *
- * @return the entire response body as a ByteBuffer.
- */
- ByteBuffer getResponseBodyAsByteBuffer();
-
- /**
- * Returns an input stream for the response body. Note that you should not try to get this more than once, and that you should not close the stream.
- *
- * @return The input stream
- */
- InputStream getResponseBodyAsStream();
-
- /**
- * Return the entire response body as a String.
- *
- * @param charset the charset to use when decoding the stream
- * @return the entire response body as a String.
- */
- String getResponseBody(Charset charset);
-
- /**
- * Return the entire response body as a String.
- *
- * @return the entire response body as a String.
- */
- String getResponseBody();
-
- /**
- * Return the request {@link Uri}. Note that if the request got redirected, the value of the {@link Uri} will be the last valid redirect url.
- *
- * @return the request {@link Uri}.
- */
- Uri getUri();
-
- /**
- * Return the content-type header value.
- *
- * @return the content-type header value.
- */
- String getContentType();
-
- /**
- * @param name the header name
- * @return the first response header value
- */
- String getHeader(CharSequence name);
-
- /**
- * Return a {@link List} of the response header value.
- *
- * @param name the header name
- * @return the response header value
- */
- List