/** * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. * SPDX-License-Identifier: Apache-2.0. */ package software.amazon.awssdk.crt.http; import java.net.URI; import software.amazon.awssdk.crt.io.ClientBootstrap; import software.amazon.awssdk.crt.io.SocketOptions; import software.amazon.awssdk.crt.io.TlsConnectionOptions; import software.amazon.awssdk.crt.io.TlsContext; /** * Contains all the configuration options for a HttpConnectionPoolManager instance */ public class HttpClientConnectionManagerOptions { public static final int DEFAULT_MAX_BUFFER_SIZE = 16 * 1024; public static final long DEFAULT_MAX_WINDOW_SIZE = Integer.MAX_VALUE; public static final int DEFAULT_MAX_CONNECTIONS = 2; private ClientBootstrap clientBootstrap; private SocketOptions socketOptions; private TlsContext tlsContext; private TlsConnectionOptions tlsConnectionOptions; private long windowSize = DEFAULT_MAX_WINDOW_SIZE; private int bufferSize = DEFAULT_MAX_BUFFER_SIZE; private URI uri; private int port = -1; private int maxConnections = DEFAULT_MAX_CONNECTIONS; private HttpProxyOptions proxyOptions; private HttpProxyEnvironmentVariableSetting httpProxyEnvironmentVariableSetting; private boolean manualWindowManagement = false; private HttpMonitoringOptions monitoringOptions; private long maxConnectionIdleInMilliseconds = 0; private HttpVersion expectedHttpVersion = HttpVersion.HTTP_1_1; private static final String HTTP = "http"; private static final String HTTPS = "https"; /** * Default constructor */ public HttpClientConnectionManagerOptions() { } /** * Sets the client bootstrap instance to use to create the pool's connections * @param clientBootstrap ClientBootstrap to use * @return this */ public HttpClientConnectionManagerOptions withClientBootstrap(ClientBootstrap clientBootstrap) { this.clientBootstrap = clientBootstrap; return this; } /** * Gets the client bootstrap instance to use to create the pool's connections * @return ClientBootstrap used by this connection manager */ public ClientBootstrap getClientBootstrap() { return clientBootstrap; } /** * Sets the socket options to use for connections in the connection pool * @param socketOptions The socket options to use for all connections in the manager * @return this */ public HttpClientConnectionManagerOptions withSocketOptions(SocketOptions socketOptions) { this.socketOptions = socketOptions; return this; } /** * @return the socket options to use for connections in the connection pool */ public SocketOptions getSocketOptions() { return socketOptions; } /** * Sets the tls context to use for connections in the connection pool * @param tlsContext The TlsContext to use * @return this */ public HttpClientConnectionManagerOptions withTlsContext(TlsContext tlsContext) { this.tlsContext = tlsContext; return this; } /** * @return the tls context used by connections in the connection pool */ public TlsContext getTlsContext() { return tlsContext; } /** * Sets the connection-specific TLS options to use for connections in the connection pool. * Either TLS context or TLS connection options will be enough to set up TLS connection. * If both set, an exception will be raised. * @param tlsConnectionOptions The TlsConnectionOptions to use * @return this */ public HttpClientConnectionManagerOptions withTlsConnectionOptions(TlsConnectionOptions tlsConnectionOptions) { this.tlsConnectionOptions = tlsConnectionOptions; return this; } /** * @return the tls context used by connections in the connection pool */ public TlsConnectionOptions getTlsConnectionOptions() { return tlsConnectionOptions; } /** * Sets the starting size of each HTTP stream's flow-control window. * This is only used when "manual window management" is enabled. * * @param windowSize The initial window size for each HTTP stream * @return this * @see #withManualWindowManagement */ public HttpClientConnectionManagerOptions withWindowSize(long windowSize) { this.windowSize = windowSize; return this; } /** * @return The starting size of each HTTP stream's flow-control window. */ public long getWindowSize() { return windowSize; } /** * @deprecated Sets the IO buffer size to use for connections in the connection pool * @param bufferSize Size of I/O buffer per connection * @return this */ public HttpClientConnectionManagerOptions withBufferSize(int bufferSize) { this.bufferSize = bufferSize; return this; } /** * @deprecated * @return the IO buffer size to use for connections in the connection pool */ public int getBufferSize() { return bufferSize; } /** * Sets the URI to use for connections in the connection pool * @param uri The endpoint URI to connect to * @return this */ public HttpClientConnectionManagerOptions withUri(URI uri) { this.uri = uri; return this; } /** * @return the URI to use for connections in the connection pool */ public URI getUri() { return uri; } /** * Sets the port to connect to for connections in the connection pool. * For 32bit values exceeding Integer.MAX_VALUE use two's complement * (i.e. -1 == 0xFFFFFFFF). * @param port The port to connect to * @return this */ public HttpClientConnectionManagerOptions withPort(int port) { this.port = port; return this; } /** * @return the port to connect to for connections in the connection pool. * Returns -1 if none has been explicitly set. * Note that two's complement is used for 32bit values exceeding * Integer.MAX_VALUE (i.e. -1 == 0xFFFFFFFF). */ public int getPort() { return port; } /** * Sets the maximum number of connections allowed in the connection pool * @param maxConnections maximum number of connections to pool * @return this */ public HttpClientConnectionManagerOptions withMaxConnections(int maxConnections) { this.maxConnections = maxConnections; return this; } /** * @return the maximum number of connections allowed in the connection pool */ public int getMaxConnections() { return maxConnections; } /** * Sets the proxy options for connections in the connection pool * @param proxyOptions HttpProxyOptions for this connection manager, or null to disable proxying * @return this */ public HttpClientConnectionManagerOptions withProxyOptions(HttpProxyOptions proxyOptions) { this.proxyOptions = proxyOptions; return this; } /** * @return the proxy options for connections in the connection pool */ public HttpProxyOptions getProxyOptions() { return proxyOptions; } /** * Optional. * Sets how proxy is fetched from the environment. * Reading proxy configuration from environment is disabled if this is NULL for backward compatibility. * Only works when proxyOptions is not set. The proxy settings follow the following precedence * 1. Configured Proxy Setting * 2. Environment (if enabled) * 3. No proxy * @param httpProxyEnvironmentVariableSetting for this connection manager * @return this */ public HttpClientConnectionManagerOptions withProxyEnvironmentVariableSetting( HttpProxyEnvironmentVariableSetting httpProxyEnvironmentVariableSetting) { this.httpProxyEnvironmentVariableSetting = httpProxyEnvironmentVariableSetting; return this; } /** * @return the proxy environment variable setting */ public HttpProxyEnvironmentVariableSetting getHttpProxyEnvironmentVariableSetting() { return httpProxyEnvironmentVariableSetting; } /** * @return true if manual window management is used, false otherwise * @see #withManualWindowManagement */ public boolean isManualWindowManagement() { return manualWindowManagement; } /** * If set to true, then you must manage the read backpressure mechanism. You should * only use this if you're allowing http response body data to escape the callbacks. E.g. you're * putting the data into a queue for another thread to process and need to make sure the memory * usage is bounded (e.g. reactive streams). *

* When enabled, each HttpStream has a flow-control window that shrinks as response body data is downloaded * (headers do not affect the window). {@link #withWindowSize} determines the starting size of each * HttpStream's window, in bytes. Data stops downloading whenever the window reaches zero. * Increment the window to keep data flowing by calling {@link HttpStreamBase#incrementWindow}, * or by returning a size from {@link HttpStreamResponseHandler#onResponseBody}. * Maintain a larger window to keep up a high download throughput, * or use a smaller window to limit how much data could get buffered in memory. * * @param manualWindowManagement true to enable manual window management, false to use automatic window management * @return this */ public HttpClientConnectionManagerOptions withManualWindowManagement(boolean manualWindowManagement) { this.manualWindowManagement = manualWindowManagement; return this; } /** * Set the expected protocol version of the connection to be made, default is HTTP/1.1 * * @param expectedHttpVersion The expected protocol version of the connection made * @return this */ public HttpClientConnectionManagerOptions withExpectedHttpVersion(HttpVersion expectedHttpVersion) { this.expectedHttpVersion = expectedHttpVersion; return this; } /** * @return Return the expected HTTP protocol version. */ public HttpVersion getExpectedHttpVersion() { return expectedHttpVersion; } /** * Sets maximum amount of time, in milliseconds, that the connection can be idle in the manager before * getting culled by the manager * @param maxConnectionIdleInMilliseconds How long to allow connections to be idle before reaping them * @return this */ public HttpClientConnectionManagerOptions withMaxConnectionIdleInMilliseconds(long maxConnectionIdleInMilliseconds) { this.maxConnectionIdleInMilliseconds = maxConnectionIdleInMilliseconds; return this; } /** * @return How long to allow connections to be idle before reaping them */ public long getMaxConnectionIdleInMilliseconds() { return maxConnectionIdleInMilliseconds; } /** * Sets the monitoring options for connections in the connection pool * @param monitoringOptions Monitoring options for this connection manager, or null to disable monitoring * @return this */ public HttpClientConnectionManagerOptions withMonitoringOptions(HttpMonitoringOptions monitoringOptions) { this.monitoringOptions = monitoringOptions; return this; } /** * @return the monitoring options for connections in the connection pool */ public HttpMonitoringOptions getMonitoringOptions() { return monitoringOptions; } /** * Validate the connection manager options are valid to use. Throw exceptions if not. */ public void validateOptions() { URI uri = this.getUri(); if (uri == null) { throw new IllegalArgumentException("URI must not be null"); } if (uri.getScheme() == null) { throw new IllegalArgumentException("URI does not have a Scheme"); } if (!HTTP.equals(uri.getScheme()) && !HTTPS.equals(uri.getScheme())) { throw new IllegalArgumentException("URI has unknown Scheme"); } if (uri.getHost() == null) { throw new IllegalArgumentException("URI does not have a Host name"); } if (clientBootstrap == null) { throw new IllegalArgumentException("ClientBootstrap must not be null"); } if (socketOptions == null) { throw new IllegalArgumentException("SocketOptions must not be null"); } if(tlsContext!= null && tlsConnectionOptions != null) { throw new IllegalArgumentException("Cannot set both TlsContext and TlsConnectionOptions."); } boolean useTls = HTTPS.equals(uri.getScheme()); boolean tlsSet = (tlsContext!= null || tlsConnectionOptions != null); if (useTls && !tlsSet) { throw new IllegalArgumentException("TlsContext or TlsConnectionOptions must not be null if https is used"); } if (windowSize <= 0) { throw new IllegalArgumentException("Window Size must be greater than zero."); } if (maxConnections <= 0) { throw new IllegalArgumentException("Max Connections must be greater than zero."); } } }