Skip to content

Commit 51dad6a

Browse files
committed
Apache configuration cleanup
1 parent 5ea93a9 commit 51dad6a

File tree

11 files changed

+390
-24
lines changed

11 files changed

+390
-24
lines changed

core/sdk-core/src/test/java/software/amazon/awssdk/core/internal/http/timers/AsyncHttpClientApiCallTimeoutTests.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -147,7 +147,7 @@ public void successfulResponse_SlowResponseHandler_ThrowsApiCallTimeoutException
147147
}
148148

149149
@Test
150-
public void slowApiAttempt_ThrowsApiCallAttemptTimeoutException() {
150+
public void slowApiAttempt_ThrowsApiCallAttemptTimeoutException() {
151151
httpClient = testAsyncClientBuilder()
152152
.apiCallTimeout(API_CALL_TIMEOUT)
153153
.apiCallAttemptTimeout(Duration.ofMillis(100))

http-clients/apache-client/pom.xml

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -67,6 +67,11 @@
6767
<artifactId>junit</artifactId>
6868
<scope>test</scope>
6969
</dependency>
70+
<dependency>
71+
<groupId>org.assertj</groupId>
72+
<artifactId>assertj-core</artifactId>
73+
<scope>test</scope>
74+
</dependency>
7075
<dependency>
7176
<groupId>org.hamcrest</groupId>
7277
<artifactId>hamcrest-all</artifactId>

http-clients/apache-client/src/main/java/software/amazon/awssdk/http/apache/ApacheHttpClient.java

Lines changed: 32 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@
1818
import static java.util.stream.Collectors.groupingBy;
1919
import static java.util.stream.Collectors.mapping;
2020
import static java.util.stream.Collectors.toList;
21+
import static software.amazon.awssdk.http.SdkHttpConfigurationOption.CONNECTION_ACQUIRE_TIMEOUT;
2122
import static software.amazon.awssdk.http.SdkHttpConfigurationOption.CONNECTION_TIMEOUT;
2223
import static software.amazon.awssdk.http.SdkHttpConfigurationOption.GLOBAL_HTTP_DEFAULTS;
2324
import static software.amazon.awssdk.http.SdkHttpConfigurationOption.MAX_CONNECTIONS;
@@ -78,6 +79,7 @@
7879
import software.amazon.awssdk.http.apache.internal.utils.ApacheUtils;
7980
import software.amazon.awssdk.utils.AttributeMap;
8081
import software.amazon.awssdk.utils.Logger;
82+
import software.amazon.awssdk.utils.Validate;
8183

8284
/**
8385
* An implementation of {@link SdkHttpClient} that uses Apache HTTP client to communicate with the service. This is the most
@@ -140,10 +142,11 @@ private void addProxyConfig(HttpClientBuilder builder,
140142
ProxyConfiguration proxyConfiguration) {
141143
if (isProxyEnabled(proxyConfiguration)) {
142144

143-
log.debug(() -> "Configuring Proxy. Proxy Host: " + proxyConfiguration.endpoint());
145+
log.debug(() -> "Configuring Proxy. Proxy Host: " + proxyConfiguration.host());
144146

145-
builder.setRoutePlanner(new SdkProxyRoutePlanner(proxyConfiguration.endpoint().getHost(),
146-
proxyConfiguration.endpoint().getPort(),
147+
builder.setRoutePlanner(new SdkProxyRoutePlanner(proxyConfiguration.host(),
148+
proxyConfiguration.port(),
149+
proxyConfiguration.scheme(),
147150
proxyConfiguration.nonProxyHosts()));
148151

149152
if (isAuthenticatedProxy(proxyConfiguration)) {
@@ -164,9 +167,8 @@ private boolean isAuthenticatedProxy(ProxyConfiguration proxyConfiguration) {
164167
}
165168

166169
private boolean isProxyEnabled(ProxyConfiguration proxyConfiguration) {
167-
return proxyConfiguration.endpoint() != null
168-
&& proxyConfiguration.endpoint().getHost() != null
169-
&& proxyConfiguration.endpoint().getPort() > 0;
170+
return proxyConfiguration.host() != null
171+
&& proxyConfiguration.port() > 0;
170172
}
171173

172174
@Override
@@ -240,6 +242,7 @@ private ApacheHttpRequestConfig createRequestConfig(DefaultBuilder builder,
240242
return ApacheHttpRequestConfig.builder()
241243
.socketTimeout(resolvedOptions.get(READ_TIMEOUT))
242244
.connectionTimeout(resolvedOptions.get(CONNECTION_TIMEOUT))
245+
.connectionAcquireTimeout(resolvedOptions.get(CONNECTION_ACQUIRE_TIMEOUT))
243246
.proxyConfiguration(builder.proxyConfiguration)
244247
.localAddress(Optional.ofNullable(builder.localAddress).orElse(null))
245248
.expectContinueEnabled(Optional.ofNullable(builder.expectContinueEnabled)
@@ -273,6 +276,13 @@ public interface Builder extends SdkHttpClient.Builder<ApacheHttpClient.Builder>
273276
*/
274277
Builder connectionTimeout(Duration connectionTimeout);
275278

279+
/**
280+
* The amount of time to wait when acquiring a connection from the pool before giving up and timing out.
281+
* @param connectionAcquisitionTimeout the timeout duration
282+
* @return this builder for method chaining.
283+
*/
284+
Builder connectionAcquisitionTimeout(Duration connectionAcquisitionTimeout);
285+
276286
/**
277287
* The maximum number of connections allowed in the connection pool. Each built HTTP client has it's own private
278288
* connection pool.
@@ -336,6 +346,22 @@ public void setConnectionTimeout(Duration connectionTimeout) {
336346
connectionTimeout(connectionTimeout);
337347
}
338348

349+
/**
350+
* The amount of time to wait when acquiring a connection from the pool before giving up and timing out.
351+
* @param connectionAcquisitionTimeout the timeout duration
352+
* @return this builder for method chaining.
353+
*/
354+
@Override
355+
public Builder connectionAcquisitionTimeout(Duration connectionAcquisitionTimeout) {
356+
Validate.isPositive(connectionAcquisitionTimeout, "connectionAcquisitionTimeout");
357+
standardOptions.put(CONNECTION_ACQUIRE_TIMEOUT, connectionAcquisitionTimeout);
358+
return this;
359+
}
360+
361+
public void setConnectionAcquisitionTimeout(Duration connectionAcquisitionTimeout) {
362+
connectionAcquisitionTimeout(connectionAcquisitionTimeout);
363+
}
364+
339365
@Override
340366
public Builder maxConnections(Integer maxConnections) {
341367
standardOptions.put(MAX_CONNECTIONS, maxConnections);

http-clients/apache-client/src/main/java/software/amazon/awssdk/http/apache/ProxyConfiguration.java

Lines changed: 114 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -18,11 +18,14 @@
1818
import static software.amazon.awssdk.utils.StringUtils.isEmpty;
1919

2020
import java.net.URI;
21+
import java.util.Arrays;
2122
import java.util.Collections;
2223
import java.util.HashSet;
2324
import java.util.Set;
24-
import software.amazon.awssdk.annotations.ReviewBeforeRelease;
25+
import java.util.stream.Collectors;
2526
import software.amazon.awssdk.annotations.SdkPublicApi;
27+
import software.amazon.awssdk.utils.ProxySystemSetting;
28+
import software.amazon.awssdk.utils.StringUtils;
2629
import software.amazon.awssdk.utils.ToString;
2730
import software.amazon.awssdk.utils.Validate;
2831
import software.amazon.awssdk.utils.builder.CopyableBuilder;
@@ -31,7 +34,6 @@
3134
/**
3235
* Configuration that defines how to communicate via an HTTP proxy.
3336
*/
34-
@ReviewBeforeRelease("Review which options are required and which are optional.")
3537
@SdkPublicApi
3638
public final class ProxyConfiguration implements ToCopyableBuilder<ProxyConfiguration.Builder, ProxyConfiguration> {
3739

@@ -42,6 +44,10 @@ public final class ProxyConfiguration implements ToCopyableBuilder<ProxyConfigur
4244
private final String ntlmWorkstation;
4345
private final Set<String> nonProxyHosts;
4446
private final Boolean preemptiveBasicAuthenticationEnabled;
47+
private final Boolean useSystemPropertyValues;
48+
private final String host;
49+
private final int port;
50+
private final String scheme;
4551

4652
/**
4753
* Initialize this configuration. Private to require use of {@link #builder()}.
@@ -52,18 +58,38 @@ private ProxyConfiguration(DefaultClientProxyConfigurationBuilder builder) {
5258
this.password = builder.password;
5359
this.ntlmDomain = builder.ntlmDomain;
5460
this.ntlmWorkstation = builder.ntlmWorkstation;
55-
this.nonProxyHosts = Collections.unmodifiableSet(new HashSet<>(builder.nonProxyHosts));
61+
this.nonProxyHosts = builder.nonProxyHosts;
5662
this.preemptiveBasicAuthenticationEnabled = builder.preemptiveBasicAuthenticationEnabled == null ? Boolean.FALSE :
5763
builder.preemptiveBasicAuthenticationEnabled;
64+
this.useSystemPropertyValues = builder.useSystemPropertyValues;
65+
this.host = resolveHost();
66+
this.port = resolvePort();
67+
this.scheme = resolveScheme();
5868
}
5969

6070
/**
61-
* The endpoint of the proxy server that the SDK should connect through.
71+
* Returns the proxy host name either from the configured endpoint or
72+
* from the "http.proxyHost" system property if {@link Builder#useSystemPropertyValues(Boolean)} is set to true.
73+
*/
74+
public String host() {
75+
return host;
76+
}
77+
78+
/**
79+
* Returns the proxy port either from the configured endpoint or
80+
* from the "http.proxyPort" system property if {@link Builder#useSystemPropertyValues(Boolean)} is set to true.
6281
*
63-
* @see Builder#endpoint(URI)
82+
* If no value is found in neither of the above options, the default value of 0 is returned.
83+
*/
84+
public int port() {
85+
return port;
86+
}
87+
88+
/**
89+
* Returns the {@link URI#scheme} from the configured endpoint. Otherwise return null.
6490
*/
65-
public URI endpoint() {
66-
return endpoint;
91+
public String scheme() {
92+
return scheme;
6793
}
6894

6995
/**
@@ -72,7 +98,7 @@ public URI endpoint() {
7298
* @see Builder#password(String)
7399
*/
74100
public String username() {
75-
return username;
101+
return resolveValue(username, ProxySystemSetting.PROXY_USERNAME);
76102
}
77103

78104
/**
@@ -81,7 +107,7 @@ public String username() {
81107
* @see Builder#password(String)
82108
*/
83109
public String password() {
84-
return password;
110+
return resolveValue(password, ProxySystemSetting.PROXY_PASSWORD);
85111
}
86112

87113
/**
@@ -105,11 +131,16 @@ public String ntlmWorkstation() {
105131
/**
106132
* The hosts that the client is allowed to access without going through the proxy.
107133
*
134+
* If the value is not set on the object, the value represent by "http.nonProxyHosts" system property is returned.
135+
* If system property is also not set, an unmodifiable empty set is returned.
136+
*
108137
* @see Builder#nonProxyHosts(Set)
109138
*/
110-
@ReviewBeforeRelease("Revisit the presentation of this option and support http.nonProxyHosts property")
111139
public Set<String> nonProxyHosts() {
112-
return nonProxyHosts;
140+
Set<String> hosts = nonProxyHosts == null && useSystemPropertyValues ? parseNonProxyHostsProperty()
141+
: nonProxyHosts;
142+
143+
return Collections.unmodifiableSet(hosts != null ? hosts : Collections.emptySet());
113144
}
114145

115146
/**
@@ -152,6 +183,54 @@ public String toString() {
152183
.build();
153184
}
154185

186+
187+
private String resolveHost() {
188+
return endpoint != null ? endpoint.getHost()
189+
: resolveValue(null, ProxySystemSetting.PROXY_HOST);
190+
}
191+
192+
private int resolvePort() {
193+
int port = 0;
194+
195+
if (endpoint != null) {
196+
port = endpoint.getPort();
197+
} else if (useSystemPropertyValues) {
198+
port = ProxySystemSetting.PROXY_PORT.getStringValue()
199+
.map(Integer::parseInt)
200+
.orElse(0);
201+
}
202+
203+
return port;
204+
}
205+
206+
public String resolveScheme() {
207+
return endpoint != null ? endpoint.getScheme() : null;
208+
}
209+
210+
/**
211+
* Uses the configuration options, system setting property and returns the final value of the given member.
212+
*/
213+
private String resolveValue(String value, ProxySystemSetting systemSetting) {
214+
return value == null && useSystemPropertyValues ? systemSetting.getStringValue().orElse(null)
215+
: value;
216+
}
217+
218+
/**
219+
* Returns the Java system property for nonProxyHosts as set of Strings.
220+
* See http://docs.oracle.com/javase/7/docs/api/java/net/doc-files/net-properties.html.
221+
*/
222+
private Set<String> parseNonProxyHostsProperty() {
223+
String nonProxyHosts = ProxySystemSetting.NON_PROXY_HOSTS.getStringValue().orElse(null);
224+
225+
if (!StringUtils.isEmpty(nonProxyHosts)) {
226+
return Arrays.stream(nonProxyHosts.split("\\|"))
227+
.map(String::toLowerCase)
228+
.map(s -> s.replace("*", ".*?"))
229+
.collect(Collectors.toSet());
230+
}
231+
return Collections.emptySet();
232+
}
233+
155234
/**
156235
* A builder for {@link ProxyConfiguration}.
157236
*
@@ -202,6 +281,15 @@ public interface Builder extends CopyableBuilder<Builder, ProxyConfiguration> {
202281
*/
203282
Builder preemptiveBasicAuthenticationEnabled(Boolean preemptiveBasicAuthenticationEnabled);
204283

284+
/**
285+
* Option whether to use system property values from {@link ProxySystemSetting} if any of the config options are missing.
286+
*
287+
* This value is set to "true" by default which means SDK will automatically use system property values
288+
* for options that are not provided during building the {@link ProxyConfiguration} object. To disable this behavior,
289+
* set this value to "false".
290+
*/
291+
Builder useSystemPropertyValues(Boolean useSystemPropertyValues);
292+
205293
}
206294

207295
/**
@@ -214,8 +302,9 @@ private static final class DefaultClientProxyConfigurationBuilder implements Bui
214302
private String password;
215303
private String ntlmDomain;
216304
private String ntlmWorkstation;
217-
private Set<String> nonProxyHosts = new HashSet<>();
305+
private Set<String> nonProxyHosts;
218306
private Boolean preemptiveBasicAuthenticationEnabled;
307+
private Boolean useSystemPropertyValues = Boolean.TRUE;
219308

220309
@Override
221310
public Builder endpoint(URI endpoint) {
@@ -282,6 +371,9 @@ public Builder nonProxyHosts(Set<String> nonProxyHosts) {
282371

283372
@Override
284373
public Builder addNonProxyHost(String nonProxyHost) {
374+
if (this.nonProxyHosts == null) {
375+
this.nonProxyHosts = new HashSet<>();
376+
}
285377
this.nonProxyHosts.add(nonProxyHost);
286378
return this;
287379
}
@@ -300,6 +392,16 @@ public void setPreemptiveBasicAuthenticationEnabled(Boolean preemptiveBasicAuthe
300392
preemptiveBasicAuthenticationEnabled(preemptiveBasicAuthenticationEnabled);
301393
}
302394

395+
@Override
396+
public Builder useSystemPropertyValues(Boolean useSystemPropertyValues) {
397+
this.useSystemPropertyValues = useSystemPropertyValues;
398+
return this;
399+
}
400+
401+
public void setUseSystemPropertyValues(Boolean useSystemPropertyValues) {
402+
useSystemPropertyValues(useSystemPropertyValues);
403+
}
404+
303405
@Override
304406
public ProxyConfiguration build() {
305407
return new ProxyConfiguration(this);

http-clients/apache-client/src/main/java/software/amazon/awssdk/http/apache/internal/ApacheHttpRequestConfig.java

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,13 +29,15 @@ public final class ApacheHttpRequestConfig {
2929

3030
private final Duration socketTimeout;
3131
private final Duration connectionTimeout;
32+
private final Duration connectionAcquireTimeout;
3233
private final InetAddress localAddress;
3334
private final boolean expectContinueEnabled;
3435
private final ProxyConfiguration proxyConfiguration;
3536

3637
private ApacheHttpRequestConfig(Builder builder) {
3738
this.socketTimeout = builder.socketTimeout;
3839
this.connectionTimeout = builder.connectionTimeout;
40+
this.connectionAcquireTimeout = builder.connectionAcquireTimeout;
3941
this.localAddress = builder.localAddress;
4042
this.expectContinueEnabled = builder.expectContinueEnabled;
4143
this.proxyConfiguration = builder.proxyConfiguration;
@@ -49,6 +51,10 @@ public Duration connectionTimeout() {
4951
return connectionTimeout;
5052
}
5153

54+
public Duration connectionAcquireTimeout() {
55+
return connectionAcquireTimeout;
56+
}
57+
5258
public InetAddress localAddress() {
5359
return localAddress;
5460
}
@@ -75,6 +81,7 @@ public static final class Builder {
7581

7682
private Duration socketTimeout;
7783
private Duration connectionTimeout;
84+
private Duration connectionAcquireTimeout;
7885
private InetAddress localAddress;
7986
private Boolean expectContinueEnabled;
8087
private ProxyConfiguration proxyConfiguration;
@@ -92,6 +99,11 @@ public Builder connectionTimeout(Duration connectionTimeout) {
9299
return this;
93100
}
94101

102+
public Builder connectionAcquireTimeout(Duration connectionAcquireTimeout) {
103+
this.connectionAcquireTimeout = connectionAcquireTimeout;
104+
return this;
105+
}
106+
95107
public Builder localAddress(InetAddress localAddress) {
96108
this.localAddress = localAddress;
97109
return this;

http-clients/apache-client/src/main/java/software/amazon/awssdk/http/apache/internal/SdkProxyRoutePlanner.java

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -37,9 +37,9 @@ public class SdkProxyRoutePlanner extends DefaultRoutePlanner {
3737
private HttpHost proxy;
3838
private Set<String> hostPatterns;
3939

40-
public SdkProxyRoutePlanner(String proxyHost, int proxyPort, Set<String> nonProxyHosts) {
40+
public SdkProxyRoutePlanner(String proxyHost, int proxyPort, String proxyProtocol, Set<String> nonProxyHosts) {
4141
super(DefaultSchemePortResolver.INSTANCE);
42-
proxy = new HttpHost(proxyHost, proxyPort);
42+
proxy = new HttpHost(proxyHost, proxyPort, proxyProtocol);
4343
this.hostPatterns = nonProxyHosts;
4444
}
4545

0 commit comments

Comments
 (0)