@@ -69,7 +69,7 @@ private AwsCrtHttpClient(DefaultBuilder builder, AttributeMap config) {
6969 }
7070 }
7171
72- public static AwsCrtHttpClient . Builder builder () {
72+ public static Builder builder () {
7373 return new DefaultBuilder ();
7474 }
7575
@@ -124,45 +124,53 @@ private CrtHttpRequest(CrtRequestContext context) {
124124 @ Override
125125 public HttpExecuteResponse call () throws IOException {
126126 HttpExecuteResponse .Builder builder = HttpExecuteResponse .builder ();
127+ CrtRequestExecutor .Result result = new CrtRequestExecutor ().execute (context );
128+ responseFuture = result .responseFuture ();
127129
128130 try {
129- CrtRequestExecutor .Result result = new CrtRequestExecutor ().execute (context );
130- responseFuture = result .responseFuture ();
131131 writeRequestBody (result .streamHandler ());
132132
133133 SdkHttpFullResponse response = CompletableFutureUtils .joinInterruptibly (responseFuture );
134134 builder .response (response );
135135 builder .responseBody (response .content ().orElse (null ));
136136 return builder .build ();
137- } catch (CompletionException e ) {
138- Throwable cause = e .getCause ();
139-
140- // Complete the future exceptionally to trigger connection cleanup in the response handler.
141- // Handles thread-interrupt case where joinInterruptibly throws due to
142- // InterruptedException. Without this, the
143- // Ensures that closeConnection() is invoked to prevent leaking the connection from the pool.
144- if (responseFuture != null ) {
145- responseFuture .completeExceptionally (cause != null ? cause : e );
146- }
147-
148- if (cause instanceof IOException ) {
149- throw (IOException ) cause ;
150- }
151-
152- if (cause instanceof HttpException ) {
153- Throwable wrapped = CrtUtils .wrapCrtException (cause );
154- if (wrapped instanceof IOException ) {
155- throw (IOException ) wrapped ;
156- }
157- throw (HttpException ) cause ;
158- }
137+ } catch (Throwable t ) {
138+ // CompletionException is the wrapper from joinInterruptibly; direct throws
139+ // (e.g., IOException from inputStream.read in writeRequestBody) arrive unwrapped.
140+ Throwable cause = (t instanceof CompletionException && t .getCause () != null ) ? t .getCause () : t ;
141+
142+ // Tear down the stream so the connection is not leaked back to the pool.
143+ // closeConnection() is idempotent and a no-op if the stream is not yet acquired
144+ // or is already closed.
145+ result .streamHandler ().closeConnection ();
146+ responseFuture .completeExceptionally (cause );
147+
148+ throw mapToIoExceptionOrRethrow (cause );
149+ }
150+ }
159151
160- if (cause instanceof InterruptedException ) {
161- Thread .currentThread ().interrupt ();
162- throw new IOException ("Request was cancelled" , cause );
152+ private static IOException mapToIoExceptionOrRethrow (Throwable cause ) {
153+ if (cause instanceof IOException ) {
154+ return (IOException ) cause ;
155+ }
156+ if (cause instanceof HttpException ) {
157+ Throwable wrapped = CrtUtils .wrapCrtException (cause );
158+ if (wrapped instanceof IOException ) {
159+ return (IOException ) wrapped ;
163160 }
164- throw new RuntimeException (e .getCause ());
161+ throw (HttpException ) cause ;
162+ }
163+ if (cause instanceof InterruptedException ) {
164+ Thread .currentThread ().interrupt ();
165+ return new IOException ("Request was cancelled" , cause );
166+ }
167+ if (cause instanceof RuntimeException ) {
168+ throw (RuntimeException ) cause ;
169+ }
170+ if (cause instanceof Error ) {
171+ throw (Error ) cause ;
165172 }
173+ return new IOException (cause );
166174 }
167175
168176 private void writeRequestBody (CrtStreamHandler streamHandler ) throws IOException {
@@ -194,14 +202,14 @@ public void abort() {
194202 /**
195203 * Builder that allows configuration of the AWS CRT HTTP implementation.
196204 */
197- public interface Builder extends SdkHttpClient .Builder <AwsCrtHttpClient . Builder > {
205+ public interface Builder extends SdkHttpClient .Builder <Builder > {
198206
199207 /**
200208 * The Maximum number of allowed concurrent requests. For HTTP/1.1 this is the same as max connections.
201209 * @param maxConcurrency maximum concurrency per endpoint
202210 * @return The builder of the method chaining.
203211 */
204- AwsCrtHttpClient . Builder maxConcurrency (Integer maxConcurrency );
212+ Builder maxConcurrency (Integer maxConcurrency );
205213
206214 /**
207215 * Configures the number of unread bytes that can be buffered in the
@@ -211,22 +219,22 @@ public interface Builder extends SdkHttpClient.Builder<AwsCrtHttpClient.Builder>
211219 * @param readBufferSize The number of bytes that can be buffered.
212220 * @return The builder of the method chaining.
213221 */
214- AwsCrtHttpClient . Builder readBufferSizeInBytes (Long readBufferSize );
222+ Builder readBufferSizeInBytes (Long readBufferSize );
215223
216224 /**
217225 * Sets the http proxy configuration to use for this client.
218226 * @param proxyConfiguration The http proxy configuration to use
219227 * @return The builder of the method chaining.
220228 */
221- AwsCrtHttpClient . Builder proxyConfiguration (ProxyConfiguration proxyConfiguration );
229+ Builder proxyConfiguration (ProxyConfiguration proxyConfiguration );
222230
223231 /**
224232 * Sets the http proxy configuration to use for this client.
225233 *
226234 * @param proxyConfigurationBuilderConsumer The consumer of the proxy configuration builder object.
227235 * @return the builder for method chaining.
228236 */
229- AwsCrtHttpClient . Builder proxyConfiguration (Consumer <ProxyConfiguration .Builder > proxyConfigurationBuilderConsumer );
237+ Builder proxyConfiguration (Consumer <ProxyConfiguration .Builder > proxyConfigurationBuilderConsumer );
230238
231239 /**
232240 * Configure the health checks for all connections established by this client.
@@ -246,7 +254,7 @@ public interface Builder extends SdkHttpClient.Builder<AwsCrtHttpClient.Builder>
246254 * @param healthChecksConfiguration The health checks config to use
247255 * @return The builder of the method chaining.
248256 */
249- AwsCrtHttpClient . Builder connectionHealthConfiguration (ConnectionHealthConfiguration healthChecksConfiguration );
257+ Builder connectionHealthConfiguration (ConnectionHealthConfiguration healthChecksConfiguration );
250258
251259 /**
252260 * A convenience method that creates an instance of the {@link ConnectionHealthConfiguration} builder, avoiding the
@@ -256,29 +264,29 @@ public interface Builder extends SdkHttpClient.Builder<AwsCrtHttpClient.Builder>
256264 * @return The builder of the method chaining.
257265 * @see #connectionHealthConfiguration(ConnectionHealthConfiguration)
258266 */
259- AwsCrtHttpClient . Builder connectionHealthConfiguration (Consumer <ConnectionHealthConfiguration .Builder >
267+ Builder connectionHealthConfiguration (Consumer <ConnectionHealthConfiguration .Builder >
260268 healthChecksConfigurationBuilder );
261269
262270 /**
263271 * Configure the maximum amount of time that a connection should be allowed to remain open while idle.
264272 * @param connectionMaxIdleTime the maximum amount of connection idle time
265273 * @return The builder of the method chaining.
266274 */
267- AwsCrtHttpClient . Builder connectionMaxIdleTime (Duration connectionMaxIdleTime );
275+ Builder connectionMaxIdleTime (Duration connectionMaxIdleTime );
268276
269277 /**
270278 * The amount of time to wait when initially establishing a connection before giving up and timing out.
271279 * @param connectionTimeout timeout
272280 * @return The builder of the method chaining.
273281 */
274- AwsCrtHttpClient . Builder connectionTimeout (Duration connectionTimeout );
282+ Builder connectionTimeout (Duration connectionTimeout );
275283
276284 /**
277285 * The amount of time to wait when acquiring a connection from the pool before giving up and timing out.
278286 * @param connectionAcquisitionTimeout the timeout duration
279287 * @return this builder for method chaining.
280288 */
281- AwsCrtHttpClient . Builder connectionAcquisitionTimeout (Duration connectionAcquisitionTimeout );
289+ Builder connectionAcquisitionTimeout (Duration connectionAcquisitionTimeout );
282290
283291 /**
284292 * Configure whether to enable {@code tcpKeepAlive} and relevant configuration for all connections established by this
@@ -292,7 +300,7 @@ AwsCrtHttpClient.Builder connectionHealthConfiguration(Consumer<ConnectionHealth
292300 * @param tcpKeepAliveConfiguration The TCP keep-alive configuration to use
293301 * @return The builder of the method chaining.
294302 */
295- AwsCrtHttpClient . Builder tcpKeepAliveConfiguration (TcpKeepAliveConfiguration tcpKeepAliveConfiguration );
303+ Builder tcpKeepAliveConfiguration (TcpKeepAliveConfiguration tcpKeepAliveConfiguration );
296304
297305 /**
298306 * Configure whether to enable {@code tcpKeepAlive} and relevant configuration for all connections established by this
@@ -306,7 +314,7 @@ AwsCrtHttpClient.Builder connectionHealthConfiguration(Consumer<ConnectionHealth
306314 * @return The builder of the method chaining.
307315 * @see #tcpKeepAliveConfiguration(TcpKeepAliveConfiguration)
308316 */
309- AwsCrtHttpClient . Builder tcpKeepAliveConfiguration (Consumer <TcpKeepAliveConfiguration .Builder >
317+ Builder tcpKeepAliveConfiguration (Consumer <TcpKeepAliveConfiguration .Builder >
310318 tcpKeepAliveConfigurationBuilder );
311319
312320 /**
@@ -325,15 +333,15 @@ AwsCrtHttpClient.Builder tcpKeepAliveConfiguration(Consumer<TcpKeepAliveConfigur
325333 * @param postQuantumTlsEnabled whether to prefer Post Quantum TLS
326334 * @return The builder of the method chaining.
327335 */
328- AwsCrtHttpClient . Builder postQuantumTlsEnabled (Boolean postQuantumTlsEnabled );
336+ Builder postQuantumTlsEnabled (Boolean postQuantumTlsEnabled );
329337 }
330338
331339 /**
332340 * Factory that allows more advanced configuration of the AWS CRT HTTP implementation.
333341 * Use {@link #builder()} to configure and construct an immutable instance of the factory.
334342 */
335343 private static final class DefaultBuilder
336- extends AwsCrtClientBuilderBase <AwsCrtHttpClient . Builder > implements AwsCrtHttpClient . Builder {
344+ extends AwsCrtClientBuilderBase <Builder > implements Builder {
337345
338346
339347 @ Override
0 commit comments