From e8e6e08544222481c5c35edd81f6253138a6f93e Mon Sep 17 00:00:00 2001 From: smw <1397472492@qq.com> Date: Wed, 26 Aug 2026 15:40:53 +0000 Subject: [PATCH] Use forwarding proxy mode for plaintext endpoints in CRT S3 client The CRT derives the proxy connection type from whether TLS options were supplied for the main connection, not from the scheme actually in use. Because S3NativeClientConfiguration always builds a TlsContext and S3CrtAsyncHttpClient passes it to the native client unconditionally, a plaintext http:// endpoint was still reached through a CONNECT tunnel. Proxies that only support forwarding mode reject those requests. Pin the proxy connection type to Forwarding when endpointOverride uses the http scheme, mirroring the scheme check that the CRT's own HttpClientConnectionManager already performs before handing a TLS context to the native layer. Only the combination of a configured proxy and a plaintext endpoint override is affected; https endpoints, endpoints without an override, and proxy-less configurations continue to resolve through Legacy as before. Not passing the TlsContext was evaluated first and does not work: aws-c-s3 still tunnels, so the connection type has to be set explicitly. Fixes #7320 --- .../bugfix-AWSCRTbasedS3Client-7a3c1e2.json | 6 +++ .../crt/S3NativeClientConfiguration.java | 20 ++++++++ .../crt/S3NativeClientConfigurationTest.java | 48 +++++++++++++++++++ 3 files changed, 74 insertions(+) create mode 100644 .changes/next-release/bugfix-AWSCRTbasedS3Client-7a3c1e2.json diff --git a/.changes/next-release/bugfix-AWSCRTbasedS3Client-7a3c1e2.json b/.changes/next-release/bugfix-AWSCRTbasedS3Client-7a3c1e2.json new file mode 100644 index 000000000000..78233be09295 --- /dev/null +++ b/.changes/next-release/bugfix-AWSCRTbasedS3Client-7a3c1e2.json @@ -0,0 +1,6 @@ +{ + "type": "bugfix", + "category": "AWS CRT-based S3 Client", + "contributor": "MingWangSong", + "description": "Fixed an issue where the CRT-based S3 client always established proxy connections through a `CONNECT` tunnel, even when `endpointOverride` used the plaintext `http://` scheme. Proxies that only support forwarding mode rejected these requests. The proxy connection type is now pinned to forwarding for plaintext endpoints, matching the behavior of `ApacheHttpClient`. See [#7320](https://github.com/aws/aws-sdk-java-v2/issues/7320)." +} diff --git a/services/s3/src/main/java/software/amazon/awssdk/services/s3/internal/crt/S3NativeClientConfiguration.java b/services/s3/src/main/java/software/amazon/awssdk/services/s3/internal/crt/S3NativeClientConfiguration.java index b3c0742a272c..47b428699dcc 100644 --- a/services/s3/src/main/java/software/amazon/awssdk/services/s3/internal/crt/S3NativeClientConfiguration.java +++ b/services/s3/src/main/java/software/amazon/awssdk/services/s3/internal/crt/S3NativeClientConfiguration.java @@ -47,6 +47,7 @@ public class S3NativeClientConfiguration implements SdkAutoCloseable { static final long DEFAULT_PART_SIZE_IN_BYTES = 8L * 1024 * 1024; private static final Logger log = Logger.loggerFor(S3NativeClientConfiguration.class); private static final long DEFAULT_TARGET_THROUGHPUT_IN_GBPS = 10; + private static final String HTTP_SCHEME = "http"; private final String signingRegion; private final StandardRetryOptions standardRetryOptions; @@ -106,6 +107,7 @@ public S3NativeClientConfiguration(Builder builder) { if (builder.httpConfiguration != null) { this.proxyOptions = resolveProxy(builder.httpConfiguration.proxyConfiguration(), tlsContext).orElse(null); + applyPlaintextEndpointProxyConnectionType(this.proxyOptions, this.endpointOverride); this.connectionTimeout = builder.httpConfiguration.connectionTimeout(); this.httpMonitoringOptions = resolveHttpMonitoringOptions(builder.httpConfiguration.healthConfiguration()).orElse(null); @@ -135,6 +137,24 @@ private long resolveThresholdInBytes(Builder builder) { return this.partSizeInBytes == null ? DEFAULT_PART_SIZE_IN_BYTES : this.partSizeInBytes; } + /** + * Pins the proxy connection type to forwarding when the endpoint is plaintext. + * + *
The CRT derives the proxy connection type from whether TLS options were supplied for the main connection,
+ * not from the scheme actually in use. Because this client is always constructed with a {@link TlsContext}, a
+ * plaintext {@code http://} endpoint would otherwise be reached through a {@code CONNECT} tunnel, which
+ * forwarding-only proxies reject. This mirrors the scheme check that the CRT's own
+ * {@code HttpClientConnectionManager} performs before handing a TLS context to the native layer.
+ */
+ private static void applyPlaintextEndpointProxyConnectionType(HttpProxyOptions proxyOptions, URI endpointOverride) {
+ if (proxyOptions == null || endpointOverride == null) {
+ return;
+ }
+ if (HTTP_SCHEME.equalsIgnoreCase(endpointOverride.getScheme())) {
+ proxyOptions.setConnectionType(HttpProxyOptions.HttpProxyConnectionType.Forwarding);
+ }
+ }
+
private static Boolean resolveUseEnvironmentVariableValues(Builder builder) {
if (builder != null && builder.httpConfiguration != null && builder.httpConfiguration.proxyConfiguration() != null) {
return builder.httpConfiguration.proxyConfiguration().isUseEnvironmentVariableValues();
diff --git a/services/s3/src/test/java/software/amazon/awssdk/services/s3/internal/crt/S3NativeClientConfigurationTest.java b/services/s3/src/test/java/software/amazon/awssdk/services/s3/internal/crt/S3NativeClientConfigurationTest.java
index 0fdb91c0e6a5..5662d6b8237c 100644
--- a/services/s3/src/test/java/software/amazon/awssdk/services/s3/internal/crt/S3NativeClientConfigurationTest.java
+++ b/services/s3/src/test/java/software/amazon/awssdk/services/s3/internal/crt/S3NativeClientConfigurationTest.java
@@ -17,6 +17,7 @@
import static org.assertj.core.api.Assertions.assertThat;
+import java.net.URI;
import java.util.stream.Stream;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.params.ParameterizedTest;
@@ -24,6 +25,8 @@
import org.junit.jupiter.params.provider.MethodSource;
import software.amazon.awssdk.auth.credentials.AwsBasicCredentials;
import software.amazon.awssdk.auth.credentials.StaticCredentialsProvider;
+import software.amazon.awssdk.crt.http.HttpProxyOptions;
+import software.amazon.awssdk.services.s3.crt.S3CrtProxyConfiguration;
import software.amazon.awssdk.services.s3.crt.S3CrtHttpConfiguration;
import software.amazon.awssdk.testutils.LogCaptor;
@@ -61,7 +64,49 @@ private static Stream