Skip to content

Use System Property Proxy Settings for Netty and Amazon CRT HTTP Clients #2771

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 10 commits into from
Nov 12, 2021
Merged
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@
import java.util.Objects;
import software.amazon.awssdk.annotations.SdkPreviewApi;
import software.amazon.awssdk.annotations.SdkPublicApi;
import software.amazon.awssdk.utils.ProxySystemSetting;
import software.amazon.awssdk.utils.builder.CopyableBuilder;
import software.amazon.awssdk.utils.builder.ToCopyableBuilder;

Expand All @@ -39,11 +40,13 @@ public final class ProxyConfiguration implements ToCopyableBuilder<ProxyConfigur

private final String username;
private final String password;
private final Boolean useSystemPropertyValues;

private ProxyConfiguration(BuilderImpl builder) {
this.useSystemPropertyValues = builder.useSystemPropertyValues;
this.scheme = builder.scheme;
this.host = builder.host;
this.port = builder.port;
this.host = resolveHost(builder.host);
this.port = resolvePort(builder.port);
this.username = builder.username;
this.password = builder.password;
}
Expand All @@ -56,31 +59,35 @@ public String scheme() {
}

/**
* @return The proxy host.
* @return The proxy host from the configuration if set, or from the "http.proxyHost" system property if
* {@link Builder#useSystemPropertyValues(Boolean)} is set to true
*/
public String host() {
return host;
}

/**
* @return The proxy port.
* @return The proxy port from the configuration if set, or from the "http.proxyPort" system property if
* {@link Builder#useSystemPropertyValues(Boolean)} is set to true
*/
public int port() {
return port;
}

