1 /** 2 * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. 3 * SPDX-License-Identifier: Apache-2.0. 4 */ 5 package software.amazon.awssdk.crt.http; 6 7 import java.net.URI; 8 import software.amazon.awssdk.crt.io.ClientBootstrap; 9 import software.amazon.awssdk.crt.io.SocketOptions; 10 import software.amazon.awssdk.crt.io.TlsConnectionOptions; 11 import software.amazon.awssdk.crt.io.TlsContext; 12 13 /** 14 * Contains all the configuration options for a HttpConnectionPoolManager instance 15 */ 16 public class HttpClientConnectionManagerOptions { 17 public static final int DEFAULT_MAX_BUFFER_SIZE = 16 * 1024; 18 public static final long DEFAULT_MAX_WINDOW_SIZE = Integer.MAX_VALUE; 19 public static final int DEFAULT_MAX_CONNECTIONS = 2; 20 21 private ClientBootstrap clientBootstrap; 22 private SocketOptions socketOptions; 23 private TlsContext tlsContext; 24 private TlsConnectionOptions tlsConnectionOptions; 25 private long windowSize = DEFAULT_MAX_WINDOW_SIZE; 26 private int bufferSize = DEFAULT_MAX_BUFFER_SIZE; 27 private URI uri; 28 private int port = -1; 29 private int maxConnections = DEFAULT_MAX_CONNECTIONS; 30 private HttpProxyOptions proxyOptions; 31 private HttpProxyEnvironmentVariableSetting httpProxyEnvironmentVariableSetting; 32 private boolean manualWindowManagement = false; 33 private HttpMonitoringOptions monitoringOptions; 34 private long maxConnectionIdleInMilliseconds = 0; 35 private HttpVersion expectedHttpVersion = HttpVersion.HTTP_1_1; 36 37 private static final String HTTP = "http"; 38 private static final String HTTPS = "https"; 39 40 /** 41 * Default constructor 42 */ HttpClientConnectionManagerOptions()43 public HttpClientConnectionManagerOptions() { 44 } 45 46 /** 47 * Sets the client bootstrap instance to use to create the pool's connections 48 * @param clientBootstrap ClientBootstrap to use 49 * @return this 50 */ withClientBootstrap(ClientBootstrap clientBootstrap)51 public HttpClientConnectionManagerOptions withClientBootstrap(ClientBootstrap clientBootstrap) { 52 this.clientBootstrap = clientBootstrap; 53 return this; 54 } 55 56 /** 57 * Gets the client bootstrap instance to use to create the pool's connections 58 * @return ClientBootstrap used by this connection manager 59 */ getClientBootstrap()60 public ClientBootstrap getClientBootstrap() { return clientBootstrap; } 61 62 /** 63 * Sets the socket options to use for connections in the connection pool 64 * @param socketOptions The socket options to use for all connections in the manager 65 * @return this 66 */ withSocketOptions(SocketOptions socketOptions)67 public HttpClientConnectionManagerOptions withSocketOptions(SocketOptions socketOptions) { 68 this.socketOptions = socketOptions; 69 return this; 70 } 71 72 /** 73 * @return the socket options to use for connections in the connection pool 74 */ getSocketOptions()75 public SocketOptions getSocketOptions() { return socketOptions; } 76 77 /** 78 * Sets the tls context to use for connections in the connection pool 79 * @param tlsContext The TlsContext to use 80 * @return this 81 */ withTlsContext(TlsContext tlsContext)82 public HttpClientConnectionManagerOptions withTlsContext(TlsContext tlsContext) { 83 this.tlsContext = tlsContext; 84 return this; 85 } 86 87 /** 88 * @return the tls context used by connections in the connection pool 89 */ getTlsContext()90 public TlsContext getTlsContext() { return tlsContext; } 91 92 /** 93 * Sets the connection-specific TLS options to use for connections in the connection pool. 94 * Either TLS context or TLS connection options will be enough to set up TLS connection. 95 * If both set, an exception will be raised. 96 * @param tlsConnectionOptions The TlsConnectionOptions to use 97 * @return this 98 */ withTlsConnectionOptions(TlsConnectionOptions tlsConnectionOptions)99 public HttpClientConnectionManagerOptions withTlsConnectionOptions(TlsConnectionOptions tlsConnectionOptions) { 100 this.tlsConnectionOptions = tlsConnectionOptions; 101 return this; 102 } 103 104 /** 105 * @return the tls context used by connections in the connection pool 106 */ getTlsConnectionOptions()107 public TlsConnectionOptions getTlsConnectionOptions() { return tlsConnectionOptions; } 108 109 /** 110 * Sets the starting size of each HTTP stream's flow-control window. 111 * This is only used when "manual window management" is enabled. 112 * 113 * @param windowSize The initial window size for each HTTP stream 114 * @return this 115 * @see #withManualWindowManagement 116 */ withWindowSize(long windowSize)117 public HttpClientConnectionManagerOptions withWindowSize(long windowSize) { 118 this.windowSize = windowSize; 119 return this; 120 } 121 122 /** 123 * @return The starting size of each HTTP stream's flow-control window. 124 */ getWindowSize()125 public long getWindowSize() { return windowSize; } 126 127 /** 128 * @deprecated Sets the IO buffer size to use for connections in the connection pool 129 * @param bufferSize Size of I/O buffer per connection 130 * @return this 131 */ withBufferSize(int bufferSize)132 public HttpClientConnectionManagerOptions withBufferSize(int bufferSize) { 133 this.bufferSize = bufferSize; 134 return this; 135 } 136 137 /** 138 * @deprecated 139 * @return the IO buffer size to use for connections in the connection pool 140 */ getBufferSize()141 public int getBufferSize() { return bufferSize; } 142 143 /** 144 * Sets the URI to use for connections in the connection pool 145 * @param uri The endpoint URI to connect to 146 * @return this 147 */ withUri(URI uri)148 public HttpClientConnectionManagerOptions withUri(URI uri) { 149 this.uri = uri; 150 return this; 151 } 152 153 /** 154 * @return the URI to use for connections in the connection pool 155 */ getUri()156 public URI getUri() { return uri; } 157 158 /** 159 * Sets the port to connect to for connections in the connection pool. 160 * For 32bit values exceeding Integer.MAX_VALUE use two's complement 161 * (i.e. -1 == 0xFFFFFFFF). 162 * @param port The port to connect to 163 * @return this 164 */ withPort(int port)165 public HttpClientConnectionManagerOptions withPort(int port) { 166 this.port = port; 167 return this; 168 } 169 170 /** 171 * @return the port to connect to for connections in the connection pool. 172 * Returns -1 if none has been explicitly set. 173 * Note that two's complement is used for 32bit values exceeding 174 * Integer.MAX_VALUE (i.e. -1 == 0xFFFFFFFF). 175 */ getPort()176 public int getPort() { return port; } 177 178 /** 179 * Sets the maximum number of connections allowed in the connection pool 180 * @param maxConnections maximum number of connections to pool 181 * @return this 182 */ withMaxConnections(int maxConnections)183 public HttpClientConnectionManagerOptions withMaxConnections(int maxConnections) { 184 this.maxConnections = maxConnections; 185 return this; 186 } 187 188 /** 189 * @return the maximum number of connections allowed in the connection pool 190 */ getMaxConnections()191 public int getMaxConnections() { return maxConnections; } 192 193 /** 194 * Sets the proxy options for connections in the connection pool 195 * @param proxyOptions HttpProxyOptions for this connection manager, or null to disable proxying 196 * @return this 197 */ withProxyOptions(HttpProxyOptions proxyOptions)198 public HttpClientConnectionManagerOptions withProxyOptions(HttpProxyOptions proxyOptions) { 199 this.proxyOptions = proxyOptions; 200 return this; 201 } 202 203 /** 204 * @return the proxy options for connections in the connection pool 205 */ getProxyOptions()206 public HttpProxyOptions getProxyOptions() { return proxyOptions; } 207 208 /** 209 * Optional. 210 * Sets how proxy is fetched from the environment. 211 * Reading proxy configuration from environment is disabled if this is NULL for backward compatibility. 212 * Only works when proxyOptions is not set. The proxy settings follow the following precedence 213 * 1. Configured Proxy Setting 214 * 2. Environment (if enabled) 215 * 3. No proxy 216 * @param httpProxyEnvironmentVariableSetting for this connection manager 217 * @return this 218 */ withProxyEnvironmentVariableSetting( HttpProxyEnvironmentVariableSetting httpProxyEnvironmentVariableSetting)219 public HttpClientConnectionManagerOptions withProxyEnvironmentVariableSetting( 220 HttpProxyEnvironmentVariableSetting httpProxyEnvironmentVariableSetting) { 221 this.httpProxyEnvironmentVariableSetting = httpProxyEnvironmentVariableSetting; 222 return this; 223 } 224 225 /** 226 * @return the proxy environment variable setting 227 */ getHttpProxyEnvironmentVariableSetting()228 public HttpProxyEnvironmentVariableSetting getHttpProxyEnvironmentVariableSetting() { 229 return httpProxyEnvironmentVariableSetting; 230 } 231 232 /** 233 * @return true if manual window management is used, false otherwise 234 * @see #withManualWindowManagement 235 */ isManualWindowManagement()236 public boolean isManualWindowManagement() { return manualWindowManagement; } 237 238 /** 239 * If set to true, then you must manage the read backpressure mechanism. You should 240 * only use this if you're allowing http response body data to escape the callbacks. E.g. you're 241 * putting the data into a queue for another thread to process and need to make sure the memory 242 * usage is bounded (e.g. reactive streams). 243 * <p> 244 * When enabled, each HttpStream has a flow-control window that shrinks as response body data is downloaded 245 * (headers do not affect the window). {@link #withWindowSize} determines the starting size of each 246 * HttpStream's window, in bytes. Data stops downloading whenever the window reaches zero. 247 * Increment the window to keep data flowing by calling {@link HttpStreamBase#incrementWindow}, 248 * or by returning a size from {@link HttpStreamResponseHandler#onResponseBody}. 249 * Maintain a larger window to keep up a high download throughput, 250 * or use a smaller window to limit how much data could get buffered in memory. 251 * 252 * @param manualWindowManagement true to enable manual window management, false to use automatic window management 253 * @return this 254 */ withManualWindowManagement(boolean manualWindowManagement)255 public HttpClientConnectionManagerOptions withManualWindowManagement(boolean manualWindowManagement) { 256 this.manualWindowManagement = manualWindowManagement; 257 return this; 258 } 259 260 /** 261 * Set the expected protocol version of the connection to be made, default is HTTP/1.1 262 * 263 * @param expectedHttpVersion The expected protocol version of the connection made 264 * @return this 265 */ withExpectedHttpVersion(HttpVersion expectedHttpVersion)266 public HttpClientConnectionManagerOptions withExpectedHttpVersion(HttpVersion expectedHttpVersion) { 267 this.expectedHttpVersion = expectedHttpVersion; 268 return this; 269 } 270 271 /** 272 * @return Return the expected HTTP protocol version. 273 */ getExpectedHttpVersion()274 public HttpVersion getExpectedHttpVersion() { 275 return expectedHttpVersion; 276 } 277 278 /** 279 * Sets maximum amount of time, in milliseconds, that the connection can be idle in the manager before 280 * getting culled by the manager 281 * @param maxConnectionIdleInMilliseconds How long to allow connections to be idle before reaping them 282 * @return this 283 */ withMaxConnectionIdleInMilliseconds(long maxConnectionIdleInMilliseconds)284 public HttpClientConnectionManagerOptions withMaxConnectionIdleInMilliseconds(long maxConnectionIdleInMilliseconds) { 285 this.maxConnectionIdleInMilliseconds = maxConnectionIdleInMilliseconds; 286 return this; 287 } 288 289 /** 290 * @return How long to allow connections to be idle before reaping them 291 */ getMaxConnectionIdleInMilliseconds()292 public long getMaxConnectionIdleInMilliseconds() { return maxConnectionIdleInMilliseconds; } 293 294 /** 295 * Sets the monitoring options for connections in the connection pool 296 * @param monitoringOptions Monitoring options for this connection manager, or null to disable monitoring 297 * @return this 298 */ withMonitoringOptions(HttpMonitoringOptions monitoringOptions)299 public HttpClientConnectionManagerOptions withMonitoringOptions(HttpMonitoringOptions monitoringOptions) { 300 this.monitoringOptions = monitoringOptions; 301 return this; 302 } 303 304 /** 305 * @return the monitoring options for connections in the connection pool 306 */ getMonitoringOptions()307 public HttpMonitoringOptions getMonitoringOptions() { return monitoringOptions; } 308 309 /** 310 * Validate the connection manager options are valid to use. Throw exceptions if not. 311 */ validateOptions()312 public void validateOptions() { 313 URI uri = this.getUri(); 314 if (uri == null) { throw new IllegalArgumentException("URI must not be null"); } 315 if (uri.getScheme() == null) { throw new IllegalArgumentException("URI does not have a Scheme"); } 316 if (!HTTP.equals(uri.getScheme()) && !HTTPS.equals(uri.getScheme())) { throw new IllegalArgumentException("URI has unknown Scheme"); } 317 if (uri.getHost() == null) { throw new IllegalArgumentException("URI does not have a Host name"); } 318 319 if (clientBootstrap == null) { throw new IllegalArgumentException("ClientBootstrap must not be null"); } 320 321 if (socketOptions == null) { throw new IllegalArgumentException("SocketOptions must not be null"); } 322 323 if(tlsContext!= null && tlsConnectionOptions != null) { 324 throw new IllegalArgumentException("Cannot set both TlsContext and TlsConnectionOptions."); 325 } 326 boolean useTls = HTTPS.equals(uri.getScheme()); 327 boolean tlsSet = (tlsContext!= null || tlsConnectionOptions != null); 328 if (useTls && !tlsSet) { throw new IllegalArgumentException("TlsContext or TlsConnectionOptions must not be null if https is used"); } 329 330 if (windowSize <= 0) { throw new IllegalArgumentException("Window Size must be greater than zero."); } 331 332 if (maxConnections <= 0) { throw new IllegalArgumentException("Max Connections must be greater than zero."); } 333 } 334 } 335