Skip to content

Commit c5e7684

Browse files
committed
move env-proxy mapping into SystemDefaultRoutePlanner so routes honour HTTP(S)_PROXY / NO_PROXY directly without altering JVM system properties
1 parent 77c3f08 commit c5e7684

File tree

5 files changed

+132
-353
lines changed

5 files changed

+132
-353
lines changed

httpclient5/src/main/java/org/apache/hc/client5/http/config/EnvironmentProxyConfigurer.java

Lines changed: 0 additions & 194 deletions
This file was deleted.

httpclient5/src/main/java/org/apache/hc/client5/http/impl/classic/HttpClientBuilder.java

Lines changed: 0 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -51,7 +51,6 @@
5151
import org.apache.hc.client5.http.classic.BackoffManager;
5252
import org.apache.hc.client5.http.classic.ConnectionBackoffStrategy;
5353
import org.apache.hc.client5.http.classic.ExecChainHandler;
54-
import org.apache.hc.client5.http.config.EnvironmentProxyConfigurer;
5554
import org.apache.hc.client5.http.config.RequestConfig;
5655
import org.apache.hc.client5.http.cookie.BasicCookieStore;
5756
import org.apache.hc.client5.http.cookie.CookieSpecFactory;
@@ -795,33 +794,6 @@ public final HttpClientBuilder disableDefaultUserAgent() {
795794
return this;
796795
}
797796

