• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 java.nio.charset.Charset;
9 import java.util.Queue;
10 import java.util.concurrent.CompletableFuture;
11 import java.util.concurrent.ConcurrentLinkedQueue;
12 
13 import software.amazon.awssdk.crt.CRT;
14 import software.amazon.awssdk.crt.CrtResource;
15 import software.amazon.awssdk.crt.CrtRuntimeException;
16 import software.amazon.awssdk.crt.io.ClientBootstrap;
17 import software.amazon.awssdk.crt.io.SocketOptions;
18 import software.amazon.awssdk.crt.io.TlsConnectionOptions;
19 import software.amazon.awssdk.crt.io.TlsContext;
20 
21 /**
22  * Manages a Pool of Http Connections
23  */
24 public class HttpClientConnectionManager extends CrtResource {
25     private static final String HTTP = "http";
26     private static final String HTTPS = "https";
27     private static final int DEFAULT_HTTP_PORT = 80;
28     private static final int DEFAULT_HTTPS_PORT = 443;
29     private final static Charset UTF8 = java.nio.charset.StandardCharsets.UTF_8;
30 
31     private final long windowSize;
32     private final URI uri;
33     private final int port;
34     private final int maxConnections;
35     private final CompletableFuture<Void> shutdownComplete = new CompletableFuture<>();
36     private final HttpVersion expectedHttpVersion;
37 
38     /**
39      * Factory function for HttpClientConnectionManager instances
40      *
41      * @param options configuration options
42      * @return a new instance of an HttpClientConnectionManager
43      */
create(HttpClientConnectionManagerOptions options)44     public static HttpClientConnectionManager create(HttpClientConnectionManagerOptions options) {
45         return new HttpClientConnectionManager(options);
46     }
47 
HttpClientConnectionManager(HttpClientConnectionManagerOptions options)48     private HttpClientConnectionManager(HttpClientConnectionManagerOptions options) {
49 
50         options.validateOptions();
51         URI uri = options.getUri();
52         ClientBootstrap clientBootstrap = options.getClientBootstrap();
53         SocketOptions socketOptions = options.getSocketOptions();
54         boolean useTls = HTTPS.equals(uri.getScheme());
55         TlsContext tlsContext = options.getTlsContext();
56         TlsConnectionOptions tlsConnectionOptions = options.getTlsConnectionOptions();
57 
58         long windowSize = options.getWindowSize();
59         int maxConnections = options.getMaxConnections();
60         int port = options.getPort();
61         if (port == -1) {
62             port = uri.getPort();
63             /* Pick a default port based on the scheme if one wasn't set */
64             if (port == -1) {
65                 if (HTTP.equals(uri.getScheme()))  { port = DEFAULT_HTTP_PORT; }
66                 if (HTTPS.equals(uri.getScheme())) { port = DEFAULT_HTTPS_PORT; }
67             }
68         }
69 
70         HttpProxyOptions proxyOptions = options.getProxyOptions();
71 
72         this.windowSize = windowSize;
73         this.uri = uri;
74         this.port = port;
75         this.maxConnections = maxConnections;
76         this.expectedHttpVersion = options.getExpectedHttpVersion();
77 
78         int proxyConnectionType = 0;
79         String proxyHost = null;
80         int proxyPort = 0;
81         TlsContext proxyTlsContext = null;
82         int proxyAuthorizationType = 0;
83         String proxyAuthorizationUsername = null;
84         String proxyAuthorizationPassword = null;
85 
86         if (proxyOptions != null) {
87             proxyConnectionType = proxyOptions.getConnectionType().getValue();
88             proxyHost = proxyOptions.getHost();
89             proxyPort = proxyOptions.getPort();
90             proxyTlsContext = proxyOptions.getTlsContext();
91             proxyAuthorizationType = proxyOptions.getAuthorizationType().getValue();
92             proxyAuthorizationUsername = proxyOptions.getAuthorizationUsername();
93             proxyAuthorizationPassword = proxyOptions.getAuthorizationPassword();
94         }
95 
96         int environmentVariableProxyConnectionType = 0;
97         TlsConnectionOptions environmentVariableProxyTlsConnectionOptions = null;
98         int environmentVariableType = 0;
99         HttpProxyEnvironmentVariableSetting environmentVariableSetting = options.getHttpProxyEnvironmentVariableSetting();
100         if (environmentVariableSetting != null) {
101             environmentVariableProxyConnectionType = environmentVariableSetting.getConnectionType().getValue();
102             environmentVariableProxyTlsConnectionOptions = environmentVariableSetting.getTlsConnectionOptions();
103             environmentVariableType = environmentVariableSetting.getEnvironmentVariableType().getValue();
104         }
105 
106         HttpMonitoringOptions monitoringOptions = options.getMonitoringOptions();
107         long monitoringThroughputThresholdInBytesPerSecond = 0;
108         int monitoringFailureIntervalInSeconds = 0;
109         if (monitoringOptions != null) {
110             monitoringThroughputThresholdInBytesPerSecond = monitoringOptions.getMinThroughputBytesPerSecond();
111             monitoringFailureIntervalInSeconds = monitoringOptions.getAllowableThroughputFailureIntervalSeconds();
112         }
113 
114         acquireNativeHandle(httpClientConnectionManagerNew(this,
115                                             clientBootstrap.getNativeHandle(),
116                                             socketOptions.getNativeHandle(),
117                                             useTls && tlsContext!=null ? tlsContext.getNativeHandle() : 0,
118                                             useTls && tlsConnectionOptions!=null ? tlsConnectionOptions.getNativeHandle() : 0,
119                                             windowSize,
120                                             uri.getHost().getBytes(UTF8),
121                                             port,
122                                             maxConnections,
123                                             proxyConnectionType,
124                                             proxyHost != null ? proxyHost.getBytes(UTF8) : null,
125                                             proxyPort,
126                                             proxyTlsContext != null ? proxyTlsContext.getNativeHandle() : 0,
127                                             proxyAuthorizationType,
128                                             proxyAuthorizationUsername != null ? proxyAuthorizationUsername.getBytes(UTF8) : null,
129                                             proxyAuthorizationPassword != null ? proxyAuthorizationPassword.getBytes(UTF8) : null,
130                                             environmentVariableProxyConnectionType,
131                                             environmentVariableProxyTlsConnectionOptions != null
132                                                     ? environmentVariableProxyTlsConnectionOptions.getNativeHandle()
133                                                     : 0,
134                                             environmentVariableType,
135                                             options.isManualWindowManagement(),
136                                             options.getMaxConnectionIdleInMilliseconds(),
137                                             monitoringThroughputThresholdInBytesPerSecond,
138                                             monitoringFailureIntervalInSeconds,
139                                             expectedHttpVersion.getValue()));
140 
141         /* we don't need to add a reference to socketOptions since it's copied during connection manager construction */
142          addReferenceTo(clientBootstrap);
143          if (useTls) {
144             if (tlsContext != null) {
145                 addReferenceTo(tlsContext);
146             }
147             if (tlsConnectionOptions != null) {
148                 addReferenceTo(tlsConnectionOptions);
149             }
150          }
151     }
152 
153     /**
154      * Request a HttpClientConnection from the Connection Pool.
155      * @return A Future for a HttpClientConnection that will be completed when a connection is acquired.
156      */
acquireConnection()157     public CompletableFuture<HttpClientConnection> acquireConnection() {
158         if (isNull()) {
159             throw new IllegalStateException("HttpClientConnectionManager has been closed, can't acquire new connections");
160         }
161 
162         CompletableFuture<HttpClientConnection> returnedFuture = new CompletableFuture<>();
163         httpClientConnectionManagerAcquireConnection(this.getNativeHandle(), returnedFuture);
164         return returnedFuture;
165     }
166 
167     /**
168      * Releases this HttpClientConnection back into the Connection Pool, and allows another Request to acquire this connection.
169      * @param conn Connection to release
170      */
releaseConnection(HttpClientConnection conn)171     public void releaseConnection(HttpClientConnection conn) {
172         conn.close();
173     }
174 
175     /**
176      * Called from Native when all Connections in this Connection Pool have finished shutting down and it is safe to
177      * begin releasing Native Resources that HttpClientConnectionManager depends on.
178      */
onShutdownComplete()179     private void onShutdownComplete() {
180         releaseReferences();
181 
182         this.shutdownComplete.complete(null);
183     }
184 
185     /**
186      * Determines whether a resource releases its dependencies at the same time the native handle is released or if it waits.
187      * Resources that wait are responsible for calling releaseReferences() manually.
188      */
189     @Override
canReleaseReferencesImmediately()190     protected boolean canReleaseReferencesImmediately() { return false; }
191 
192     /**
193      * Closes this Connection Pool and any pending Connection Acquisitions
194      */
195     @Override
releaseNativeHandle()196     protected void releaseNativeHandle() {
197         if (!isNull()) {
198             /*
199              * Release our Native pointer and schedule tasks on the Native Event Loop to start sending HTTP/TLS/TCP
200              * connection shutdown messages to peers for any open Connections.
201              */
202             httpClientConnectionManagerRelease(getNativeHandle());
203         }
204     }
205 
getShutdownCompleteFuture()206     public CompletableFuture<Void> getShutdownCompleteFuture() { return shutdownComplete; }
207 
208     /*******************************************************************************
209      * Getter methods
210      ******************************************************************************/
211 
212     /**
213      * @return maximum number of connections this connection manager will pool
214      */
getMaxConnections()215     public int getMaxConnections() {
216         return maxConnections;
217     }
218 
219     /**
220      * @return concurrency metrics for the current manager
221      */
getManagerMetrics()222     public HttpManagerMetrics getManagerMetrics() {
223         if (isNull()) {
224             throw new IllegalStateException("HttpClientConnectionManager has been closed, can't fetch metrics");
225         }
226         return httpConnectionManagerFetchMetrics(getNativeHandle());
227     }
228 
229     /**
230      * @return size of the per-connection streaming read window for response handling
231      */
getWindowSize()232     public long getWindowSize() {
233         return windowSize;
234     }
235 
236     /**
237      * @return uri the connection manager is making connections to
238      */
getUri()239     public URI getUri() {
240         return uri;
241     }
242 
243     /*******************************************************************************
244      * Native methods
245      ******************************************************************************/
246 
httpClientConnectionManagerNew(HttpClientConnectionManager thisObj, long client_bootstrap, long socketOptions, long tlsContext, long tlsConnectionOptions, long windowSize, byte[] endpoint, int port, int maxConns, int proxyConnectionType, byte[] proxyHost, int proxyPort, long proxyTlsContext, int proxyAuthorizationType, byte[] proxyAuthorizationUsername, byte[] proxyAuthorizationPassword, int environmentVariableProxyConnectionType, long environmentVariableProxyTlsConnectionOptions, int environmentVariableSetting, boolean isManualWindowManagement, long maxConnectionIdleInMilliseconds, long monitoringThroughputThresholdInBytesPerSecond, int monitoringFailureIntervalInSeconds, int expectedProtocol)247     private static native long httpClientConnectionManagerNew(HttpClientConnectionManager thisObj,
248                                                         long client_bootstrap,
249                                                         long socketOptions,
250                                                         long tlsContext,
251                                                         long tlsConnectionOptions,
252                                                         long windowSize,
253                                                         byte[] endpoint,
254                                                         int port,
255                                                         int maxConns,
256                                                         int proxyConnectionType,
257                                                         byte[] proxyHost,
258                                                         int proxyPort,
259                                                         long proxyTlsContext,
260                                                         int proxyAuthorizationType,
261                                                         byte[] proxyAuthorizationUsername,
262                                                         byte[] proxyAuthorizationPassword,
263                                                         int environmentVariableProxyConnectionType,
264                                                         long environmentVariableProxyTlsConnectionOptions,
265                                                         int environmentVariableSetting,
266                                                         boolean isManualWindowManagement,
267                                                         long maxConnectionIdleInMilliseconds,
268                                                         long monitoringThroughputThresholdInBytesPerSecond,
269                                                         int monitoringFailureIntervalInSeconds,
270                                                         int expectedProtocol) throws CrtRuntimeException;
271 
httpClientConnectionManagerRelease(long conn_manager)272     private static native void httpClientConnectionManagerRelease(long conn_manager) throws CrtRuntimeException;
273 
httpClientConnectionManagerAcquireConnection(long conn_manager, CompletableFuture<HttpClientConnection> acquireFuture)274     private static native void httpClientConnectionManagerAcquireConnection(long conn_manager, CompletableFuture<HttpClientConnection> acquireFuture) throws CrtRuntimeException;
275 
httpConnectionManagerFetchMetrics(long conn_manager)276     private static native HttpManagerMetrics httpConnectionManagerFetchMetrics(long conn_manager) throws CrtRuntimeException;
277 
278 }
279