xref: /aosp_15_r20/external/aws-crt-java/src/main/java/software/amazon/awssdk/crt/s3/S3Client.java (revision 3c7ae9de214676c52d19f01067dc1a404272dc11)
1 
2 /**
3  * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
4  * SPDX-License-Identifier: Apache-2.0.
5  */
6 package software.amazon.awssdk.crt.s3;
7 
8 import java.nio.charset.Charset;
9 import java.util.concurrent.CompletableFuture;
10 import software.amazon.awssdk.crt.CrtResource;
11 import software.amazon.awssdk.crt.CrtRuntimeException;
12 import software.amazon.awssdk.crt.http.HttpMonitoringOptions;
13 import software.amazon.awssdk.crt.http.HttpProxyEnvironmentVariableSetting;
14 import software.amazon.awssdk.crt.http.HttpProxyOptions;
15 import software.amazon.awssdk.crt.http.HttpRequestBodyStream;
16 import software.amazon.awssdk.crt.io.TlsConnectionOptions;
17 import software.amazon.awssdk.crt.io.TlsContext;
18 import software.amazon.awssdk.crt.io.StandardRetryOptions;
19 import software.amazon.awssdk.crt.Log;
20 import software.amazon.awssdk.crt.auth.signing.AwsSigningConfig;
21 
22 import java.net.URI;
23 
24 public class S3Client extends CrtResource {
25 
26     private final static Charset UTF8 = java.nio.charset.StandardCharsets.UTF_8;
27     private final CompletableFuture<Void> shutdownComplete = new CompletableFuture<>();
28     private final String region;
29 
S3Client(S3ClientOptions options)30     public S3Client(S3ClientOptions options) throws CrtRuntimeException {
31         TlsContext tlsCtx = options.getTlsContext();
32         region = options.getRegion();
33 
34         int proxyConnectionType = 0;
35         String proxyHost = null;
36         int proxyPort = 0;
37         TlsContext proxyTlsContext = null;
38         int proxyAuthorizationType = 0;
39         String proxyAuthorizationUsername = null;
40         String proxyAuthorizationPassword = null;
41 
42         HttpProxyOptions proxyOptions = options.getProxyOptions();
43         if (proxyOptions != null) {
44             proxyConnectionType = proxyOptions.getConnectionType().getValue();
45             proxyHost = proxyOptions.getHost();
46             proxyPort = proxyOptions.getPort();
47             proxyTlsContext = proxyOptions.getTlsContext();
48             proxyAuthorizationType = proxyOptions.getAuthorizationType().getValue();
49             proxyAuthorizationUsername = proxyOptions.getAuthorizationUsername();
50             proxyAuthorizationPassword = proxyOptions.getAuthorizationPassword();
51         }
52 
53         int environmentVariableProxyConnectionType = 0;
54         TlsConnectionOptions environmentVariableProxyTlsConnectionOptions = null;
55         int environmentVariableType = 1;
56         HttpProxyEnvironmentVariableSetting environmentVariableSetting = options.getHttpProxyEnvironmentVariableSetting();
57         if (environmentVariableSetting != null) {
58             environmentVariableProxyConnectionType = environmentVariableSetting.getConnectionType().getValue();
59             environmentVariableProxyTlsConnectionOptions = environmentVariableSetting.getTlsConnectionOptions();
60             environmentVariableType = environmentVariableSetting.getEnvironmentVariableType().getValue();
61         }
62 
63         HttpMonitoringOptions monitoringOptions = options.getMonitoringOptions();
64         long monitoringThroughputThresholdInBytesPerSecond = 0;
65         int monitoringFailureIntervalInSeconds = 0;
66         if (monitoringOptions != null) {
67             monitoringThroughputThresholdInBytesPerSecond = monitoringOptions.getMinThroughputBytesPerSecond();
68             monitoringFailureIntervalInSeconds = monitoringOptions.getAllowableThroughputFailureIntervalSeconds();
69         }
70         AwsSigningConfig signingConfig = options.getSigningConfig();
71         boolean didCreateSigningConfig = false;
72         if(signingConfig == null && options.getCredentialsProvider()!= null) {
73             /* Create the signing config from credentials provider */
74             signingConfig = AwsSigningConfig.getDefaultS3SigningConfig(region, options.getCredentialsProvider());
75             didCreateSigningConfig = true;
76         }
77 
78         acquireNativeHandle(s3ClientNew(this,
79                 region.getBytes(UTF8),
80                 options.getClientBootstrap().getNativeHandle(),
81                 tlsCtx != null ? tlsCtx.getNativeHandle() : 0,
82                 signingConfig,
83                 options.getPartSize(),
84                 options.getMultiPartUploadThreshold(),
85                 options.getThroughputTargetGbps(),
86                 options.getReadBackpressureEnabled(),
87                 options.getInitialReadWindowSize(),
88                 options.getMaxConnections(),
89                 options.getStandardRetryOptions(),
90                 options.getComputeContentMd5(),
91                 proxyConnectionType,
92                 proxyHost != null ? proxyHost.getBytes(UTF8) : null,
93                 proxyPort,
94                 proxyTlsContext != null ? proxyTlsContext.getNativeHandle() : 0,
95                 proxyAuthorizationType,
96                 proxyAuthorizationUsername != null ? proxyAuthorizationUsername.getBytes(UTF8) : null,
97                 proxyAuthorizationPassword != null ? proxyAuthorizationPassword.getBytes(UTF8) : null,
98                 environmentVariableProxyConnectionType,
99                 environmentVariableProxyTlsConnectionOptions != null
100                         ? environmentVariableProxyTlsConnectionOptions.getNativeHandle()
101                         : 0,
102                 environmentVariableType,
103                 options.getConnectTimeoutMs(),
104                 options.getTcpKeepAliveOptions(),
105                 monitoringThroughputThresholdInBytesPerSecond,
106                 monitoringFailureIntervalInSeconds,
107                 options.getEnableS3Express(),
108                 options.getS3ExpressCredentialsProviderFactory(),
109                 options.getMemoryLimitInBytes()));
110 
111         addReferenceTo(options.getClientBootstrap());
112         if(didCreateSigningConfig) {
113             /* The native code will keep the needed resource around */
114             signingConfig.close();
115         }
116     }
117 
onShutdownComplete()118     private void onShutdownComplete() {
119         releaseReferences();
120 
121         this.shutdownComplete.complete(null);
122     }
123 
makeMetaRequest(S3MetaRequestOptions options)124     public S3MetaRequest makeMetaRequest(S3MetaRequestOptions options) {
125 
126         if(isNull()) {
127             Log.log(Log.LogLevel.Error, Log.LogSubject.S3Client,
128                     "S3Client.makeMetaRequest has invalid client. The client can not be used after it is closed.");
129             throw new IllegalStateException("S3Client.makeMetaRequest has invalid client. The client can not be used after it is closed.");
130         }
131 
132         if (options.getHttpRequest() == null) {
133             Log.log(Log.LogLevel.Error, Log.LogSubject.S3Client,
134                     "S3Client.makeMetaRequest has invalid options; Http Request cannot be null.");
135             throw new IllegalArgumentException("S3Client.makeMetaRequest has invalid options; Http Request cannot be null.");
136         }
137 
138         if (options.getResponseHandler() == null) {
139             Log.log(Log.LogLevel.Error, Log.LogSubject.S3Client,
140                     "S3Client.makeMetaRequest has invalid options; Response Handler cannot be null.");
141             throw new IllegalArgumentException("S3Client.makeMetaRequest has invalid options; Response Handler cannot be null.");
142         }
143 
144         S3MetaRequest metaRequest = new S3MetaRequest();
145         S3MetaRequestResponseHandlerNativeAdapter responseHandlerNativeAdapter = new S3MetaRequestResponseHandlerNativeAdapter(
146                 options.getResponseHandler());
147 
148         byte[] httpRequestBytes = options.getHttpRequest().marshalForJni();
149         byte[] requestFilePath = null;
150         if (options.getRequestFilePath() != null) {
151             requestFilePath = options.getRequestFilePath().toString().getBytes(UTF8);
152         }
153 
154         AwsSigningConfig signingConfig = options.getSigningConfig();
155         boolean didCreateSigningConfig = false;
156         if(signingConfig == null && options.getCredentialsProvider()!= null) {
157             signingConfig = AwsSigningConfig.getDefaultS3SigningConfig(region, options.getCredentialsProvider());
158             didCreateSigningConfig = true;
159         }
160         URI endpoint = options.getEndpoint();
161 
162         ChecksumConfig checksumConfig = options.getChecksumConfig() != null ? options.getChecksumConfig()
163                 : new ChecksumConfig();
164 
165         long metaRequestNativeHandle = s3ClientMakeMetaRequest(getNativeHandle(), metaRequest, region.getBytes(UTF8),
166                 options.getMetaRequestType().getNativeValue(), checksumConfig.getChecksumLocation().getNativeValue(),
167                 checksumConfig.getChecksumAlgorithm().getNativeValue(), checksumConfig.getValidateChecksum(),
168                 ChecksumAlgorithm.marshallAlgorithmsForJNI(checksumConfig.getValidateChecksumAlgorithmList()),
169                 httpRequestBytes, options.getHttpRequest().getBodyStream(), requestFilePath, signingConfig,
170                 responseHandlerNativeAdapter, endpoint == null ? null : endpoint.toString().getBytes(UTF8),
171                 options.getResumeToken());
172 
173         metaRequest.setMetaRequestNativeHandle(metaRequestNativeHandle);
174 
175         if(didCreateSigningConfig) {
176             /* The native code will keep the needed resource around */
177             signingConfig.close();
178         }
179         return metaRequest;
180     }
181 
182     /**
183      * Determines whether a resource releases its dependencies at the same time the
184      * native handle is released or if it waits. Resources that wait are responsible
185      * for calling releaseReferences() manually.
186      */
187     @Override
canReleaseReferencesImmediately()188     protected boolean canReleaseReferencesImmediately() {
189         return false;
190     }
191 
192     /**
193      * Cleans up the native resources associated with this client. The client is
194      * unusable after this call
195      */
196     @Override
releaseNativeHandle()197     protected void releaseNativeHandle() {
198         if (!isNull()) {
199             s3ClientDestroy(getNativeHandle());
200         }
201     }
202 
getShutdownCompleteFuture()203     public CompletableFuture<Void> getShutdownCompleteFuture() {
204         return shutdownComplete;
205     }
206 
207     /*******************************************************************************
208      * native methods
209      ******************************************************************************/
s3ClientNew(S3Client thisObj, byte[] region, long clientBootstrap, long tlsContext, AwsSigningConfig signingConfig, long partSize, long multipartUploadThreshold, double throughputTargetGbps, boolean enableReadBackpressure, long initialReadWindow, int maxConnections, StandardRetryOptions standardRetryOptions, boolean computeContentMd5, int proxyConnectionType, byte[] proxyHost, int proxyPort, long proxyTlsContext, int proxyAuthorizationType, byte[] proxyAuthorizationUsername, byte[] proxyAuthorizationPassword, int environmentVariableProxyConnectionType, long environmentVariableProxyTlsConnectionOptions, int environmentVariableSetting, int connectTimeoutMs, S3TcpKeepAliveOptions tcpKeepAliveOptions, long monitoringThroughputThresholdInBytesPerSecond, int monitoringFailureIntervalInSeconds, boolean enableS3Express, S3ExpressCredentialsProviderFactory s3expressCredentialsProviderFactory, long memoryLimitInBytes)210     private static native long s3ClientNew(S3Client thisObj, byte[] region, long clientBootstrap,
211             long tlsContext, AwsSigningConfig signingConfig, long partSize, long multipartUploadThreshold, double throughputTargetGbps,
212             boolean enableReadBackpressure, long initialReadWindow, int maxConnections,
213             StandardRetryOptions standardRetryOptions, boolean computeContentMd5,
214             int proxyConnectionType,
215             byte[] proxyHost,
216             int proxyPort,
217             long proxyTlsContext,
218             int proxyAuthorizationType,
219             byte[] proxyAuthorizationUsername,
220             byte[] proxyAuthorizationPassword,
221             int environmentVariableProxyConnectionType,
222             long environmentVariableProxyTlsConnectionOptions,
223             int environmentVariableSetting,
224             int connectTimeoutMs,
225             S3TcpKeepAliveOptions tcpKeepAliveOptions,
226             long monitoringThroughputThresholdInBytesPerSecond,
227             int monitoringFailureIntervalInSeconds,
228             boolean enableS3Express,
229             S3ExpressCredentialsProviderFactory s3expressCredentialsProviderFactory,
230             long memoryLimitInBytes) throws CrtRuntimeException;
231 
s3ClientDestroy(long client)232     private static native void s3ClientDestroy(long client);
233 
s3ClientMakeMetaRequest(long clientId, S3MetaRequest metaRequest, byte[] region, int metaRequestType, int checksumLocation, int checksumAlgorithm, boolean validateChecksum, int[] validateAlgorithms, byte[] httpRequestBytes, HttpRequestBodyStream httpRequestBodyStream, byte[] requestFilePath, AwsSigningConfig signingConfig, S3MetaRequestResponseHandlerNativeAdapter responseHandlerNativeAdapter, byte[] endpoint, ResumeToken resumeToken)234     private static native long s3ClientMakeMetaRequest(long clientId, S3MetaRequest metaRequest, byte[] region,
235             int metaRequestType, int checksumLocation, int checksumAlgorithm, boolean validateChecksum,
236             int[] validateAlgorithms, byte[] httpRequestBytes,
237             HttpRequestBodyStream httpRequestBodyStream, byte[] requestFilePath,
238             AwsSigningConfig signingConfig, S3MetaRequestResponseHandlerNativeAdapter responseHandlerNativeAdapter,
239             byte[] endpoint, ResumeToken resumeToken);
240 }
241