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) {
+ }
+ }
+}