From 73c9d6e8f89f40570e7f8a81976f368282a29a60 Mon Sep 17 00:00:00 2001 From: Zoe Wang <33073555+zoewangg@users.noreply.github.com> Date: Wed, 12 Aug 2026 14:02:31 -0700 Subject: [PATCH 1/2] fix(http): trim nonProxyHosts entry whitespace Whitespace around comma- or pipe-separated no_proxy / http.nonProxyHosts entries was treated as part of the host name and never matched, so the host was proxied. Trim each entry in the shared SdkHttpUtils parser; also documents the nonProxyHosts wildcard contract. --- .../bugfix-Apache5HTTPClient-6c80c24.json | 6 ++++ .../bugfix-ApacheHTTPClient-97e1afc.json | 6 ++++ .../bugfix-NettyNIOHTTPClient-93bb990.json | 6 ++++ ...ugfix-URLConnectionHTTPClient-da3b3e2.json | 6 ++++ .../awssdk/crtcore/CrtProxyConfiguration.java | 6 +++- .../http/apache/ProxyConfiguration.java | 17 ++++++++++- .../http/apache5/ProxyConfiguration.java | 17 ++++++++++- .../http/nio/netty/ProxyConfiguration.java | 18 +++++++++-- .../http/nio/netty/ProxyWireMockTest.java | 30 +++++++++++++++++++ .../urlconnection/ProxyConfiguration.java | 17 ++++++++++- .../http/proxy/ProxyConfigCommonTestData.java | 21 ++++++++++++- .../awssdk/utils/http/SdkHttpUtils.java | 1 + .../amazon/awssdk/utils/SdkHttpUtilsTest.java | 25 ++++++++++++++++ 13 files changed, 168 insertions(+), 8 deletions(-) create mode 100644 .changes/next-release/bugfix-Apache5HTTPClient-6c80c24.json create mode 100644 .changes/next-release/bugfix-ApacheHTTPClient-97e1afc.json create mode 100644 .changes/next-release/bugfix-NettyNIOHTTPClient-93bb990.json create mode 100644 .changes/next-release/bugfix-URLConnectionHTTPClient-da3b3e2.json diff --git a/.changes/next-release/bugfix-Apache5HTTPClient-6c80c24.json b/.changes/next-release/bugfix-Apache5HTTPClient-6c80c24.json new file mode 100644 index 000000000000..954a45368bc4 --- /dev/null +++ b/.changes/next-release/bugfix-Apache5HTTPClient-6c80c24.json @@ -0,0 +1,6 @@ +{ + "type": "bugfix", + "category": "Apache 5 HTTP Client", + "contributor": "", + "description": "Trimmed surrounding whitespace from `nonProxyHosts` / `no_proxy` entries so comma- or pipe-separated values with spaces (e.g. `no_proxy=a.com, *.foo.com`) are honored. Previously an entry with a leading or trailing space was treated as part of the host name and never matched, so the host was routed through the proxy instead of bypassing it." +} diff --git a/.changes/next-release/bugfix-ApacheHTTPClient-97e1afc.json b/.changes/next-release/bugfix-ApacheHTTPClient-97e1afc.json new file mode 100644 index 000000000000..5c3c8cb7d608 --- /dev/null +++ b/.changes/next-release/bugfix-ApacheHTTPClient-97e1afc.json @@ -0,0 +1,6 @@ +{ + "type": "bugfix", + "category": "Apache HTTP Client", + "contributor": "", + "description": "Trimmed surrounding whitespace from `nonProxyHosts` / `no_proxy` entries so comma- or pipe-separated values with spaces (e.g. `no_proxy=a.com, *.foo.com`) are honored. Previously an entry with a leading or trailing space was treated as part of the host name and never matched, so the host was routed through the proxy instead of bypassing it." +} diff --git a/.changes/next-release/bugfix-NettyNIOHTTPClient-93bb990.json b/.changes/next-release/bugfix-NettyNIOHTTPClient-93bb990.json new file mode 100644 index 000000000000..8334e0008adc --- /dev/null +++ b/.changes/next-release/bugfix-NettyNIOHTTPClient-93bb990.json @@ -0,0 +1,6 @@ +{ + "type": "bugfix", + "category": "Netty NIO HTTP Client", + "contributor": "", + "description": "Trimmed surrounding whitespace from `nonProxyHosts` / `no_proxy` entries so comma- or pipe-separated values with spaces (e.g. `no_proxy=a.com, *.foo.com`) are honored. Previously an entry with a leading or trailing space was treated as part of the host name and never matched, so the host was routed through the proxy instead of bypassing it." +} diff --git a/.changes/next-release/bugfix-URLConnectionHTTPClient-da3b3e2.json b/.changes/next-release/bugfix-URLConnectionHTTPClient-da3b3e2.json new file mode 100644 index 000000000000..7cd654403232 --- /dev/null +++ b/.changes/next-release/bugfix-URLConnectionHTTPClient-da3b3e2.json @@ -0,0 +1,6 @@ +{ + "type": "bugfix", + "category": "URL Connection HTTP Client", + "contributor": "", + "description": "Trimmed surrounding whitespace from `nonProxyHosts` / `no_proxy` entries so comma- or pipe-separated values with spaces (e.g. `no_proxy=a.com, *.foo.com`) are honored. Previously an entry with a leading or trailing space was treated as part of the host name and never matched, so the host was routed through the proxy instead of bypassing it." +} diff --git a/core/crt-core/src/main/java/software/amazon/awssdk/crtcore/CrtProxyConfiguration.java b/core/crt-core/src/main/java/software/amazon/awssdk/crtcore/CrtProxyConfiguration.java index cf7c8737f699..014cbd6a044c 100644 --- a/core/crt-core/src/main/java/software/amazon/awssdk/crtcore/CrtProxyConfiguration.java +++ b/core/crt-core/src/main/java/software/amazon/awssdk/crtcore/CrtProxyConfiguration.java @@ -259,6 +259,9 @@ public interface Builder { * are not provided during building the {@link CrtProxyConfiguration} object. To disable this behaviour, set this value to * false.It is important to note that when this property is set to "true," all proxy settings will exclusively originate * from system properties, and no partial settings will be obtained from EnvironmentVariableValues. + *

Pipe-separated host names in the {@code http.nonProxyHosts} system property 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. * * @param useSystemPropertyValues The option whether to use system property values * @return This object for method chaining. @@ -272,7 +275,8 @@ public interface Builder { * value to false.It is important to note that when this property is set to "true," all proxy settings will exclusively * originate from environment variableValues, and no partial settings will be obtained from SystemPropertyValues. *

Comma-separated host names in the NO_PROXY environment variable indicate multiple hosts to exclude from - * proxy settings. + * 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. * * @param useEnvironmentVariableValues The option whether to use environment variable values * @return This object for method chaining. diff --git a/http-clients/apache-client/src/main/java/software/amazon/awssdk/http/apache/ProxyConfiguration.java b/http-clients/apache-client/src/main/java/software/amazon/awssdk/http/apache/ProxyConfiguration.java index c5e24a9e7e11..a73dfb74e5df 100644 --- a/http-clients/apache-client/src/main/java/software/amazon/awssdk/http/apache/ProxyConfiguration.java +++ b/http-clients/apache-client/src/main/java/software/amazon/awssdk/http/apache/ProxyConfiguration.java @@ -259,11 +259,18 @@ public interface Builder extends CopyableBuilder { /** * Configure the hosts that the client is allowed to access without going through the proxy. + *

Entries supplied here are treated as exact host names (e.g. {@code example.com}) or CIDR ranges for IP addresses + * (e.g. {@code 10.0.0.0/8}). Wildcard patterns such as {@code *.example.com} or a bare {@code *} are not supported for + * entries supplied here; to use wildcards, configure them through the {@code http.nonProxyHosts} system property or the + * {@code NO_PROXY} environment variable instead. */ Builder nonProxyHosts(Set nonProxyHosts); /** * Add a host that the client is allowed to access without going through the proxy. + *

The host is treated as an exact host name or CIDR range; wildcard patterns are not supported for entries supplied + * here. See {@link #nonProxyHosts(Set)} for details on wildcard support through the system property or environment + * variable. * * @see ProxyConfiguration#nonProxyHosts() */ @@ -281,6 +288,11 @@ public interface Builder extends CopyableBuilder { * are not provided during building the {@link ProxyConfiguration} object. To disable this behavior, set this value to * "false".It is important to note that when this property is set to "true," all proxy settings will exclusively originate * from system properties, and no partial settings will be obtained from EnvironmentVariableValues. + *

Pipe-separated host names in the {@code http.nonProxyHosts} system property 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. 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), + * a single {@code *} (which matches all hosts), or a CIDR range for IP addresses (e.g. {@code 10.0.0.0/8}). */ Builder useSystemPropertyValues(Boolean useSystemPropertyValues); @@ -293,7 +305,10 @@ public interface Builder extends CopyableBuilder { * proxy settings will exclusively originate from environment variableValues, and no partial settings will be obtained * from SystemPropertyValues. *

Comma-separated host names in the NO_PROXY environment variable indicate multiple hosts to exclude from - * proxy settings. + * 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), + * 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. * @return This object for method chaining. diff --git a/http-clients/apache5-client/src/main/java/software/amazon/awssdk/http/apache5/ProxyConfiguration.java b/http-clients/apache5-client/src/main/java/software/amazon/awssdk/http/apache5/ProxyConfiguration.java index 14c655c2557b..61ad3805468d 100644 --- a/http-clients/apache5-client/src/main/java/software/amazon/awssdk/http/apache5/ProxyConfiguration.java +++ b/http-clients/apache5-client/src/main/java/software/amazon/awssdk/http/apache5/ProxyConfiguration.java @@ -259,11 +259,18 @@ public interface Builder extends CopyableBuilder { /** * Configure the hosts that the client is allowed to access without going through the proxy. + *

Entries supplied here are treated as exact host names (e.g. {@code example.com}) or CIDR ranges for IP addresses + * (e.g. {@code 10.0.0.0/8}). Wildcard patterns such as {@code *.example.com} or a bare {@code *} are not supported for + * entries supplied here; to use wildcards, configure them through the {@code http.nonProxyHosts} system property or the + * {@code NO_PROXY} environment variable instead. */ Builder nonProxyHosts(Set nonProxyHosts); /** * Add a host that the client is allowed to access without going through the proxy. + *

The host is treated as an exact host name or CIDR range; wildcard patterns are not supported for entries supplied + * here. See {@link #nonProxyHosts(Set)} for details on wildcard support through the system property or environment + * variable. * * @see ProxyConfiguration#nonProxyHosts() */ @@ -281,6 +288,11 @@ public interface Builder extends CopyableBuilder { * are not provided during building the {@link ProxyConfiguration} object. To disable this behavior, set this value to * "false".It is important to note that when this property is set to "true," all proxy settings will exclusively originate * from system properties, and no partial settings will be obtained from EnvironmentVariableValues. + *

Pipe-separated host names in the {@code http.nonProxyHosts} system property 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. 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), + * a single {@code *} (which matches all hosts), or a CIDR range for IP addresses (e.g. {@code 10.0.0.0/8}). */ Builder useSystemPropertyValues(Boolean useSystemPropertyValues); @@ -293,7 +305,10 @@ public interface Builder extends CopyableBuilder { * proxy settings will exclusively originate from environment variableValues, and no partial settings will be obtained * from SystemPropertyValues. *

Comma-separated host names in the NO_PROXY environment variable indicate multiple hosts to exclude from - * proxy settings. + * 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), + * 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. * @return This object for method chaining. diff --git a/http-clients/netty-nio-client/src/main/java/software/amazon/awssdk/http/nio/netty/ProxyConfiguration.java b/http-clients/netty-nio-client/src/main/java/software/amazon/awssdk/http/nio/netty/ProxyConfiguration.java index 2c422fceb2b4..3e99406187ba 100644 --- a/http-clients/netty-nio-client/src/main/java/software/amazon/awssdk/http/nio/netty/ProxyConfiguration.java +++ b/http-clients/netty-nio-client/src/main/java/software/amazon/awssdk/http/nio/netty/ProxyConfiguration.java @@ -235,8 +235,12 @@ public interface Builder extends CopyableBuilder { Builder scheme(String scheme); /** - * Set the set of hosts that should not be proxied. Any request whose host portion matches any of the patterns - * given in the set will be sent to the remote host directly instead of through the proxy. + * Set the set of hosts that should not be proxied. Any request whose host portion matches one of these entries will be + * sent to the remote host directly instead of through the proxy. + *

Entries supplied here are treated as exact host names (e.g. {@code example.com}) or CIDR ranges for IP addresses + * (e.g. {@code 10.0.0.0/8}). Wildcard patterns such as {@code *.example.com} or a bare {@code *} are not supported for + * entries supplied here; to use wildcards, configure them through the {@code http.nonProxyHosts} system property or the + * {@code NO_PROXY} environment variable instead. * * @param nonProxyHosts The set of hosts that should not be proxied. * @return This object for method chaining. @@ -265,6 +269,11 @@ public interface Builder extends CopyableBuilder { * options are not provided during building the {@link ProxyConfiguration} object. To disable this behaviour, set this * value to false.It is important to note that when this property is set to "true," all proxy settings will exclusively * be obtained from System Property Values, and no partial settings will be obtained from Environment Variable Values. + *

Pipe-separated host names in the {@code http.nonProxyHosts} system property 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. 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), + * a single {@code *} (which matches all hosts), or a CIDR range for IP addresses (e.g. {@code 10.0.0.0/8}). * * @param useSystemPropertyValues The option whether to use system property values * @return This object for method chaining. @@ -280,7 +289,10 @@ public interface Builder extends CopyableBuilder { * proxy settings will exclusively originate from Environment Variable Values, and no partial settings will be obtained * from System Property Values. *

Comma-separated host names in the NO_PROXY environment variable indicate multiple hosts to exclude from - * proxy settings. + * 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), + * 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 * @return This object for method chaining. diff --git a/http-clients/netty-nio-client/src/test/java/software/amazon/awssdk/http/nio/netty/ProxyWireMockTest.java b/http-clients/netty-nio-client/src/test/java/software/amazon/awssdk/http/nio/netty/ProxyWireMockTest.java index 438d65e1f9fc..75ab4de383cf 100644 --- a/http-clients/netty-nio-client/src/test/java/software/amazon/awssdk/http/nio/netty/ProxyWireMockTest.java +++ b/http-clients/netty-nio-client/src/test/java/software/amazon/awssdk/http/nio/netty/ProxyWireMockTest.java @@ -37,11 +37,14 @@ import software.amazon.awssdk.http.async.AsyncExecuteRequest; import software.amazon.awssdk.http.async.SdkAsyncHttpClient; import software.amazon.awssdk.http.async.SdkAsyncHttpResponseHandler; +import software.amazon.awssdk.testutils.EnvironmentVariableHelper; /** * Tests for HTTP proxy functionality in the Netty client. */ public class ProxyWireMockTest { + private static final EnvironmentVariableHelper ENVIRONMENT_VARIABLE_HELPER = new EnvironmentVariableHelper(); + private static SdkAsyncHttpClient client; private static ProxyConfiguration proxyCfg; @@ -79,6 +82,7 @@ public void methodTeardown() { client.close(); } client = null; + ENVIRONMENT_VARIABLE_HELPER.reset(); } @Test(expected = IOException.class) @@ -150,6 +154,32 @@ public void proxyConfigured_hostInNonProxySet_nonBlockingDns_doesNotConnect() { assertThat(responseHandler.fullResponseAsString()).isEqualTo("hello"); } + @Test + public void proxyConfigured_hostInCommaSpaceNoProxyEnv_doesNotConnect() { + ENVIRONMENT_VARIABLE_HELPER.set("no_proxy", "example.com, localhost"); + + RecordingResponseHandler responseHandler = new RecordingResponseHandler(); + AsyncExecuteRequest req = AsyncExecuteRequest.builder() + .request(testSdkRequest()) + .responseHandler(responseHandler) + .requestContentPublisher(new EmptyPublisher()) + .build(); + + ProxyConfiguration cfg = ProxyConfiguration.builder() + .host("localhost") + .port(mockProxy.port()) + .build(); + + client = NettyNioAsyncHttpClient.builder() + .proxyConfiguration(cfg) + .build(); + + client.execute(req).join(); + + responseHandler.completeFuture.join(); + assertThat(responseHandler.fullResponseAsString()).isEqualTo("hello"); + } + private SdkHttpFullRequest testSdkRequest() { return SdkHttpFullRequest.builder() .method(SdkHttpMethod.GET) diff --git a/http-clients/url-connection-client/src/main/java/software/amazon/awssdk/http/urlconnection/ProxyConfiguration.java b/http-clients/url-connection-client/src/main/java/software/amazon/awssdk/http/urlconnection/ProxyConfiguration.java index 8ca88eb36320..db1b91ffdcab 100644 --- a/http-clients/url-connection-client/src/main/java/software/amazon/awssdk/http/urlconnection/ProxyConfiguration.java +++ b/http-clients/url-connection-client/src/main/java/software/amazon/awssdk/http/urlconnection/ProxyConfiguration.java @@ -219,11 +219,18 @@ public interface Builder extends CopyableBuilder { /** * Configure the hosts that the client is allowed to access without going through the proxy. + *

Entries supplied here are treated as exact host names (e.g. {@code example.com}) or CIDR ranges for IP addresses + * (e.g. {@code 10.0.0.0/8}). Wildcard patterns such as {@code *.example.com} or a bare {@code *} are not supported for + * entries supplied here; to use wildcards, configure them through the {@code http.nonProxyHosts} system property or the + * {@code NO_PROXY} environment variable instead. */ Builder nonProxyHosts(Set nonProxyHosts); /** * Add a host that the client is allowed to access without going through the proxy. + *

The host is treated as an exact host name or CIDR range; wildcard patterns are not supported for entries supplied + * here. See {@link #nonProxyHosts(Set)} for details on wildcard support through the system property or environment + * variable. * * @see ProxyConfiguration#nonProxyHosts() */ @@ -236,6 +243,11 @@ public interface Builder extends CopyableBuilder { * are not provided during building the {@link ProxyConfiguration} object. To disable this behavior, set this value to * "false".It is important to note that when this property is set to "true," all proxy settings will exclusively originate * from system properties, and no partial settings will be obtained from EnvironmentVariableValues + *

Pipe-separated host names in the {@code http.nonProxyHosts} system property 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. 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), + * a single {@code *} (which matches all hosts), or a CIDR range for IP addresses (e.g. {@code 10.0.0.0/8}). */ Builder useSystemPropertyValues(Boolean useSystemPropertyValues); @@ -246,7 +258,10 @@ public interface Builder extends CopyableBuilder { * value to "false".It is important to note that when this property is set to "true," all proxy settings will exclusively * originate from environment variableValues, and no partial settings will be obtained from SystemPropertyValues. *

Comma-separated host names in the NO_PROXY environment variable indicate multiple hosts to exclude from - * proxy settings. + * 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), + * 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 * @return This object for method chaining. diff --git a/test/http-client-tests/src/main/java/software/amazon/awssdk/http/proxy/ProxyConfigCommonTestData.java b/test/http-client-tests/src/main/java/software/amazon/awssdk/http/proxy/ProxyConfigCommonTestData.java index 4dc1d58be2c7..0c86b9676ccd 100644 --- a/test/http-client-tests/src/main/java/software/amazon/awssdk/http/proxy/ProxyConfigCommonTestData.java +++ b/test/http-client-tests/src/main/java/software/amazon/awssdk/http/proxy/ProxyConfigCommonTestData.java @@ -36,6 +36,7 @@ public final class ProxyConfigCommonTestData { public static final String ENVIRONMENT_HOST = "environmentVariable.com".toLowerCase(Locale.US); public static final String ENVIRONMENT_VARIABLE_PORT_NUMBER = "3333"; public static final String ENVIRONMENT_VARIABLE_NON_PROXY = "environmentVariableNonProxy".toLowerCase(Locale.US); + public static final String ENVIRONMENT_VARIABLE_NON_PROXY_SECOND = "secondNonProxy.com".toLowerCase(Locale.US); public static final String USER_HOST_ON_BUILDER = "proxyBuilder.com"; public static final int USER_PORT_NUMBER_ON_BUILDER = 9999; public static final String USER_USERNAME_ON_BUILDER = "proxyBuilderUser"; @@ -245,7 +246,16 @@ null, null, getSystemPropertyProxySettings().host(USER_HOST_ON_BUILDER).port(USE + "resolved", getSystemPropertiesWithNoUserName(), environmentSettingsWithNoPassword(), - new TestProxySetting(), false, true, getEnvironmentVariableProxySettings().password(null)) + new TestProxySetting(), false, true, getEnvironmentVariableProxySettings().password(null)), + + Arguments.of( + "Provided no system property and a comma-space separated no_proxy environment variable when " + + "useEnvironmentVariable is set then each non-proxy host is resolved with surrounding whitespace trimmed", + Collections.singletonList(Pair.of("", "")), + environmentSettingsWithCommaSpaceNonProxy(), + new TestProxySetting(), false, true, + getEnvironmentVariableProxySettings().nonProxyHost(ENVIRONMENT_VARIABLE_NON_PROXY, + ENVIRONMENT_VARIABLE_NON_PROXY_SECOND)) ); } @@ -300,6 +310,15 @@ private static List> environmentSettingsWithNoPassword() { ); } + private static List> environmentSettingsWithCommaSpaceNonProxy() { + return Arrays.asList( + Pair.of("%s_proxy", + "http://" + ENV_VARIABLE_USER + ":" + ENV_VARIABLE_PASSWORD + "@" + ENVIRONMENT_HOST + + ":" + ENVIRONMENT_VARIABLE_PORT_NUMBER + "/"), + Pair.of("no_proxy", ENVIRONMENT_VARIABLE_NON_PROXY + ", " + ENVIRONMENT_VARIABLE_NON_PROXY_SECOND) + ); + } + private static List> systemPropertySettings() { return Arrays.asList( Pair.of("%s.proxyHost", SYSTEM_PROPERTY_HOST), diff --git a/utils/src/main/java/software/amazon/awssdk/utils/http/SdkHttpUtils.java b/utils/src/main/java/software/amazon/awssdk/utils/http/SdkHttpUtils.java index 02a402d0db4d..487610762340 100644 --- a/utils/src/main/java/software/amazon/awssdk/utils/http/SdkHttpUtils.java +++ b/utils/src/main/java/software/amazon/awssdk/utils/http/SdkHttpUtils.java @@ -438,6 +438,7 @@ public static Set parseNonProxyHostsProperty() { private static Set extractNonProxyHosts(String nonProxyHosts) { if (nonProxyHosts != null && !isEmpty(nonProxyHosts)) { return Arrays.stream(nonProxyHosts.split("\\|")) + .map(String::trim) .map(String::toLowerCase) .map(s -> StringUtils.replace(s, "*", ".*?")) .collect(Collectors.toSet()); diff --git a/utils/src/test/java/software/amazon/awssdk/utils/SdkHttpUtilsTest.java b/utils/src/test/java/software/amazon/awssdk/utils/SdkHttpUtilsTest.java index 5f27afc9ccb6..4435403166dc 100644 --- a/utils/src/test/java/software/amazon/awssdk/utils/SdkHttpUtilsTest.java +++ b/utils/src/test/java/software/amazon/awssdk/utils/SdkHttpUtilsTest.java @@ -333,4 +333,29 @@ void parseNonProxyHostsProperty_regexPathStillRewritesWildcard() { } } } + + @Test + void parseListOfNonProxyHostWithCommaSpace_trimsSurroundingWhitespace(){ + String multipleHostNames = "example.com, *greedy.org, 192.168.1.1"; + ENVIRONMENT_VARIABLE_HELPER.set("no_proxy", multipleHostNames); + Set strings = SdkHttpUtils.parseNonProxyHostsEnvironmentVariable(); + assertThat(strings).isEqualTo(Stream.of("example.com", ".*?greedy.org", "192.168.1.1") + .collect(Collectors.toSet())); + } + + @Test + void parseNonProxyHostWithSurroundingWhitespace_isTrimmed(){ + ENVIRONMENT_VARIABLE_HELPER.set("no_proxy", " example.com "); + Set strings = SdkHttpUtils.parseNonProxyHostsEnvironmentVariable(); + assertThat(strings).containsExactly("example.com"); + } + + @Test + void parseListOfNonProxyHostWithoutWhitespace_isUnchanged(){ + String multipleHostNames = "example.com,*greedy.org,192.168.1.1"; + ENVIRONMENT_VARIABLE_HELPER.set("no_proxy", multipleHostNames); + Set strings = SdkHttpUtils.parseNonProxyHostsEnvironmentVariable(); + assertThat(strings).isEqualTo(Stream.of("example.com", ".*?greedy.org", "192.168.1.1") + .collect(Collectors.toSet())); + } } From efecfa1ac4a61795b9ab1d4ceaa51a8b57e8b176 Mon Sep 17 00:00:00 2001 From: Zoe Wang <33073555+zoewangg@users.noreply.github.com> Date: Wed, 12 Aug 2026 16:19:14 -0700 Subject: [PATCH 2/2] test: remove duplicate nonProxyHosts trim test parseListOfNonProxyHostWithoutWhitespace_isUnchanged duplicated the existing parseListOfNonProxyHostWithCommasAndWildCard (same no-whitespace input and assertions). The no-whitespace regression is already covered there; the whitespace-trim behavior is covered by the comma-space and single-host trim tests. --- .../software/amazon/awssdk/utils/SdkHttpUtilsTest.java | 9 --------- 1 file changed, 9 deletions(-) diff --git a/utils/src/test/java/software/amazon/awssdk/utils/SdkHttpUtilsTest.java b/utils/src/test/java/software/amazon/awssdk/utils/SdkHttpUtilsTest.java index 4435403166dc..a7055d65b25e 100644 --- a/utils/src/test/java/software/amazon/awssdk/utils/SdkHttpUtilsTest.java +++ b/utils/src/test/java/software/amazon/awssdk/utils/SdkHttpUtilsTest.java @@ -349,13 +349,4 @@ void parseNonProxyHostWithSurroundingWhitespace_isTrimmed(){ Set strings = SdkHttpUtils.parseNonProxyHostsEnvironmentVariable(); assertThat(strings).containsExactly("example.com"); } - - @Test - void parseListOfNonProxyHostWithoutWhitespace_isUnchanged(){ - String multipleHostNames = "example.com,*greedy.org,192.168.1.1"; - ENVIRONMENT_VARIABLE_HELPER.set("no_proxy", multipleHostNames); - Set strings = SdkHttpUtils.parseNonProxyHostsEnvironmentVariable(); - assertThat(strings).isEqualTo(Stream.of("example.com", ".*?greedy.org", "192.168.1.1") - .collect(Collectors.toSet())); - } }