From 16d2c81178bdb5d51b9abfa49aa01a6db4d07621 Mon Sep 17 00:00:00 2001
From: Zoe Wang <33073555+zoewangg@users.noreply.github.com>
Date: Mon, 23 Mar 2026 18:31:00 -0700
Subject: [PATCH 1/2] Set maxConcurrentStreams on HTTP/2 stream manager so that
the MAX_CONNECTIONS setting is respected for HTTP/2. Also improved the error
message when HTTP/2 is configured with the sync client to clarify available
options.
---
.../amazon/awssdk/http/crt/AwsCrtHttpClient.java | 4 +++-
.../amazon/awssdk/http/crt/AwsCrtHttpClientBase.java | 9 +++++----
.../amazon/awssdk/http/crt/internal/CrtUtils.java | 10 +++-------
.../software/amazon/awssdk/http/crt/H2ErrorTest.java | 5 +++--
pom.xml | 2 +-
5 files changed, 15 insertions(+), 15 deletions(-)
diff --git a/http-clients/aws-crt-client/src/main/java/software/amazon/awssdk/http/crt/AwsCrtHttpClient.java b/http-clients/aws-crt-client/src/main/java/software/amazon/awssdk/http/crt/AwsCrtHttpClient.java
index a2eec3bcc625..ca97f6079b89 100644
--- a/http-clients/aws-crt-client/src/main/java/software/amazon/awssdk/http/crt/AwsCrtHttpClient.java
+++ b/http-clients/aws-crt-client/src/main/java/software/amazon/awssdk/http/crt/AwsCrtHttpClient.java
@@ -58,7 +58,9 @@ public final class AwsCrtHttpClient extends AwsCrtHttpClientBase implements SdkH
private AwsCrtHttpClient(DefaultBuilder builder, AttributeMap config) {
super(builder, config);
if (this.protocol == Protocol.HTTP2) {
- throw new UnsupportedOperationException("HTTP/2 is not supported in sync client. Use AwsCrtAsyncHttpClient instead.");
+ throw new UnsupportedOperationException(
+ "HTTP/2 is not supported for sync HTTP clients. Either use HTTP/1.1 (the default) or use an async "
+ + "HTTP client (e.g., AwsCrtAsyncHttpClient).");
}
}
diff --git a/http-clients/aws-crt-client/src/main/java/software/amazon/awssdk/http/crt/AwsCrtHttpClientBase.java b/http-clients/aws-crt-client/src/main/java/software/amazon/awssdk/http/crt/AwsCrtHttpClientBase.java
index 228a6086eddf..b7d00688c2ab 100644
--- a/http-clients/aws-crt-client/src/main/java/software/amazon/awssdk/http/crt/AwsCrtHttpClientBase.java
+++ b/http-clients/aws-crt-client/src/main/java/software/amazon/awssdk/http/crt/AwsCrtHttpClientBase.java
@@ -69,7 +69,7 @@ abstract class AwsCrtHttpClientBase implements SdkAutoCloseable {
private final HttpProxyOptions proxyOptions;
private final HttpMonitoringOptions monitoringOptions;
private final long maxConnectionIdleInMilliseconds;
- private final int maxConnectionsPerEndpoint;
+ private final int maxStreamsPerEndpoint;
private final long connectionAcquisitionTimeout;
private final TlsContextOptions tlsContextOptions;
private boolean isClosed = false;
@@ -95,7 +95,7 @@ abstract class AwsCrtHttpClientBase implements SdkAutoCloseable {
this.tlsContext = registerOwnedResource(clientTlsContext);
this.readBufferSize = builder.getReadBufferSizeInBytes() == null ?
DEFAULT_STREAM_WINDOW_SIZE : builder.getReadBufferSizeInBytes();
- this.maxConnectionsPerEndpoint = config.get(SdkHttpConfigurationOption.MAX_CONNECTIONS);
+ this.maxStreamsPerEndpoint = config.get(SdkHttpConfigurationOption.MAX_CONNECTIONS);
this.monitoringOptions = resolveHttpMonitoringOptions(builder.getConnectionHealthConfiguration()).orElse(null);
this.maxConnectionIdleInMilliseconds = config.get(SdkHttpConfigurationOption.CONNECTION_MAX_IDLE_TIMEOUT).toMillis();
this.connectionAcquisitionTimeout = config.get(SdkHttpConfigurationOption.CONNECTION_ACQUIRE_TIMEOUT).toMillis();
@@ -121,7 +121,7 @@ String clientName() {
}
private HttpStreamManager createConnectionPool(URI uri) {
- log.debug(() -> "Creating ConnectionPool for: URI:" + uri + ", MaxConns: " + maxConnectionsPerEndpoint);
+ log.debug(() -> "Creating ConnectionPool for: URI:" + uri + ", MaxConns: " + maxStreamsPerEndpoint);
boolean isHttps = "https".equalsIgnoreCase(uri.getScheme());
TlsContext poolTlsContext = isHttps ? tlsContext : null;
@@ -132,7 +132,7 @@ private HttpStreamManager createConnectionPool(URI uri) {
.withTlsContext(poolTlsContext)
.withUri(uri)
.withWindowSize(readBufferSize)
- .withMaxConnections(maxConnectionsPerEndpoint)
+ .withMaxConnections(maxStreamsPerEndpoint)
.withManualWindowManagement(true)
.withProxyOptions(proxyOptions)
.withMonitoringOptions(monitoringOptions)
@@ -144,6 +144,7 @@ private HttpStreamManager createConnectionPool(URI uri) {
if (protocol == Protocol.HTTP2) {
Http2StreamManagerOptions h2Options = new Http2StreamManagerOptions()
+ .withMaxConcurrentStreams(maxStreamsPerEndpoint)
.withConnectionManagerOptions(h1Options);
if (!isHttps) {
diff --git a/http-clients/aws-crt-client/src/main/java/software/amazon/awssdk/http/crt/internal/CrtUtils.java b/http-clients/aws-crt-client/src/main/java/software/amazon/awssdk/http/crt/internal/CrtUtils.java
index 6b660175614a..53f73f2e8d42 100644
--- a/http-clients/aws-crt-client/src/main/java/software/amazon/awssdk/http/crt/internal/CrtUtils.java
+++ b/http-clients/aws-crt-client/src/main/java/software/amazon/awssdk/http/crt/internal/CrtUtils.java
@@ -28,8 +28,8 @@
import java.util.concurrent.CompletionException;
import javax.net.ssl.SSLHandshakeException;
import software.amazon.awssdk.annotations.SdkInternalApi;
+import software.amazon.awssdk.crt.CRT;
import software.amazon.awssdk.crt.CrtRuntimeException;
-import software.amazon.awssdk.crt.http.HttpClientConnection;
import software.amazon.awssdk.crt.http.HttpException;
import software.amazon.awssdk.crt.http.HttpManagerMetrics;
import software.amazon.awssdk.crt.http.HttpStreamManager;
@@ -50,10 +50,7 @@ private CrtUtils() {
public static Throwable wrapWithIoExceptionIfRetryable(HttpException httpException) {
Throwable toThrow = httpException;
- // TODO: switch to Crt.awsIsTransientError once https://github.com/awslabs/aws-crt-java/pull/972 is merged
- if (HttpClientConnection.isErrorRetryable(httpException)) {
- // IOExceptions get retried, and if the CRT says this error is retryable,
- // it's semantically an IOException anyway.
+ if (CRT.awsIsTransientError(httpException.getErrorCode())) {
toThrow = new IOException(httpException);
}
return toThrow;
@@ -70,8 +67,7 @@ public static Throwable wrapCrtException(Throwable throwable) {
if (httpErrorCode == CRT_TLS_NEGOTIATION_ERROR_CODE) {
return new SSLHandshakeException(httpException.getMessage());
}
- // TODO: check with CRT team, could CRT_SOCKET_TIMEOUT be thrown
- // from processes other than tcp connect?
+
if (httpErrorCode == CRT_SOCKET_TIMEOUT) {
return new ConnectException(httpException.getMessage());
}
diff --git a/http-clients/aws-crt-client/src/test/java/software/amazon/awssdk/http/crt/H2ErrorTest.java b/http-clients/aws-crt-client/src/test/java/software/amazon/awssdk/http/crt/H2ErrorTest.java
index 926c07414c3f..557419ea426d 100644
--- a/http-clients/aws-crt-client/src/test/java/software/amazon/awssdk/http/crt/H2ErrorTest.java
+++ b/http-clients/aws-crt-client/src/test/java/software/amazon/awssdk/http/crt/H2ErrorTest.java
@@ -55,6 +55,7 @@
import org.junit.jupiter.api.AfterEach;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
+import software.amazon.awssdk.crt.http.HttpException;
import software.amazon.awssdk.http.Protocol;
import software.amazon.awssdk.http.async.SdkAsyncHttpClient;
import software.amazon.awssdk.utils.AttributeMap;
@@ -82,14 +83,14 @@ public void teardown() {
}
@Test
- public void serverSendsRstStream_shouldThrowIOException() throws Exception {
+ public void serverSendsRstStream_shouldNotThrowIOException() throws Exception {
H2ErrorServer server = new H2ErrorServer(ErrorType.RST_STREAM);
server.init();
try {
CompletableFuture> request = sendGetRequest(server.port(), client);
assertThatThrownBy(request::join)
.isInstanceOf(CompletionException.class)
- .hasCauseInstanceOf(IOException.class)
+ .hasCauseInstanceOf(HttpException.class)
.hasMessageContaining("RST_STREAM");
} finally {
server.shutdown();
diff --git a/pom.xml b/pom.xml
index 6a8d8b09fed0..52ac0c9ebe13 100644
--- a/pom.xml
+++ b/pom.xml
@@ -130,7 +130,7 @@
3.1.5
1.17.1
1.37
- 0.43.5
+ 0.43.9
5.10.3
From 22cd422dc7606365bcf273d450b3a757c2f6dc13 Mon Sep 17 00:00:00 2001
From: Zoe Wang <33073555+zoewangg@users.noreply.github.com>
Date: Tue, 24 Mar 2026 14:03:26 -0700
Subject: [PATCH 2/2] Update
http-clients/aws-crt-client/src/main/java/software/amazon/awssdk/http/crt/AwsCrtHttpClientBase.java
Co-authored-by: Dengke Tang <815825145@qq.com>
---
.../software/amazon/awssdk/http/crt/AwsCrtHttpClientBase.java | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/http-clients/aws-crt-client/src/main/java/software/amazon/awssdk/http/crt/AwsCrtHttpClientBase.java b/http-clients/aws-crt-client/src/main/java/software/amazon/awssdk/http/crt/AwsCrtHttpClientBase.java
index b7d00688c2ab..41a834c6d7aa 100644
--- a/http-clients/aws-crt-client/src/main/java/software/amazon/awssdk/http/crt/AwsCrtHttpClientBase.java
+++ b/http-clients/aws-crt-client/src/main/java/software/amazon/awssdk/http/crt/AwsCrtHttpClientBase.java
@@ -121,7 +121,7 @@ String clientName() {
}
private HttpStreamManager createConnectionPool(URI uri) {
- log.debug(() -> "Creating ConnectionPool for: URI:" + uri + ", MaxConns: " + maxStreamsPerEndpoint);
+ log.debug(() -> "Creating ConnectionPool for: URI:" + uri + ", MaxConns: " + maxStreamsPerEndpoint+ ", MaxStreams: " + maxStreamsPerEndpoint);
boolean isHttps = "https".equalsIgnoreCase(uri.getScheme());
TlsContext poolTlsContext = isHttps ? tlsContext : null;