Skip to content

Commit 865d97b

Browse files
committed
Implement configurable HTTP timeouts with detailed error handling
This PR enhances the HTTP client implementation by: - Adding support for different types of timeout configuration via environment variables - Implementing specific error handling for three distinct timeout scenarios (socket, connect, connection request) - Adding proper error codes to identify the exact type of timeout that occurred - Improving diagnostics through detailed error reporting These changes allow applications to better understand connection failures and configure timeout behavior according to their specific requirements. Issue: 207597
1 parent a0dcbb5 commit 865d97b

2 files changed

Lines changed: 53 additions & 11 deletions

File tree

common/src/main/java/com/genexus/internet/GXHttpClient.java

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -719,7 +719,11 @@ private byte[] addToArray(byte[] in, byte[] val)
719719
}
720720

721721
protected void setExceptionsCatch(Exception e) {
722-
setErrCode(ERROR_IO);
722+
setExceptionsCatch(ERROR_IO, e);
723+
}
724+
725+
protected void setExceptionsCatch(int ErrorType, Exception e) {
726+
setErrCode(ErrorType);
723727
setErrDescription(e.getMessage());
724728
}
725729

java/src/main/java/com/genexus/internet/HttpClientJavaLib.java

Lines changed: 48 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,7 @@
11
package com.genexus.internet;
22

33
import java.io.*;
4-
import java.net.InetAddress;
5-
import java.net.URISyntaxException;
6-
import java.net.UnknownHostException;
4+
import java.net.*;
75
import java.nio.charset.Charset;
86
import java.nio.charset.StandardCharsets;
97
import java.security.KeyManagementException;
@@ -12,12 +10,14 @@
1210
import java.security.UnrecoverableKeyException;
1311
import java.security.cert.CertificateException;
1412
import java.util.*;
15-
import java.net.URI;
1613
import javax.net.ssl.SSLContext;
1714

1815
import org.apache.http.*;
1916
import org.apache.http.HttpResponse;
17+
import org.apache.http.client.CookieStore;
2018
import org.apache.http.client.config.CookieSpecs;
19+
import org.apache.http.conn.ConnectTimeoutException;
20+
import org.apache.http.conn.ConnectionPoolTimeoutException;
2121
import org.apache.http.conn.DnsResolver;
2222
import org.apache.http.conn.routing.HttpRoute;
2323
import org.apache.http.conn.ssl.NoopHostnameVerifier;
@@ -65,6 +65,9 @@
6565
import com.genexus.specific.java.*;
6666

6767
public class HttpClientJavaLib extends GXHttpClient {
68+
private static final int ERROR_SOCKET_TIMEOUT = 1001;
69+
private static final int ERROR_CONNECT_TIMEOUT = 1002;
70+
private static final int ERROR_CONNECTION_REQUEST_TIMEOUT = 1003;
6871

6972
private static final DnsResolver FIRST_IP_DNS_RESOLVER = host -> {
7073
InetAddress[] allIps = SystemDefaultDnsResolver.INSTANCE.resolve(host);
@@ -400,11 +403,35 @@ public void execute(String method, String url) {
400403

401404
int msTimeout = getTimeout() * 1000;
402405

406+
int connectTimeout = msTimeout;
407+
int connectionRequestTimeout = msTimeout;
408+
int socketTimeout = msTimeout;
409+
410+
try {
411+
String connectTimeoutEnv = System.getenv("HTTP_CONNECT_TIMEOUT_MS");
412+
if (connectTimeoutEnv != null && !connectTimeoutEnv.trim().isEmpty()) {
413+
connectTimeout = Integer.parseInt(connectTimeoutEnv);
414+
}
415+
416+
String connectionRequestTimeoutEnv = System.getenv("HTTP_CONNECTION_REQUEST_TIMEOUT_MS");
417+
if (connectionRequestTimeoutEnv != null && !connectionRequestTimeoutEnv.trim().isEmpty()) {
418+
connectionRequestTimeout = Integer.parseInt(connectionRequestTimeoutEnv);
419+
}
420+
421+
String socketTimeoutEnv = System.getenv("HTTP_SOCKET_TIMEOUT_MS");
422+
if (socketTimeoutEnv != null && !socketTimeoutEnv.trim().isEmpty()) {
423+
socketTimeout = Integer.parseInt(socketTimeoutEnv);
424+
}
425+
}
426+
catch (NumberFormatException e) {
427+
logger.error("Error parsing timeout environment variables", e);
428+
}
429+
403430
RequestConfig.Builder requestConfigBuilder = RequestConfig.custom()
404431
.setCookieSpec(CookieSpecs.STANDARD)
405-
.setSocketTimeout(msTimeout)
406-
.setConnectionRequestTimeout(msTimeout)
407-
.setConnectTimeout(msTimeout);
432+
.setSocketTimeout(socketTimeout)
433+
.setConnectionRequestTimeout(connectionRequestTimeout)
434+
.setConnectTimeout(connectTimeout);
408435

409436
this.httpClientBuilder.setRoutePlanner(null);
410437

@@ -635,10 +662,14 @@ public void execute(String method, String url) {
635662
isChunkedResponse = response.getFirstHeader("Transfer-Encoding").getValue().equalsIgnoreCase("chunked");
636663
}
637664
}
665+
} catch (ConnectionPoolTimeoutException e) {
666+
setExecuteExceptionsCatch(ERROR_CONNECTION_REQUEST_TIMEOUT, e);
667+
} catch (ConnectTimeoutException e) {
668+
setExecuteExceptionsCatch(ERROR_CONNECT_TIMEOUT, e);
669+
} catch (SocketTimeoutException e) {
670+
setExecuteExceptionsCatch(ERROR_SOCKET_TIMEOUT, e);
638671
} catch (IOException e) {
639-
setExceptionsCatch(e);
640-
this.statusCode = 0;
641-
this.reasonLine = "";
672+
setExecuteExceptionsCatch(ERROR_IO, e);
642673
}
643674
finally {
644675
if (Application.isJMXEnabled()){
@@ -654,6 +685,13 @@ public void execute(String method, String url) {
654685
resetStateAdapted();
655686
}
656687
}
688+
689+
private void setExecuteExceptionsCatch(int ErrorType, Exception e) {
690+
setExceptionsCatch(ErrorType, e);
691+
this.statusCode = 0;
692+
this.reasonLine = "";
693+
logger.error("Execute error: " + e.getMessage(), e);
694+
}
657695

658696
private synchronized void displayHTTPConnections(){
659697
Iterator<HttpRoute> iterator = storedRoutes.iterator();

0 commit comments

Comments
 (0)