Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 6 additions & 0 deletions .changes/next-release/bugfix-AWSSDKforJavav2-134c9c4.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
{
"type": "bugfix",
"category": "AWS SDK for Java v2",
"contributor": "afarber",
"description": "Support leading-dot domain suffixes in the NO_PROXY environment variable."
}
Original file line number Diff line number Diff line change
Expand Up @@ -276,7 +276,8 @@ public interface Builder {
* originate from environment variableValues, and no partial settings will be obtained from SystemPropertyValues.
* <p>Comma-separated host names in the NO_PROXY environment variable indicate multiple hosts to exclude from
* proxy settings. Surrounding empty spaces around each host name are trimmed, so both {@code "a.com,b.com"} and
* {@code "a.com, b.com"} are accepted.
* {@code "a.com, b.com"} are accepted. A leading-dot suffix such as {@code .example.com} is equivalent to
* {@code *.example.com}.
*
* @param useEnvironmentVariableValues The option whether to use environment variable values
* @return This object for method chaining.
Expand Down Expand Up @@ -410,4 +411,4 @@ public void setUseSystemPropertyValues(Boolean useSystemPropertyValues) {
}

}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -313,6 +313,7 @@ public interface Builder extends CopyableBuilder<Builder, ProxyConfiguration> {
* proxy settings. Surrounding empty spaces around each host name are trimmed, so both {@code "a.com,b.com"} and
* {@code "a.com, b.com"} are accepted. Each entry may be an exact host name (e.g. {@code example.com}), a
* leading-wildcard suffix (e.g. {@code *.example.com}, which matches {@code example.com} and its subdomains),
* or a leading-dot suffix (e.g. {@code .example.com}, equivalent to {@code *.example.com}),
* a single {@code *} (which matches all hosts), or a CIDR range for IP addresses (e.g. {@code 10.0.0.0/8}).
*
* @param useEnvironmentVariableValues The option whether to use environment variable values.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@
package software.amazon.awssdk.http.apache.internal;

import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertNull;

import java.util.Collections;
import org.apache.http.HttpException;
Expand All @@ -29,6 +30,7 @@
*/
public class SdkProxyRoutePlannerTest {
private static final HttpHost S3_HOST = new HttpHost("s3.us-west-2.amazonaws.com", 443, "https");
private static final HttpHost INTERNAL_HOST = new HttpHost("s3.storage.company.internal", 443, "https");
private static final HttpGet S3_REQUEST = new HttpGet("/my-bucket/my-object");
private static final HttpClientContext CONTEXT = new HttpClientContext();

Expand All @@ -49,4 +51,12 @@ public void testSetsCorrectSchemeBasedOnProcotol_HTTP() throws HttpException {
assertEquals("localhost", proxyHost.getHostName());
assertEquals("http", proxyHost.getSchemeName());
}

@Test
public void leadingDotSuffixPatternBypassesProxy() throws HttpException {
SdkProxyRoutePlanner planner = new SdkProxyRoutePlanner("localhost", 1234, "https",
Collections.singleton(".*?.company.internal"));

assertNull(planner.determineRoute(INTERNAL_HOST, S3_REQUEST, CONTEXT).getProxyHost());
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -308,6 +308,7 @@ public interface Builder extends CopyableBuilder<Builder, ProxyConfiguration> {
* proxy settings. Surrounding empty spaces around each host name are trimmed, so both {@code "a.com,b.com"} and
* {@code "a.com, b.com"} are accepted. Each entry may be an exact host name (e.g. {@code example.com}), a
* leading-wildcard suffix (e.g. {@code *.example.com}, which matches {@code example.com} and its subdomains),
* or a leading-dot suffix (e.g. {@code .example.com}, equivalent to {@code *.example.com}),
* a single {@code *} (which matches all hosts), or a CIDR range for IP addresses (e.g. {@code 10.0.0.0/8}).
*
* @param useEnvironmentVariableValues The option whether to use environment variable values.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -126,7 +126,7 @@ public interface Builder extends CrtProxyConfiguration.Builder, CopyableBuilder<
* proxy settings will exclusively originate from Environment Variable Values, and no partial settings will be obtained
* from System Property Values.
* <p>Comma-separated host names in the NO_PROXY environment variable indicate multiple hosts to exclude from
* proxy settings.
* proxy settings. A leading-dot suffix such as {@code .example.com} is equivalent to {@code *.example.com}.
*
* @param useEnvironmentVariableValues The option whether to use environment variable values
* @return This object for method chaining.
Expand Down Expand Up @@ -177,4 +177,4 @@ public ProxyConfiguration build() {
return new ProxyConfiguration(this);
}
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -353,6 +353,7 @@ public interface Builder extends CopyableBuilder<Builder, ProxyConfiguration> {
* proxy settings. Surrounding empty spaces around each host name are trimmed, so both {@code "a.com,b.com"} and
* {@code "a.com, b.com"} are accepted. Each entry may be an exact host name (e.g. {@code example.com}), a
* leading-wildcard suffix (e.g. {@code *.example.com}, which matches {@code example.com} and its subdomains),
* or a leading-dot suffix (e.g. {@code .example.com}, equivalent to {@code *.example.com}),
* a single {@code *} (which matches all hosts), or a CIDR range for IP addresses (e.g. {@code 10.0.0.0/8}).
*
* @param useEnvironmentVariablesValues The option whether to use environment variable values
Expand Down Expand Up @@ -460,4 +461,4 @@ public ProxyConfiguration build() {
return new ProxyConfiguration(this);
}
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -261,6 +261,7 @@ public interface Builder extends CopyableBuilder<Builder, ProxyConfiguration> {
* proxy settings. Surrounding empty spaces around each host name are trimmed, so both {@code "a.com,b.com"} and
* {@code "a.com, b.com"} are accepted. Each entry may be an exact host name (e.g. {@code example.com}), a
* leading-wildcard suffix (e.g. {@code *.example.com}, which matches {@code example.com} and its subdomains),
* or a leading-dot suffix (e.g. {@code .example.com}, equivalent to {@code *.example.com}),
* a single {@code *} (which matches all hosts), or a CIDR range for IP addresses (e.g. {@code 10.0.0.0/8}).
*
* @param useEnvironmentVariablesValues The option whether to use environment variable values
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -436,10 +436,15 @@ public static Set<String> parseNonProxyHostsProperty() {
}

private static Set<String> extractNonProxyHosts(String nonProxyHosts) {
return extractNonProxyHosts(nonProxyHosts, UnaryOperator.identity());
}

private static Set<String> extractNonProxyHosts(String nonProxyHosts, UnaryOperator<String> tokenMapper) {
if (nonProxyHosts != null && !isEmpty(nonProxyHosts)) {
return Arrays.stream(nonProxyHosts.split("\\|"))
.map(String::trim)
.map(String::toLowerCase)
.map(tokenMapper)
.map(s -> StringUtils.replace(s, "*", ".*?"))
.collect(Collectors.toSet());
}
Expand All @@ -450,6 +455,6 @@ public static Set<String> parseNonProxyHostsEnvironmentVariable() {
String hosts = ProxyEnvironmentSetting.NO_PROXY.getStringValue()
.map(noProxyHost -> noProxyHost.replace(",", "|"))
.orElse(null);
return extractNonProxyHosts(hosts);
return extractNonProxyHosts(hosts, host -> host.startsWith(".") ? "*" + host : host);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -318,6 +318,16 @@ void parseListOfNonProxyHostWithPipesAndWildCard(){
.collect(Collectors.toSet()));
}

@Test
void parseListOfNonProxyHostWithLeadingDotSuffix() {
ENVIRONMENT_VARIABLE_HELPER.set("no_proxy", "example.com, .company.internal,*.greedy.org");

Set<String> strings = SdkHttpUtils.parseNonProxyHostsEnvironmentVariable();

assertThat(strings).isEqualTo(Stream.of("example.com", ".*?.company.internal", ".*?.greedy.org")
.collect(Collectors.toSet()));
}

@Test
void parseNonProxyHostsProperty_regexPathStillRewritesWildcard() {
String previous = System.getProperty("http.nonProxyHosts");
Expand All @@ -334,6 +344,21 @@ void parseNonProxyHostsProperty_regexPathStillRewritesWildcard() {
}
}

@Test
void parseNonProxyHostsProperty_leadingDotIsNotNormalized() {
String previous = System.getProperty("http.nonProxyHosts");
System.setProperty("http.nonProxyHosts", ".company.internal");
try {
assertThat(SdkHttpUtils.parseNonProxyHostsProperty()).containsExactly(".company.internal");
} finally {
if (previous == null) {
System.clearProperty("http.nonProxyHosts");
} else {
System.setProperty("http.nonProxyHosts", previous);
}
}
}

@Test
void parseListOfNonProxyHostWithCommaSpace_trimsSurroundingWhitespace(){
String multipleHostNames = "example.com, *greedy.org, 192.168.1.1";
Expand Down