From c1ad9a07bcf0bfa835ae3e865e43a8dec3cb16d8 Mon Sep 17 00:00:00 2001 From: Claus Ibsen Date: Sun, 8 Feb 2026 11:15:06 +0100 Subject: [PATCH] CAMEL-22972: camel-as2 - AS2ClientConnection leaks HTTP connections on error paths --- .../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 7cbf23c6b97df..e1392c58fb00f 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 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 HttpResponse send(ClassicHttpRequest request, HttpCoreContext httpContext 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; }