You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@cxf.apache.org by re...@apache.org on 2023/08/11 03:17:04 UTC

[cxf] 01/02: [CXF-8885] Eliminate hidden reference to `HttpClient` in `ProxySelector` (#1377)

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

reta pushed a commit to branch 3.6.x-fixes
in repository https://gitbox.apache.org/repos/asf/cxf.git

commit 4410892ad37e906863e7a996f543c5b503dcc666
Author: Leo Wörteler <le...@woerteler.de>
AuthorDate: Fri Aug 11 01:40:53 2023 +0200

    [CXF-8885] Eliminate hidden reference to `HttpClient` in `ProxySelector` (#1377)
    
    The SelectorManager thread of the WebClient would normally shut down
    after the HttpClient's outer shell, the `HttpClientFacade` has been
    garbage collected. Unfortunately the `ProxySelector` instance created in
    `HttpClientHTTPConduit` is a non-static (anonymous) subclass, so it
    retains a hard reference to the enclosing `HttpClientHTTPConduit`
    instance and therefore also its `client` field. This gives the
    SelectorManager thread a hard reference to the `HttpClientFacade`, so
    the facade can never be garbage collected and the thread never shuts
    down. Making the class static solves the problem.
    
    (cherry picked from commit e204d71ce0a2d4af2ed2299c34c49c9ac094dfe4)
---
 .../cxf/transport/http/HttpClientHTTPConduit.java  | 40 ++++++++++++++++------
 1 file changed, 29 insertions(+), 11 deletions(-)

diff --git a/rt/transports/http/src/main/java/org/apache/cxf/transport/http/HttpClientHTTPConduit.java b/rt/transports/http/src/main/java/org/apache/cxf/transport/http/HttpClientHTTPConduit.java
index 0451e9af68..44c5785ca8 100644
--- a/rt/transports/http/src/main/java/org/apache/cxf/transport/http/HttpClientHTTPConduit.java
+++ b/rt/transports/http/src/main/java/org/apache/cxf/transport/http/HttpClientHTTPConduit.java
@@ -206,17 +206,7 @@ public class HttpClientHTTPConduit extends URLConnectionHTTPConduit {
         HttpClient cl = client;
         if (cl == null) {
             int ctimeout = determineConnectionTimeout(message, csPolicy);        
-            ProxySelector ps = new ProxySelector() {
-                public List<Proxy> select(URI uri) {
-                    Proxy proxy = proxyFactory.createProxy(csPolicy, uri);
-                    if (proxy !=  null) {
-                        return Arrays.asList(proxy);
-                    }
-                    return ProxySelector.getDefault().select(uri);
-                }
-                public void connectFailed(URI uri, SocketAddress sa, IOException ioe) {
-                }
-            };
+            ProxySelector ps = new ProxyFactoryProxySelector(proxyFactory, csPolicy);
             
             HttpClient.Builder cb = HttpClient.newBuilder()
                 .proxy(ps)
@@ -309,6 +299,34 @@ public class HttpClientHTTPConduit extends URLConnectionHTTPConduit {
     }
 
 
+    /**
+     * This class <i>must</i> be static so it doesn't capture a reference to {@code HttpClientHTTPConduit.this} and
+     * through that to {@link HttpClientHTTPConduit#client}. Otherwise the client can never be garbage collected, which
+     * means that the companion "SelectorManager" thread keeps running indefinitely (see CXF-8885).
+     */
+    private static final class ProxyFactoryProxySelector extends ProxySelector {
+        private final ProxyFactory proxyFactory;
+        private final HTTPClientPolicy csPolicy;
+
+        ProxyFactoryProxySelector(ProxyFactory proxyFactory, HTTPClientPolicy csPolicy) {
+            this.proxyFactory = proxyFactory;
+            this.csPolicy = csPolicy;
+        }
+
+        @Override
+        public List<Proxy> select(URI uri) {
+            Proxy proxy = proxyFactory.createProxy(csPolicy, uri);
+            if (proxy !=  null) {
+                return Arrays.asList(proxy);
+            }
+            return ProxySelector.getDefault().select(uri);
+        }
+
+        @Override
+        public void connectFailed(URI uri, SocketAddress sa, IOException ioe) {
+        }
+    }
+
     class HttpClientWrappedOutputStream extends WrappedOutputStream {
         List<Flow.Subscriber<? super ByteBuffer>> subscribers = new LinkedList<>();
         CompletableFuture<HttpResponse<InputStream>> future;