1 /* 2 * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"). 5 * You may not use this file except in compliance with the License. 6 * A copy of the License is located at 7 * 8 * http://aws.amazon.com/apache2.0 9 * 10 * or in the "license" file accompanying this file. This file is distributed 11 * on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either 12 * express or implied. See the License for the specific language governing 13 * permissions and limitations under the License. 14 */ 15 16 package software.amazon.awssdk.http.crt; 17 18 import static software.amazon.awssdk.http.HttpMetric.HTTP_CLIENT_NAME; 19 import static software.amazon.awssdk.utils.Validate.paramNotNull; 20 21 import java.time.Duration; 22 import java.util.concurrent.CompletableFuture; 23 import java.util.function.Consumer; 24 import software.amazon.awssdk.annotations.SdkPublicApi; 25 import software.amazon.awssdk.crt.http.HttpClientConnectionManager; 26 import software.amazon.awssdk.http.SdkHttpConfigurationOption; 27 import software.amazon.awssdk.http.async.AsyncExecuteRequest; 28 import software.amazon.awssdk.http.async.SdkAsyncHttpClient; 29 import software.amazon.awssdk.http.crt.internal.AwsCrtClientBuilderBase; 30 import software.amazon.awssdk.http.crt.internal.CrtAsyncRequestContext; 31 import software.amazon.awssdk.http.crt.internal.CrtAsyncRequestExecutor; 32 import software.amazon.awssdk.utils.AttributeMap; 33 34 /** 35 * An implementation of {@link SdkAsyncHttpClient} that uses the AWS Common Runtime (CRT) Http Client to communicate with 36 * Http Web Services. This client is asynchronous and uses non-blocking IO. 37 * 38 * <p>This can be created via {@link #builder()}</p> 39 * {@snippet : 40 SdkAsyncHttpClient client = AwsCrtAsyncHttpClient.builder() 41 .maxConcurrency(100) 42 .connectionTimeout(Duration.ofSeconds(1)) 43 .connectionMaxIdleTime(Duration.ofSeconds(5)) 44 .build(); 45 * } 46 * 47 */ 48 @SdkPublicApi 49 public final class AwsCrtAsyncHttpClient extends AwsCrtHttpClientBase implements SdkAsyncHttpClient { 50 AwsCrtAsyncHttpClient(DefaultAsyncBuilder builder, AttributeMap config)51 private AwsCrtAsyncHttpClient(DefaultAsyncBuilder builder, AttributeMap config) { 52 super(builder, config); 53 } 54 builder()55 public static AwsCrtAsyncHttpClient.Builder builder() { 56 return new DefaultAsyncBuilder(); 57 } 58 59 /** 60 * Create a {@link AwsCrtAsyncHttpClient} client with the default configuration 61 * 62 * @return an {@link SdkAsyncHttpClient} 63 */ create()64 public static SdkAsyncHttpClient create() { 65 return new DefaultAsyncBuilder().build(); 66 } 67 68 @Override clientName()69 public String clientName() { 70 return super.clientName(); 71 } 72 73 @Override execute(AsyncExecuteRequest asyncRequest)74 public CompletableFuture<Void> execute(AsyncExecuteRequest asyncRequest) { 75 76 paramNotNull(asyncRequest, "asyncRequest"); 77 paramNotNull(asyncRequest.request(), "SdkHttpRequest"); 78 paramNotNull(asyncRequest.requestContentPublisher(), "RequestContentPublisher"); 79 paramNotNull(asyncRequest.responseHandler(), "ResponseHandler"); 80 81 asyncRequest.metricCollector() 82 .ifPresent(metricCollector -> metricCollector.reportMetric(HTTP_CLIENT_NAME, clientName())); 83 84 /* 85 * See the note on getOrCreateConnectionPool() 86 * 87 * In particular, this returns a ref-counted object and calling getOrCreateConnectionPool 88 * increments the ref count by one. We add a try-with-resources to release our ref 89 * once we have successfully submitted a request. In this way, we avoid a race condition 90 * when close/shutdown is called from another thread while this function is executing (ie. 91 * we have a pool and no one can destroy it underneath us until we've finished submitting the 92 * request) 93 */ 94 try (HttpClientConnectionManager crtConnPool = getOrCreateConnectionPool(poolKey(asyncRequest.request()))) { 95 CrtAsyncRequestContext context = CrtAsyncRequestContext.builder() 96 .crtConnPool(crtConnPool) 97 .readBufferSize(this.readBufferSize) 98 .request(asyncRequest) 99 .build(); 100 101 return new CrtAsyncRequestExecutor().execute(context); 102 } 103 } 104 105 /** 106 * Builder that allows configuration of the AWS CRT HTTP implementation. 107 */ 108 public interface Builder extends SdkAsyncHttpClient.Builder<AwsCrtAsyncHttpClient.Builder> { 109 110 /** 111 * The Maximum number of allowed concurrent requests. For HTTP/1.1 this is the same as max connections. 112 * @param maxConcurrency maximum concurrency per endpoint 113 * @return The builder of the method chaining. 114 */ maxConcurrency(Integer maxConcurrency)115 AwsCrtAsyncHttpClient.Builder maxConcurrency(Integer maxConcurrency); 116 117 /** 118 * Configures the number of unread bytes that can be buffered in the 119 * client before we stop reading from the underlying TCP socket and wait for the Subscriber 120 * to read more data. 121 * 122 * @param readBufferSize The number of bytes that can be buffered. 123 * @return The builder of the method chaining. 124 */ readBufferSizeInBytes(Long readBufferSize)125 AwsCrtAsyncHttpClient.Builder readBufferSizeInBytes(Long readBufferSize); 126 127 /** 128 * Sets the http proxy configuration to use for this client. 129 * @param proxyConfiguration The http proxy configuration to use 130 * @return The builder of the method chaining. 131 */ proxyConfiguration(ProxyConfiguration proxyConfiguration)132 AwsCrtAsyncHttpClient.Builder proxyConfiguration(ProxyConfiguration proxyConfiguration); 133 134 /** 135 * Sets the http proxy configuration to use for this client. 136 * 137 * @param proxyConfigurationBuilderConsumer The consumer of the proxy configuration builder object. 138 * @return the builder for method chaining. 139 */ proxyConfiguration(Consumer<ProxyConfiguration.Builder> proxyConfigurationBuilderConsumer)140 AwsCrtAsyncHttpClient.Builder proxyConfiguration(Consumer<ProxyConfiguration.Builder> proxyConfigurationBuilderConsumer); 141 142 /** 143 * Configure the health checks for all connections established by this client. 144 * 145 * <p> 146 * You can set a throughput threshold for a connection to be considered healthy. 147 * If a connection falls below this threshold ({@link ConnectionHealthConfiguration#minimumThroughputInBps() 148 * }) for the configurable amount 149 * of time ({@link ConnectionHealthConfiguration#minimumThroughputTimeout()}), 150 * then the connection is considered unhealthy and will be shut down. 151 * 152 * <p> 153 * By default, monitoring options are disabled. You can enable {@code healthChecks} by providing this configuration 154 * and specifying the options for monitoring for the connection manager. 155 * @param healthChecksConfiguration The health checks config to use 156 * @return The builder of the method chaining. 157 */ connectionHealthConfiguration(ConnectionHealthConfiguration healthChecksConfiguration)158 AwsCrtAsyncHttpClient.Builder connectionHealthConfiguration(ConnectionHealthConfiguration healthChecksConfiguration); 159 160 /** 161 * A convenience method that creates an instance of the {@link ConnectionHealthConfiguration} builder, avoiding the 162 * need to create one manually via {@link ConnectionHealthConfiguration#builder()}. 163 * 164 * @param healthChecksConfigurationBuilder The health checks config builder to use 165 * @return The builder of the method chaining. 166 * @see #connectionHealthConfiguration(ConnectionHealthConfiguration) 167 */ connectionHealthConfiguration(Consumer<ConnectionHealthConfiguration.Builder> healthChecksConfigurationBuilder)168 AwsCrtAsyncHttpClient.Builder connectionHealthConfiguration(Consumer<ConnectionHealthConfiguration.Builder> 169 healthChecksConfigurationBuilder); 170 171 /** 172 * Configure the maximum amount of time that a connection should be allowed to remain open while idle. 173 * @param connectionMaxIdleTime the maximum amount of connection idle time 174 * @return The builder of the method chaining. 175 */ connectionMaxIdleTime(Duration connectionMaxIdleTime)176 AwsCrtAsyncHttpClient.Builder connectionMaxIdleTime(Duration connectionMaxIdleTime); 177 178 /** 179 * The amount of time to wait when initially establishing a connection before giving up and timing out. 180 * @param connectionTimeout timeout 181 * @return The builder of the method chaining. 182 */ connectionTimeout(Duration connectionTimeout)183 AwsCrtAsyncHttpClient.Builder connectionTimeout(Duration connectionTimeout); 184 185 /** 186 * Configure whether to enable {@code tcpKeepAlive} and relevant configuration for all connections established by this 187 * client. 188 * 189 * <p> 190 * By default, tcpKeepAlive is disabled. You can enable {@code tcpKeepAlive} by providing this configuration 191 * and specifying periodic TCP keepalive packet intervals and timeouts. This may be required for certain connections for 192 * longer durations than default socket timeouts. 193 * 194 * @param tcpKeepAliveConfiguration The TCP keep-alive configuration to use 195 * @return The builder of the method chaining. 196 */ tcpKeepAliveConfiguration(TcpKeepAliveConfiguration tcpKeepAliveConfiguration)197 AwsCrtAsyncHttpClient.Builder tcpKeepAliveConfiguration(TcpKeepAliveConfiguration tcpKeepAliveConfiguration); 198 199 /** 200 * Configure whether to enable {@code tcpKeepAlive} and relevant configuration for all connections established by this 201 * client. 202 * 203 * <p> 204 * A convenience method that creates an instance of the {@link TcpKeepAliveConfiguration} builder, avoiding the 205 * need to create one manually via {@link TcpKeepAliveConfiguration#builder()}. 206 * 207 * @param tcpKeepAliveConfigurationBuilder The TCP keep-alive configuration builder to use 208 * @return The builder of the method chaining. 209 * @see #tcpKeepAliveConfiguration(TcpKeepAliveConfiguration) 210 */ tcpKeepAliveConfiguration(Consumer<TcpKeepAliveConfiguration.Builder> tcpKeepAliveConfigurationBuilder)211 AwsCrtAsyncHttpClient.Builder tcpKeepAliveConfiguration(Consumer<TcpKeepAliveConfiguration.Builder> 212 tcpKeepAliveConfigurationBuilder); 213 214 /** 215 * Configure whether to enable a hybrid post-quantum key exchange option for the Transport Layer Security (TLS) network 216 * encryption protocol when communicating with services that support Post Quantum TLS. If Post Quantum cipher suites are 217 * not supported on the platform, the SDK will use the default TLS cipher suites. 218 * 219 * <p> 220 * See <a href="https://docs.aws.amazon.com/kms/latest/developerguide/pqtls.html">Using hybrid post-quantum TLS with AWS KMS</a> 221 * 222 * <p> 223 * It's disabled by default. 224 * 225 * @param postQuantumTlsEnabled whether to prefer Post Quantum TLS 226 * @return The builder of the method chaining. 227 */ postQuantumTlsEnabled(Boolean postQuantumTlsEnabled)228 AwsCrtAsyncHttpClient.Builder postQuantumTlsEnabled(Boolean postQuantumTlsEnabled); 229 } 230 231 /** 232 * Factory that allows more advanced configuration of the AWS CRT HTTP implementation. Use {@link #builder()} to 233 * configure and construct an immutable instance of the factory. 234 */ 235 private static final class DefaultAsyncBuilder 236 extends AwsCrtClientBuilderBase<AwsCrtAsyncHttpClient.Builder> implements Builder { 237 238 @Override build()239 public SdkAsyncHttpClient build() { 240 return new AwsCrtAsyncHttpClient(this, getAttributeMap().build() 241 .merge(SdkHttpConfigurationOption.GLOBAL_HTTP_DEFAULTS)); 242 } 243 244 @Override buildWithDefaults(AttributeMap serviceDefaults)245 public SdkAsyncHttpClient buildWithDefaults(AttributeMap serviceDefaults) { 246 return new AwsCrtAsyncHttpClient(this, getAttributeMap().build() 247 .merge(serviceDefaults) 248 .merge(SdkHttpConfigurationOption.GLOBAL_HTTP_DEFAULTS)); 249 } 250 } 251 } 252