798-
/**
799-
* Enables transparent transfer of proxy-related environment variables
800-
* to the standard JDK system-properties <em>for this client only</em>.
801-
* <p>
802-
* When this flag is set, {@link EnvironmentProxyConfigurer#apply()}
803-
* will be invoked during {@link #build()}, copying
804-
* {@code HTTP_PROXY}, {@code HTTPS_PROXY} and {@code NO_PROXY}
805-
* (plus lower-case aliases) to their {@code http.*}/{@code https.*}
806-
* counterparts, provided those properties are not already defined.
807-
* </p>
808-
*
809-
* <p><strong>Opt-in behaviour:</strong> if you do not call
810-
* {@code useEnvironmentProxy()}, the builder leaves JVM system
811-
* properties untouched. Combine with
812-
* {@link #useSystemProperties()}&nbsp;(enabled by default via
813-
* {@code HttpClientBuilder.create()}) so the newly populated
814-
* properties are actually honoured by the client.</p>
815-
*
816-
* @return this builder, for method chaining
817-
* @since 5.6
818-
*/
819-
public HttpClientBuilder useEnvironmentProxy() {
820-
this.applyEnvProxy = true;
821-
return this;
822-
}
823-
824-
825797
/**
826798
* Sets the {@link ProxySelector} that will be used to select the proxies
827799
* to be used for establishing HTTP connections. If a non-null proxy selector is set,
@@ -870,10 +842,6 @@ protected Function<HttpContext, HttpClientContext> contextAdaptor() {
870842

871843
public CloseableHttpClient build() {
872844

873-
if (applyEnvProxy) {
874-
EnvironmentProxyConfigurer.apply();
875-
}
876-
877845
// Create main request executor
878846
// We copy the instance fields to avoid changing them, and rename to avoid accidental use of the wrong version
879847
HttpRequestExecutor requestExecCopy = this.requestExec;

httpclient5/src/main/java/org/apache/hc/client5/http/impl/routing/SystemDefaultRoutePlanner.java

Lines changed: 76 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -27,12 +27,16 @@
2727

2828
package org.apache.hc.client5.http.impl.routing;
2929

30+
import java.net.InetAddress;
3031
import java.net.InetSocketAddress;
3132
import java.net.Proxy;
3233
import java.net.ProxySelector;
3334
import java.net.URI;
3435
import java.net.URISyntaxException;
36+
import java.security.AccessController;
37+
import java.security.PrivilegedAction;
3538
import java.util.List;
39+
import java.util.Locale;
3640

3741
import org.apache.hc.client5.http.SchemePortResolver;
3842
import org.apache.hc.core5.annotation.Contract;
@@ -85,7 +89,7 @@ protected HttpHost determineProxy(final HttpHost target, final HttpContext conte
8589
}
8690
if (proxySelectorInstance == null) {
8791
//The proxy selector can be "unset", so we must be able to deal with a null selector
88-
return null;
92+
return determineEnvProxy(target); // === env-fallback ===
8993
}
9094
final List<Proxy> proxies = proxySelectorInstance.select(targetURI);
9195
final Proxy p = chooseProxy(proxies);
@@ -100,8 +104,79 @@ protected HttpHost determineProxy(final HttpHost target, final HttpContext conte
100104
result = new HttpHost(null, isa.getAddress(), isa.getHostString(), isa.getPort());
101105
}
102106

107+
if (result == null) {
108+
result = determineEnvProxy(target);
109+
}
110+
103111
return result;
104112
}
113+
private static HttpHost determineEnvProxy(final HttpHost target) {
114+
final boolean secure = "https".equalsIgnoreCase(target.getSchemeName());
115+
HttpHost proxy = proxyFromEnv(secure ? "HTTPS_PROXY" : "HTTP_PROXY");
116+
if (proxy == null && !secure) {
117+
proxy = proxyFromEnv("HTTPS_PROXY"); // reuse HTTPS proxy for HTTP if only that exists
118+
}
119+
if (proxy != null && !isNoProxy(target)) {
120+
return proxy;
121+
}
122+
return null;
123+
}
124+
125+
private static HttpHost proxyFromEnv(final String var) {
126+
String val = getenv(var);
127+
if (val == null || val.isEmpty()) {
128+
val = getenv(var.toLowerCase(Locale.ROOT));
129+
}
130+
if (val == null || val.isEmpty()) {
131+
return null;
132+
}
133+
if (!val.contains("://")) {
134+
val = "http://" + val;
135+
}
136+
try {
137+
final URI uri = new URI(val);
138+
final String host = uri.getHost();
139+
final int port = uri.getPort() != -1
140+
? uri.getPort()
141+
: ("https".equalsIgnoreCase(uri.getScheme()) ? 443 : 80);
142+
return new HttpHost(uri.getScheme(), InetAddress.getByName(host), port);
143+
} catch (final Exception ignore) {
144+
return null;
145+
}
146+
}
147+
148+
private static boolean isNoProxy(final HttpHost target) {
149+
String list = getenv("NO_PROXY");
150+
if (list == null || list.isEmpty()) {
151+
list = getenv("no_proxy");
152+
}
153+
if (list == null || list.isEmpty()) {
154+
return false;
155+
}
156+
final String host = target.getHostName().toLowerCase(Locale.ROOT);
157+
final String hostPort = host + (target.getPort() != -1 ? ":" + target.getPort() : "");
158+
for (String rule : list.split(",")) {
159+
rule = rule.trim().toLowerCase(Locale.ROOT);
160+
if (rule.isEmpty()) {
161+
continue;
162+
}
163+
if (rule.equals(host) || rule.equals(hostPort)) {
164+
return true; // exact
165+
}
166+
if (rule.startsWith("*.") && host.endsWith(rule.substring(1))) {
167+
return true; // *.example.com
168+
}
169+
if (rule.endsWith("/16") && host.startsWith(rule.substring(0, rule.length() - 3))) {
170+
return true; // cidr /16
171+
}
172+
}
173+
return false;
174+
}
175+
176+
private static String getenv(final String key) {
177+
return AccessController.doPrivileged(
178+
(PrivilegedAction<String>) () -> System.getenv(key));
179+
}
105180

106181
private Proxy chooseProxy(final List<Proxy> proxies) {
107182
Proxy result = null;

0 commit comments

Comments
 (0)