You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@camel.apache.org by da...@apache.org on 2026/02/08 11:34:53 UTC

(camel) branch main updated: CAMEL-22972: camel-as2 - AS2ClientConnection leaks HTTP connections on error paths (#21307)

This is an automated email from the ASF dual-hosted git repository.

davsclaus pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/camel.git


The following commit(s) were added to refs/heads/main by this push:
     new c50b03cb2e7e CAMEL-22972: camel-as2 - AS2ClientConnection leaks HTTP connections on error paths (#21307)
c50b03cb2e7e is described below

commit c50b03cb2e7ef9e1c5777f5900870d532c296977
Author: Claus Ibsen <cl...@gmail.com>
AuthorDate: Sun Feb 8 12:34:46 2026 +0100

    CAMEL-22972: camel-as2 - AS2ClientConnection leaks HTTP connections on error paths (#21307)
---
 .../component/as2/api/AS2ClientConnection.java     | 61 ++++++++++++++--------
 1 file changed, 40 insertions(+), 21 deletions(-)

diff --git a/components/camel-as2/camel-as2-api/src/main/java/org/apache/camel/component/as2/api/AS2ClientConnection.java b/components/camel-as2/camel-as2-api/src/main/java/org/apache/camel/component/as2/api/AS2ClientConnection.java
index 7cbf23c6b97d..e1392c58fb00 100644
--- a/components/camel-as2/camel-as2-api/src/main/java/org/apache/camel/component/as2/api/AS2ClientConnection.java
+++ b/components/camel-as2/camel-as2-api/src/main/java/org/apache/camel/component/as2/api/AS2ClientConnection.java
@@ -30,6 +30,7 @@ import javax.net.ssl.SSLSocketFactory;
 import org.apache.camel.component.as2.api.io.AS2BHttpClientConnection;
 import org.apache.camel.component.as2.api.protocol.RequestAS2;
 import org.apache.camel.component.as2.api.protocol.RequestMDN;
+import org.apache.camel.util.IOHelper;
 import org.apache.camel.util.ObjectHelper;
 import org.apache.hc.client5.http.ConnectionKeepAliveStrategy;
 import org.apache.hc.client5.http.HttpRoute;
@@ -187,31 +188,49 @@ public class AS2ClientConnection {
             throws HttpException, IOException, InterruptedException, ExecutionException, TimeoutException {
 
         HttpRoute route = new HttpRoute(targetHost);
-
         request.setAuthority(new URIAuthority(targetHost));
-
         LeaseRequest leaseRequest = connectionPoolManager.lease(UUID.randomUUID().toString(), route, null);
-        ConnectionEndpoint endpoint = leaseRequest.get(Timeout.ofSeconds(RETRIEVE_CONNECTION_TIMEOUT_SECONDS));
-        if (!endpoint.isConnected()) {
-            connectionPoolManager.connect(endpoint, TimeValue.ofMilliseconds(connectionTimeoutMilliseconds), httpContext);
-        }
 
-        // Execute Request
-        HttpRequestExecutor httpExecutor = new HttpRequestExecutor() {
-            @Override
-            public ClassicHttpResponse execute(ClassicHttpRequest request, HttpClientConnection conn, HttpContext context)
-                    throws IOException, HttpException {
-                super.preProcess(request, httpProcessor, context);
-                ClassicHttpResponse response = super.execute(request, conn, context);
-                super.postProcess(response, httpProcessor, context);
-                return response;
+        ConnectionEndpoint endpoint = null;
+        HttpResponse response = null;
+        try {
+            endpoint = leaseRequest.get(Timeout.ofSeconds(RETRIEVE_CONNECTION_TIMEOUT_SECONDS));
+            if (!endpoint.isConnected()) {
+                connectionPoolManager.connect(endpoint, TimeValue.ofMilliseconds(connectionTimeoutMilliseconds), httpContext);
             }
-        };
-
-        HttpResponse response = endpoint.execute(UUID.randomUUID().toString(), request, httpExecutor, httpContext);
-        connectionPoolManager.release(endpoint, null,
-                connectionKeepAliveStrategy.getKeepAliveDuration(response, httpContext));
-
+            // Execute Request
+            HttpRequestExecutor httpExecutor = new HttpRequestExecutor() {
+                @Override
+                public ClassicHttpResponse execute(ClassicHttpRequest request, HttpClientConnection conn, HttpContext context)
+                        throws IOException, HttpException {
+                    super.preProcess(request, httpProcessor, context);
+                    ClassicHttpResponse response = super.execute(request, conn, context);
+                    super.postProcess(response, httpProcessor, context);
+                    return response;
+                }
+            };
+            response = endpoint.execute(UUID.randomUUID().toString(), request, httpExecutor, httpContext);
+        } finally {
+            if (endpoint != null) {
+                TimeValue keepAlive = null;
+                if (response != null) {
+                    // Normal happy path: release with computed keep-alive.
+                    keepAlive = connectionKeepAliveStrategy.getKeepAliveDuration(response, httpContext);
+                }
+                if (keepAlive == null) {
+                    // If we didn't get a response, something failed mid-flight:
+                    // do NOT keep this connection around. Close it and release with zero keep-alive.
+                    keepAlive = TimeValue.ZERO_MILLISECONDS;
+                }
+                try {
+                    connectionPoolManager.release(endpoint, null, keepAlive);
+                } catch (Exception ignored) {
+                    // ignore
+                } finally {
+                    IOHelper.close(endpoint);
+                }
+            }
+        }
         return response;
     }