/**
* @return Basic authentication username
*/
* @return The proxy username from the configuration if set, or from the "http.proxyUser" system property if
* {@link Builder#useSystemPropertyValues(Boolean)} is set to true
* */
public String username() {
return username;
return resolveValue(username, ProxySystemSetting.PROXY_USERNAME);
}

/**
* @return Basic authentication password
*/
* @return The proxy password from the configuration if set, or from the "http.proxyPassword" system property if
* {@link Builder#useSystemPropertyValues(Boolean)} is set to true
* */
public String password() {
return password;
return resolveValue(password, ProxySystemSetting.PROXY_PASSWORD);
}

@Override
Expand Down Expand Up @@ -182,19 +189,49 @@ public interface Builder extends CopyableBuilder<Builder, ProxyConfiguration> {
* @return This object for method chaining.
*/
Builder password(String password);

/**
* The option whether to use system property values from {@link ProxySystemSetting} if any of the config options
* are missing. The value is set to "true" by default which means SDK will automatically use system property values if
* options are not provided during building the {@link ProxyConfiguration} object. To disable this behaviour, set this
* value to false.
*
* @param useSystemPropertyValues The option whether to use system property values
* @return This object for method chaining.
*/
Builder useSystemPropertyValues(Boolean useSystemPropertyValues);
}

private String resolveHost(String host) {
return resolveValue(host, ProxySystemSetting.PROXY_HOST);
}

private int resolvePort(int port) {
return port == 0 && Boolean.TRUE.equals(useSystemPropertyValues) ?
ProxySystemSetting.PROXY_PORT.getStringValue().map(Integer::parseInt).orElse(0) : port;
}

/**
* Uses the configuration options, system setting property and returns the final value of the given member.
*/
private String resolveValue(String value, ProxySystemSetting systemSetting) {
return value == null && Boolean.TRUE.equals(useSystemPropertyValues) ?
systemSetting.getStringValue().orElse(null) : value;
}

private static final class BuilderImpl implements Builder {
private String scheme;
private String host;
private int port;
private int port = 0;
private String username;
private String password;
private Boolean useSystemPropertyValues = Boolean.TRUE;

private BuilderImpl() {
}

private BuilderImpl(ProxyConfiguration proxyConfiguration) {
this.useSystemPropertyValues = proxyConfiguration.useSystemPropertyValues;
this.scheme = proxyConfiguration.scheme;
this.host = proxyConfiguration.host;
this.port = proxyConfiguration.port;
Expand Down Expand Up @@ -232,6 +269,16 @@ public Builder password(String password) {
return this;
}

@Override
public Builder useSystemPropertyValues(Boolean useSystemPropertyValues) {
this.useSystemPropertyValues = useSystemPropertyValues;
return this;
}

public void setUseSystemPropertyValues(Boolean useSystemPropertyValues) {
useSystemPropertyValues(useSystemPropertyValues);
}

@Override
public ProxyConfiguration build() {
return new ProxyConfiguration(this);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,19 +20,93 @@
import java.lang.reflect.Method;
import java.util.Random;
import java.util.stream.Stream;
import org.junit.AfterClass;
import org.junit.Before;
import org.junit.Test;

/**
* Tests for {@link ProxyConfiguration}.
*/
public class ProxyConfigurationTest {
private static final Random RNG = new Random();
private static final String TEST_HOST = "foo.com";
private static final int TEST_PORT = 7777;
private static final String TEST_USER = "testuser";
private static final String TEST_PASSWORD = "123";

@Before
public void setup() {
clearProxyProperties();
}

@AfterClass
public static void cleanup() {
clearProxyProperties();
}

@Test
public void build_setsAllProperties() {
verifyAllPropertiesSet(allPropertiesSetConfig());
}

@Test
public void build_systemPropertyDefault() {
setProxyProperties();
ProxyConfiguration config = ProxyConfiguration.builder().build();

assertThat(config.host()).isEqualTo(TEST_HOST);
assertThat(config.port()).isEqualTo(TEST_PORT);
assertThat(config.username()).isEqualTo(TEST_USER);
assertThat(config.password()).isEqualTo(TEST_PASSWORD);
assertThat(config.scheme()).isNull();
}

@Test
public void build_systemPropertyEnabled() {
setProxyProperties();
ProxyConfiguration config = ProxyConfiguration.builder().useSystemPropertyValues(Boolean.TRUE).build();

assertThat(config.host()).isEqualTo(TEST_HOST);
assertThat(config.port()).isEqualTo(TEST_PORT);
assertThat(config.username()).isEqualTo(TEST_USER);
assertThat(config.password()).isEqualTo(TEST_PASSWORD);
assertThat(config.scheme()).isNull();
}

@Test
public void build_systemPropertyDisabled() {
setProxyProperties();
ProxyConfiguration config = ProxyConfiguration.builder()
.host("localhost")
.port(8888)
.username("username")
.password("password")
.useSystemPropertyValues(Boolean.FALSE).build();

assertThat(config.host()).isEqualTo("localhost");
assertThat(config.port()).isEqualTo(8888);
assertThat(config.username()).isEqualTo("username");
assertThat(config.password()).isEqualTo("password");
assertThat(config.scheme()).isNull();
}

@Test
public void build_systemPropertyOverride() {
setProxyProperties();
ProxyConfiguration config = ProxyConfiguration.builder()
.host("localhost")
.port(8888)
.username("username")
.password("password")
.build();

assertThat(config.host()).isEqualTo("localhost");
assertThat(config.port()).isEqualTo(8888);
assertThat(config.username()).isEqualTo("username");
assertThat(config.password()).isEqualTo("password");
assertThat(config.scheme()).isNull();
}

@Test
public void toBuilder_roundTrip_producesExactCopy() {
ProxyConfiguration original = allPropertiesSetConfig();
Expand Down Expand Up @@ -76,6 +150,8 @@ private void setRandomValue(Object o, Method setter) throws InvocationTargetExce
setter.invoke(o, randomString());
} else if (int.class.equals(paramClass)) {
setter.invoke(o, RNG.nextInt());
} else if (Boolean.class.equals(paramClass)) {
setter.invoke(o, RNG.nextBoolean());
} else {
throw new RuntimeException("Don't know how create random value for type " + paramClass);
}
Expand Down Expand Up @@ -108,4 +184,18 @@ private String randomString() {

return sb.toString();
}

private void setProxyProperties() {
System.setProperty("http.proxyHost", TEST_HOST);
System.setProperty("http.proxyPort", Integer.toString(TEST_PORT));
System.setProperty("http.proxyUser", TEST_USER);
System.setProperty("http.proxyPassword", TEST_PASSWORD);
}

private static void clearProxyProperties() {
System.clearProperty("http.proxyHost");
System.clearProperty("http.proxyPort");
System.clearProperty("http.proxyUser");
System.clearProperty("http.proxyPassword");
}
}
Loading