27
27
28
28
package org .apache .hc .client5 .http .impl .routing ;
29
29
30
+ import java .net .InetAddress ;
30
31
import java .net .InetSocketAddress ;
31
32
import java .net .Proxy ;
32
33
import java .net .ProxySelector ;
33
34
import java .net .URI ;
34
35
import java .net .URISyntaxException ;
36
+ import java .security .AccessController ;
37
+ import java .security .PrivilegedAction ;
35
38
import java .util .List ;
39
+ import java .util .Locale ;
36
40
37
41
import org .apache .hc .client5 .http .SchemePortResolver ;
38
42
import org .apache .hc .core5 .annotation .Contract ;
@@ -85,7 +89,7 @@ protected HttpHost determineProxy(final HttpHost target, final HttpContext conte
85
89
}
86
90
if (proxySelectorInstance == null ) {
87
91
//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 ===
89
93
}
90
94
final List <Proxy > proxies = proxySelectorInstance .select (targetURI );
91
95
final Proxy p = chooseProxy (proxies );
@@ -100,8 +104,79 @@ protected HttpHost determineProxy(final HttpHost target, final HttpContext conte
100
104
result = new HttpHost (null , isa .getAddress (), isa .getHostString (), isa .getPort ());
101
105
}
102
106
107
+ if (result == null ) {
108
+ result = determineEnvProxy (target );
109
+ }
110
+
103
111
return result ;
104
112
}
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
+ }
105
180
106
181
private Proxy chooseProxy (final List <Proxy > proxies ) {
107
182
Proxy result = null ;
0 commit comments