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

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


The following commit(s) were added to refs/heads/main by this push:
     new 2e1fd49f0dc [CXF-9218]Respect configured ProxySelector instead of 
hard-wiring system proxy properties (#3154)
2e1fd49f0dc is described below

commit 2e1fd49f0dc51f6f5aa9f04a06696debe3d7dc16
Author: Freeman(Yue) Fang <[email protected]>
AuthorDate: Fri May 29 12:01:31 2026 -0400

    [CXF-9218]Respect configured ProxySelector instead of hard-wiring system 
proxy properties (#3154)
---
 .../apache/cxf/transport/http/ProxyFactory.java    | 101 +++----------
 .../cxf/transport/http/ProxyFactoryTest.java       | 156 +++++++++++++++++++++
 2 files changed, 175 insertions(+), 82 deletions(-)

diff --git 
a/rt/transports/http/src/main/java/org/apache/cxf/transport/http/ProxyFactory.java
 
b/rt/transports/http/src/main/java/org/apache/cxf/transport/http/ProxyFactory.java
index 058672b5eca..30deabdb131 100644
--- 
a/rt/transports/http/src/main/java/org/apache/cxf/transport/http/ProxyFactory.java
+++ 
b/rt/transports/http/src/main/java/org/apache/cxf/transport/http/ProxyFactory.java
@@ -20,75 +20,15 @@ package org.apache.cxf.transport.http;
 
 import java.net.InetSocketAddress;
 import java.net.Proxy;
+import java.net.ProxySelector;
 import java.net.URI;
+import java.util.List;
 import java.util.regex.Pattern;
 
 import org.apache.cxf.common.util.StringUtils;
-import org.apache.cxf.common.util.SystemPropertyAction;
 import org.apache.cxf.transports.http.configuration.HTTPClientPolicy;
-import org.apache.cxf.transports.http.configuration.ProxyServerType;
 
 public class ProxyFactory {
-    /**
-     * JVM/System property name holding the hostname of the http proxy.
-     */
-    private static final String HTTP_PROXY_HOST = "http.proxyHost";
-
-    /**
-     * JVM/System property name holding the port of the http proxy.
-     */
-    private static final String HTTP_PROXY_PORT = "http.proxyPort";
-
-    /**
-     * JVM/System property name holding the list of hosts/patterns that
-     * should not use the proxy configuration.
-     */
-    private static final String HTTP_NON_PROXY_HOSTS = "http.nonProxyHosts";
-
-    /**
-     * This field holds ONLY the static System proxy configuration:
-     * + http.proxyHost
-     * + http.proxyPort (default 8080)
-     * + http.nonProxyHosts (default null)
-     * It is initialized at the instance creation (and may be null
-     * if there is no appropriate System properties)
-     */
-    private HTTPClientPolicy systemProxyConfiguration;
-
-    public ProxyFactory() {
-        this.systemProxyConfiguration = createSystemProxyConfiguration();
-    }
-
-    private static HTTPClientPolicy createSystemProxyConfiguration() {
-        // Retrieve system properties (if any)
-        HTTPClientPolicy systemProxyConfiguration = null;
-        String proxyHost = 
SystemPropertyAction.getPropertyOrNull(HTTP_PROXY_HOST);
-        if (StringUtils.isEmpty(proxyHost)) {
-            proxyHost = null;
-        }
-        if (proxyHost != null) {
-            // System is configured with a proxy, use it
-
-            systemProxyConfiguration = new HTTPClientPolicy();
-            systemProxyConfiguration.setProxyServer(proxyHost);
-            systemProxyConfiguration.setProxyServerType(ProxyServerType.HTTP);
-
-            // 8080 is the default proxy port value as per some documentation
-            String proxyPort = 
SystemPropertyAction.getProperty(HTTP_PROXY_PORT, "8080");
-            if (StringUtils.isEmpty(proxyPort)) {
-                proxyPort = "8080";
-            }
-
-            
systemProxyConfiguration.setProxyServerPort(Integer.parseInt(proxyPort));
-
-            // Load non proxy hosts
-            String nonProxyHosts = 
SystemPropertyAction.getPropertyOrNull(HTTP_NON_PROXY_HOSTS);
-            if (!StringUtils.isEmpty(nonProxyHosts)) {
-                systemProxyConfiguration.setNonProxyHosts(nonProxyHosts);
-            }
-        }
-        return systemProxyConfiguration;
-    }
 
     /**
      * This method returns the Proxy server should it be set on the
@@ -97,29 +37,30 @@ public class ProxyFactory {
      * @return The proxy server or null, if not set.
      */
     public Proxy createProxy(HTTPClientPolicy policy, URI currentUrl) {
-        if (policy != null) {
-            // Maybe the user has provided some proxy information
-            if (policy.isSetProxyServer()
+        if (policy != null && policy.isSetProxyServer()
                 && !StringUtils.isEmpty(policy.getProxyServer())) {
-                return getProxy(policy, currentUrl.getHost());
-            }
-            // There is a policy but no Proxy configuration,
-            // fallback on the system proxy configuration
-            return getSystemProxy(currentUrl.getHost());
+            return getProxy(policy, currentUrl.getHost());
         }
-        // Use system proxy configuration
-        return getSystemProxy(currentUrl.getHost());
+        return getSystemProxy(currentUrl);
     }
 
     /**
-     * Get the system proxy (if any) for the given URL's host.
+     * Delegate to the configured {@link ProxySelector} so that custom
+     * implementations (e.g. wrappers around {@code DefaultProxySelector})
+     * are honoured rather than bypassed.
      */
-    private Proxy getSystemProxy(String hostname) {
-        if (systemProxyConfiguration != null) {
-            return getProxy(systemProxyConfiguration, hostname);
+    private Proxy getSystemProxy(URI uri) {
+        ProxySelector selector = ProxySelector.getDefault();
+        if (selector == null) {
+            return null;
+        }
+        List<Proxy> proxies = selector.select(uri);
+        if (proxies != null && !proxies.isEmpty()) {
+            Proxy proxy = proxies.get(0);
+            if (proxy != Proxy.NO_PROXY) {
+                return proxy;
+            }
         }
-
-        // No proxy configured
         return null;
     }
 
@@ -128,15 +69,11 @@ public class ProxyFactory {
      */
     private Proxy getProxy(final HTTPClientPolicy policy, final String 
hostname) {
         if (policy.isSetNonProxyHosts()) {
-
-            // Try to match the URL hostname with the exclusion pattern
             Pattern pattern = PatternBuilder.build(policy.getNonProxyHosts());
             if (pattern.matcher(hostname).matches()) {
-                // Excluded hostname -> no proxy
                 return Proxy.NO_PROXY;
             }
         }
-        // Either nonProxyHosts is not set or the pattern did not match
         return createProxy(policy);
     }
 
diff --git 
a/rt/transports/http/src/test/java/org/apache/cxf/transport/http/ProxyFactoryTest.java
 
b/rt/transports/http/src/test/java/org/apache/cxf/transport/http/ProxyFactoryTest.java
new file mode 100644
index 00000000000..d5fed49b736
--- /dev/null
+++ 
b/rt/transports/http/src/test/java/org/apache/cxf/transport/http/ProxyFactoryTest.java
@@ -0,0 +1,156 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.cxf.transport.http;
+
+import java.io.IOException;
+import java.net.InetSocketAddress;
+import java.net.Proxy;
+import java.net.ProxySelector;
+import java.net.SocketAddress;
+import java.net.URI;
+import java.util.Collections;
+import java.util.List;
+
+import org.apache.cxf.transports.http.configuration.HTTPClientPolicy;
+import org.apache.cxf.transports.http.configuration.ProxyServerType;
+
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNull;
+
+public class ProxyFactoryTest {
+
+    private ProxySelector originalSelector;
+    private ProxyFactory factory;
+
+    @Before
+    public void setUp() {
+        originalSelector = ProxySelector.getDefault();
+        factory = new ProxyFactory();
+    }
+
+    @After
+    public void tearDown() {
+        ProxySelector.setDefault(originalSelector);
+    }
+
+    @Test
+    public void explicitPolicyProxyIsUsed() throws Exception {
+        HTTPClientPolicy policy = new HTTPClientPolicy();
+        policy.setProxyServer("proxy.example.com");
+        policy.setProxyServerPort(8080);
+        policy.setProxyServerType(ProxyServerType.HTTP);
+
+        Proxy proxy = factory.createProxy(policy, new 
URI("http://target.example.com/service";));
+
+        assertEquals(Proxy.Type.HTTP, proxy.type());
+        assertEquals(new InetSocketAddress("proxy.example.com", 8080), 
proxy.address());
+    }
+
+    @Test
+    public void nonProxyHostsExcludesMatchingHost() throws Exception {
+        HTTPClientPolicy policy = new HTTPClientPolicy();
+        policy.setProxyServer("proxy.example.com");
+        policy.setProxyServerPort(8080);
+        policy.setProxyServerType(ProxyServerType.HTTP);
+        policy.setNonProxyHosts("internal.example.com");
+
+        Proxy proxy = factory.createProxy(policy, new 
URI("http://internal.example.com/service";));
+
+        assertEquals(Proxy.NO_PROXY, proxy);
+    }
+
+    @Test
+    public void customProxySelectorIsConsultedWhenNoPolicyProxy() throws 
Exception {
+        Proxy expected = new Proxy(Proxy.Type.HTTP, new 
InetSocketAddress("custom-proxy.example.com", 3128));
+        ProxySelector.setDefault(new FixedProxySelector(expected));
+
+        Proxy proxy = factory.createProxy(new HTTPClientPolicy(), new 
URI("http://target.example.com/service";));
+
+        assertEquals(expected, proxy);
+    }
+
+    @Test
+    public void customProxySelectorIsConsultedWhenPolicyIsNull() throws 
Exception {
+        Proxy expected = new Proxy(Proxy.Type.HTTP, new 
InetSocketAddress("proxy.example.com", 8080));
+        ProxySelector.setDefault(new FixedProxySelector(expected));
+
+        Proxy proxy = factory.createProxy(null, new 
URI("http://target.example.com/service";));
+
+        assertEquals(expected, proxy);
+    }
+
+    @Test
+    public void customProxySelectorCanBypassProxyForCertainHosts() throws 
Exception {
+        Proxy routedProxy = new Proxy(Proxy.Type.HTTP, new 
InetSocketAddress("proxy.example.com", 8080));
+        ProxySelector.setDefault(new 
BypassingProxySelector("internal.example.com", routedProxy));
+
+        assertNull(factory.createProxy(null, new 
URI("http://internal.example.com/service";)));
+        assertEquals(routedProxy, factory.createProxy(null, new 
URI("http://external.example.com/service";)));
+    }
+
+    @Test
+    public void noProxyReturnedWhenSelectorReturnsNoProxy() throws Exception {
+        ProxySelector.setDefault(new FixedProxySelector(Proxy.NO_PROXY));
+
+        assertNull(factory.createProxy(null, new 
URI("http://target.example.com/service";)));
+    }
+
+    private static final class FixedProxySelector extends ProxySelector {
+        private final Proxy proxy;
+
+        FixedProxySelector(Proxy proxy) {
+            this.proxy = proxy;
+        }
+
+        @Override
+        public List<Proxy> select(URI uri) {
+            return Collections.singletonList(proxy);
+        }
+
+        @Override
+        public void connectFailed(URI uri, SocketAddress sa, IOException ioe) {
+        }
+    }
+
+    private static final class BypassingProxySelector extends ProxySelector {
+        private final String bypassHost;
+        private final Proxy proxy;
+
+        BypassingProxySelector(String bypassHost, Proxy proxy) {
+            this.bypassHost = bypassHost;
+            this.proxy = proxy;
+        }
+
+        @Override
+        public List<Proxy> select(URI uri) {
+            if (bypassHost.equals(uri.getHost())) {
+                return Collections.singletonList(Proxy.NO_PROXY);
+            }
+            return Collections.singletonList(proxy);
+        }
+
+        @Override
+        public void connectFailed(URI uri, SocketAddress sa, IOException ioe) {
+        }
+    }
+}

Reply via email to