From f3bb7c3d6463dee7d850c50bb6f89273277678b7 Mon Sep 17 00:00:00 2001 From: Sam Harrison Date: Thu, 3 Feb 2022 13:23:37 -0600 Subject: [PATCH] [DI-1920] fix: set socket config with blocking operation timeout Sets a default socket config with timeout for all connections. Note that this must be applied to the connection manger and not the client builder. The client builder default socket config is only used when not given a connection manager. --- src/main/java/com/twilio/http/HttpClient.java | 38 ++++++----- .../com/twilio/http/NetworkHttpClient.java | 52 ++++++++------- .../com/twilio/http/ValidationClient.java | 63 +++++++++++++------ 3 files changed, 93 insertions(+), 60 deletions(-) diff --git a/src/main/java/com/twilio/http/HttpClient.java b/src/main/java/com/twilio/http/HttpClient.java index 92fa2891c0..71e595ff34 100644 --- a/src/main/java/com/twilio/http/HttpClient.java +++ b/src/main/java/com/twilio/http/HttpClient.java @@ -1,24 +1,44 @@ package com.twilio.http; +import lombok.Getter; +import lombok.Setter; import org.apache.http.client.RedirectStrategy; +import org.apache.http.client.config.RequestConfig; +import org.apache.http.config.SocketConfig; import org.apache.http.impl.client.DefaultRedirectStrategy; public abstract class HttpClient { + public static final int CONNECTION_TIMEOUT = 10000; + public static final int SOCKET_TIMEOUT = 30500; + public static final RequestConfig DEFAULT_REQUEST_CONFIG = RequestConfig + .custom() + .setConnectTimeout(CONNECTION_TIMEOUT) + .setSocketTimeout(SOCKET_TIMEOUT) + .build(); + public static final SocketConfig DEFAULT_SOCKET_CONFIG = SocketConfig + .custom() + .setSoTimeout(SOCKET_TIMEOUT) + .build(); + public static final int ANY_500 = -500; public static final int ANY_400 = -400; public static final int ANY_300 = -300; public static final int ANY_200 = -200; public static final int ANY_100 = -100; - public static final int[] RETRY_CODES = new int[]{ANY_500}; + public static final int[] RETRY_CODES = new int[] {ANY_500}; public static final int RETRIES = 3; public static final long DELAY_MILLIS = 100L; // Default redirect strategy to not auto-redirect for any methods (empty string array). + @Getter + @Setter private RedirectStrategy redirectStrategy = new DefaultRedirectStrategy(new String[0]); + @Getter private Response lastResponse; + @Getter private Request lastRequest; /** @@ -66,14 +86,6 @@ public Response reliableRequest(final Request request, final int[] retryCodes, i return response; } - public Response getLastResponse() { - return lastResponse; - } - - public Request getLastRequest() { - return lastRequest; - } - protected boolean shouldRetry(final Response response, final int[] retryCodes) { if (response == null) { return true; @@ -119,13 +131,5 @@ protected boolean shouldRetry(final Response response, final int[] retryCodes) { return false; } - public RedirectStrategy getRedirectStrategy() { - return redirectStrategy; - } - - public void setRedirectStrategy(final RedirectStrategy redirectStrategy) { - this.redirectStrategy = redirectStrategy; - } - public abstract Response makeRequest(final Request request); } diff --git a/src/main/java/com/twilio/http/NetworkHttpClient.java b/src/main/java/com/twilio/http/NetworkHttpClient.java index c7483476bd..ccee98d3ea 100644 --- a/src/main/java/com/twilio/http/NetworkHttpClient.java +++ b/src/main/java/com/twilio/http/NetworkHttpClient.java @@ -2,48 +2,54 @@ import com.twilio.Twilio; import com.twilio.exception.ApiException; + +import java.io.IOException; +import java.nio.charset.StandardCharsets; +import java.util.Arrays; +import java.util.Collection; +import java.util.List; +import java.util.Map; + import org.apache.http.HttpEntity; import org.apache.http.HttpHeaders; import org.apache.http.HttpResponse; import org.apache.http.HttpVersion; -import org.apache.http.client.utils.HttpClientUtils; -import org.apache.http.entity.BufferedHttpEntity; import org.apache.http.client.config.RequestConfig; import org.apache.http.client.methods.RequestBuilder; +import org.apache.http.client.utils.HttpClientUtils; +import org.apache.http.config.SocketConfig; +import org.apache.http.entity.BufferedHttpEntity; import org.apache.http.impl.client.HttpClientBuilder; import org.apache.http.impl.conn.PoolingHttpClientConnectionManager; import org.apache.http.message.BasicHeader; -import java.io.IOException; -import java.nio.charset.StandardCharsets; -import java.util.Arrays; -import java.util.Collection; -import java.util.List; -import java.util.Map; - public class NetworkHttpClient extends HttpClient { - private static final int CONNECTION_TIMEOUT = 10000; - private static final int SOCKET_TIMEOUT = 30500; - private final org.apache.http.client.HttpClient client; /** * Create a new HTTP Client. */ public NetworkHttpClient() { - this(RequestConfig.custom() - .setConnectTimeout(CONNECTION_TIMEOUT) - .setSocketTimeout(SOCKET_TIMEOUT) - .build() - ); + this(DEFAULT_REQUEST_CONFIG); } /** * Create a new HTTP Client with a custom request config. - * @param config a RequestConfig. + * + * @param requestConfig a RequestConfig. */ - public NetworkHttpClient(RequestConfig config) { + public NetworkHttpClient(final RequestConfig requestConfig) { + this(requestConfig, DEFAULT_SOCKET_CONFIG); + } + + /** + * Create a new HTTP Client with a custom request and socket config. + * + * @param requestConfig a RequestConfig. + * @param socketConfig a SocketConfig. + */ + public NetworkHttpClient(final RequestConfig requestConfig, final SocketConfig socketConfig) { Collection headers = Arrays.asList( new BasicHeader("X-Twilio-Client", "java-" + Twilio.VERSION), new BasicHeader(HttpHeaders.USER_AGENT, "twilio-java/" + Twilio.VERSION + " (" + Twilio.JAVA_VERSION + ")"), @@ -61,12 +67,13 @@ public NetworkHttpClient(RequestConfig config) { } PoolingHttpClientConnectionManager connectionManager = new PoolingHttpClientConnectionManager(); - connectionManager.setDefaultMaxPerRoute(10); - connectionManager.setMaxTotal(10*2); + connectionManager.setDefaultSocketConfig(socketConfig); + connectionManager.setDefaultMaxPerRoute(10); + connectionManager.setMaxTotal(10 * 2); client = clientBuilder .setConnectionManager(connectionManager) - .setDefaultRequestConfig(config) + .setDefaultRequestConfig(requestConfig) .setDefaultHeaders(headers) .setRedirectStrategy(this.getRedirectStrategy()) .build(); @@ -145,6 +152,5 @@ public Response makeRequest(final Request request) { HttpClientUtils.closeQuietly(response); } - } } diff --git a/src/main/java/com/twilio/http/ValidationClient.java b/src/main/java/com/twilio/http/ValidationClient.java index da3724cf36..64b5d90650 100644 --- a/src/main/java/com/twilio/http/ValidationClient.java +++ b/src/main/java/com/twilio/http/ValidationClient.java @@ -7,6 +7,7 @@ import org.apache.http.HttpVersion; import org.apache.http.client.config.RequestConfig; import org.apache.http.client.methods.RequestBuilder; +import org.apache.http.config.SocketConfig; import org.apache.http.impl.client.HttpClientBuilder; import org.apache.http.impl.conn.PoolingHttpClientConnectionManager; import org.apache.http.message.BasicHeader; @@ -21,37 +22,56 @@ public class ValidationClient extends HttpClient { - private static final int CONNECTION_TIMEOUT = 10000; - private static final int SOCKET_TIMEOUT = 30500; - private static final RequestConfig DEFAULT_REQUEST_CONFIG = RequestConfig.custom() - .setConnectTimeout(CONNECTION_TIMEOUT) - .setSocketTimeout(SOCKET_TIMEOUT) - .build();; - private final org.apache.http.client.HttpClient client; /** * Create a new ValidationClient. * - * @param accountSid Twilio Account SID - * @param credentialSid Twilio Credential SID - * @param signingKey Twilio Signing key - * @param privateKey Private Key + * @param accountSid Twilio Account SID + * @param credentialSid Twilio Credential SID + * @param signingKey Twilio Signing key + * @param privateKey Private Key */ - public ValidationClient(String accountSid, String credentialSid, String signingKey, PrivateKey privateKey) { + public ValidationClient(final String accountSid, + final String credentialSid, + final String signingKey, + final PrivateKey privateKey) { this(accountSid, credentialSid, signingKey, privateKey, DEFAULT_REQUEST_CONFIG); } /** * Create a new ValidationClient. * - * @param accountSid Twilio Account SID - * @param credentialSid Twilio Credential SID - * @param signingKey Twilio Signing key - * @param privateKey Private Key - * @param config HTTP Request Config + * @param accountSid Twilio Account SID + * @param credentialSid Twilio Credential SID + * @param signingKey Twilio Signing key + * @param privateKey Private Key + * @param requestConfig HTTP Request Config + */ + public ValidationClient(final String accountSid, + final String credentialSid, + final String signingKey, + final PrivateKey privateKey, + final RequestConfig requestConfig) { + this(accountSid, credentialSid, signingKey, privateKey, requestConfig, DEFAULT_SOCKET_CONFIG); + } + + /** + * Create a new ValidationClient. + * + * @param accountSid Twilio Account SID + * @param credentialSid Twilio Credential SID + * @param signingKey Twilio Signing key + * @param privateKey Private Key + * @param requestConfig HTTP Request Config + * @param socketConfig HTTP Socket Config */ - public ValidationClient(String accountSid, String credentialSid, String signingKey, PrivateKey privateKey, RequestConfig config) { + public ValidationClient(final String accountSid, + final String credentialSid, + final String signingKey, + final PrivateKey privateKey, + final RequestConfig requestConfig, + final SocketConfig socketConfig) { Collection headers = Arrays.asList( new BasicHeader("X-Twilio-Client", "java-" + Twilio.VERSION), new BasicHeader(HttpHeaders.USER_AGENT, "twilio-java/" + Twilio.VERSION + " (" + Twilio.JAVA_VERSION + ")"), @@ -59,9 +79,12 @@ public ValidationClient(String accountSid, String credentialSid, String signingK new BasicHeader(HttpHeaders.ACCEPT_ENCODING, "utf-8") ); + final PoolingHttpClientConnectionManager connectionManager = new PoolingHttpClientConnectionManager(); + connectionManager.setDefaultSocketConfig(socketConfig); + client = HttpClientBuilder.create() - .setConnectionManager(new PoolingHttpClientConnectionManager()) - .setDefaultRequestConfig(config) + .setConnectionManager(connectionManager) + .setDefaultRequestConfig(requestConfig) .setDefaultHeaders(headers) .setMaxConnPerRoute(10) .addInterceptorLast(new ValidationInterceptor(accountSid, credentialSid, signingKey, privateKey))