1 /**
2 * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
3 * SPDX-License-Identifier: Apache-2.0.
4 */
5 #include "aws_signing.h"
6 #include "credentials.h"
7 #include "crt.h"
8 #include "http_request_utils.h"
9 #include "java_class_ids.h"
10 #include "retry_utils.h"
11 #include <aws/common/string.h>
12 #include <aws/http/connection.h>
13 #include <aws/http/proxy.h>
14 #include <aws/http/request_response.h>
15 #include <aws/io/channel_bootstrap.h>
16 #include <aws/io/retry_strategy.h>
17 #include <aws/io/stream.h>
18 #include <aws/io/tls_channel_handler.h>
19 #include <aws/io/uri.h>
20 #include <aws/s3/s3_client.h>
21 #include <aws/s3/s3express_credentials_provider.h>
22 #include <http_proxy_options.h>
23 #include <http_proxy_options_environment_variable.h>
24 #include <jni.h>
25
26 /* on 32-bit platforms, casting pointers to longs throws a warning we don't need */
27 #if UINTPTR_MAX == 0xffffffff
28 # if defined(_MSC_VER)
29 # pragma warning(push)
30 # pragma warning(disable : 4305) /* 'type cast': truncation from 'jlong' to 'jni_tls_ctx_options *' */
31 # pragma warning(disable : 4221)
32 # else
33 # pragma GCC diagnostic push
34 # pragma GCC diagnostic ignored "-Wpointer-to-int-cast"
35 # pragma GCC diagnostic ignored "-Wint-to-pointer-cast"
36 # endif
37 #endif
38
39 struct s3_client_callback_data {
40 JavaVM *jvm;
41 jobject java_s3_client;
42 struct aws_signing_config_data signing_config_data;
43 jobject java_s3express_provider_factory;
44 };
45
46 struct s3_client_make_meta_request_callback_data {
47 JavaVM *jvm;
48 jobject java_s3_meta_request;
49 jobject java_s3_meta_request_response_handler_native_adapter;
50 struct aws_input_stream *input_stream;
51 struct aws_signing_config_data signing_config_data;
52 jthrowable java_exception;
53 };
54
55 static void s_on_s3_client_shutdown_complete_callback(void *user_data);
56 static void s_on_s3_meta_request_shutdown_complete_callback(void *user_data);
57
aws_s3_tcp_keep_alive_options_from_java(JNIEnv * env,jobject jni_s3_tcp_keep_alive_options,struct aws_s3_tcp_keep_alive_options * s3_tcp_keep_alive_options)58 int aws_s3_tcp_keep_alive_options_from_java(
59 JNIEnv *env,
60 jobject jni_s3_tcp_keep_alive_options,
61 struct aws_s3_tcp_keep_alive_options *s3_tcp_keep_alive_options) {
62
63 uint16_t jni_keep_alive_interval_sec = (*env)->GetShortField(
64 env, jni_s3_tcp_keep_alive_options, s3_tcp_keep_alive_options_properties.keep_alive_interval_sec_field_id);
65
66 uint16_t jni_keep_alive_timeout_sec = (*env)->GetShortField(
67 env, jni_s3_tcp_keep_alive_options, s3_tcp_keep_alive_options_properties.keep_alive_timeout_sec_field_id);
68
69 uint16_t jni_keep_alive_max_failed_probes = (*env)->GetShortField(
70 env, jni_s3_tcp_keep_alive_options, s3_tcp_keep_alive_options_properties.keep_alive_max_failed_probes_field_id);
71
72 AWS_ZERO_STRUCT(*s3_tcp_keep_alive_options);
73
74 s3_tcp_keep_alive_options->keep_alive_interval_sec = jni_keep_alive_interval_sec;
75 s3_tcp_keep_alive_options->keep_alive_timeout_sec = jni_keep_alive_timeout_sec;
76 s3_tcp_keep_alive_options->keep_alive_max_failed_probes = jni_keep_alive_max_failed_probes;
77
78 return AWS_OP_SUCCESS;
79 }
80
81 struct s3_client_s3express_provider_java_impl {
82 JavaVM *jvm;
83 jobject java_s3express_provider;
84 };
85
86 struct s3_client_s3express_provider_callback_data {
87 void *log_id;
88 aws_on_get_credentials_callback_fn *get_cred_callback;
89 void *get_cred_user_data;
90 };
91
92 JNIEXPORT void JNICALL
Java_software_amazon_awssdk_crt_s3_S3ExpressCredentialsProvider_s3expressCredentialsProviderGetCredentialsCompleted(JNIEnv * env,jclass jni_class,jlong nativeHandler,jobject java_credentials)93 Java_software_amazon_awssdk_crt_s3_S3ExpressCredentialsProvider_s3expressCredentialsProviderGetCredentialsCompleted(
94 JNIEnv *env,
95 jclass jni_class,
96 jlong nativeHandler,
97 jobject java_credentials) {
98
99 (void)jni_class;
100 struct s3_client_s3express_provider_callback_data *callback_data = (void *)nativeHandler;
101 struct aws_credentials *native_credentials = NULL;
102 int error_code = AWS_ERROR_SUCCESS;
103
104 if (!java_credentials || aws_jni_check_and_clear_exception(env)) {
105 /* TODO: a separate error code?? */
106 AWS_LOGF_ERROR(
107 AWS_LS_S3_META_REQUEST,
108 "id=%p: Failed to get S3Express credentials from Java",
109 (void *)callback_data->log_id);
110 error_code = AWS_ERROR_HTTP_CALLBACK_FAILURE;
111 goto done;
112 }
113
114 native_credentials = aws_credentials_new_from_java_credentials(env, java_credentials);
115 if (!native_credentials) {
116 aws_jni_throw_runtime_exception(env, "Failed to create native credentials");
117 AWS_LOGF_ERROR(
118 AWS_LS_S3_META_REQUEST,
119 "id=%p: Failed to create native credentials from Java",
120 (void *)callback_data->log_id);
121 goto done;
122 }
123 struct aws_byte_cursor session_token = aws_credentials_get_session_token(native_credentials);
124
125 if (session_token.len == 0) {
126 aws_jni_throw_runtime_exception(env, "S3ExpressCredentialsProvider - sessionToken must be non-null");
127 error_code = AWS_ERROR_HTTP_CALLBACK_FAILURE;
128 aws_credentials_release(native_credentials);
129 native_credentials = NULL;
130 goto done;
131 }
132
133 done:
134 callback_data->get_cred_callback(native_credentials, error_code, callback_data->get_cred_user_data);
135 aws_credentials_release(native_credentials);
136 aws_mem_release(aws_jni_get_allocator(), callback_data);
137 }
138
s_s3express_get_creds_java(struct aws_s3express_credentials_provider * provider,const struct aws_credentials * original_credentials,const struct aws_credentials_properties_s3express * s3express_properties,aws_on_get_credentials_callback_fn callback,void * user_data)139 static int s_s3express_get_creds_java(
140 struct aws_s3express_credentials_provider *provider,
141 const struct aws_credentials *original_credentials,
142 const struct aws_credentials_properties_s3express *s3express_properties,
143 aws_on_get_credentials_callback_fn callback,
144 void *user_data) {
145
146 struct s3_client_s3express_provider_java_impl *impl = provider->impl;
147 int result = AWS_OP_ERR;
148
149 /********** JNI ENV ACQUIRE **********/
150 JNIEnv *env = aws_jni_acquire_thread_env(impl->jvm);
151 if (!env) {
152 /* If we can't get an environment, then the JVM is probably shutting down. Don't crash. */
153 return AWS_OP_SUCCESS;
154 }
155 jobject properties_object = NULL;
156 jobject original_credentials_object = NULL;
157
158 properties_object = (*env)->NewObject(
159 env,
160 s3express_credentials_properties_properties.s3express_credentials_properties_class,
161 s3express_credentials_properties_properties.constructor_method_id);
162 if ((*env)->ExceptionCheck(env) || properties_object == NULL) {
163 aws_jni_throw_runtime_exception(
164 env,
165 "S3ExpressCredentialsProvider.getS3ExpressCredentials: Failed to create S3ExpressCredentialsProperties "
166 "object.");
167 goto done;
168 }
169 original_credentials_object = aws_java_credentials_from_native_new(env, original_credentials);
170 if ((*env)->ExceptionCheck(env) || original_credentials_object == NULL) {
171 aws_jni_throw_runtime_exception(
172 env, "S3ExpressCredentialsProvider.getS3ExpressCredentials: Failed to create Credentials object.");
173 goto done;
174 }
175
176 jstring jni_host = aws_jni_string_from_cursor(env, &s3express_properties->host);
177 jstring jni_region = aws_jni_string_from_cursor(env, &s3express_properties->region);
178 (*env)->SetObjectField(env, properties_object, s3express_credentials_properties_properties.host_field_id, jni_host);
179 (*env)->SetObjectField(
180 env, properties_object, s3express_credentials_properties_properties.region_field_id, jni_region);
181 (*env)->DeleteLocalRef(env, jni_host);
182 (*env)->DeleteLocalRef(env, jni_region);
183
184 struct s3_client_s3express_provider_callback_data *callback_data =
185 aws_mem_calloc(aws_jni_get_allocator(), 1, sizeof(struct s3_client_s3express_provider_callback_data));
186
187 callback_data->get_cred_callback = callback;
188 callback_data->get_cred_user_data = user_data;
189 callback_data->log_id = impl->java_s3express_provider;
190
191 /* Invoke the java call */
192 (*env)->CallVoidMethod(
193 env,
194 impl->java_s3express_provider,
195 s3express_credentials_provider_properties.getS3ExpressCredentials,
196 properties_object,
197 original_credentials_object,
198 (jlong)callback_data);
199
200 if (aws_jni_check_and_clear_exception(env)) {
201 /* Check if any exception raised */
202 AWS_LOGF_ERROR(
203 AWS_LS_S3_META_REQUEST,
204 "id=%p: S3ExpressCredentialsProvider.getS3ExpressCredentials failed",
205 (void *)impl->java_s3express_provider);
206 aws_mem_release(aws_jni_get_allocator(), callback_data);
207 goto done;
208 }
209 result = AWS_OP_SUCCESS;
210 done:
211 if (properties_object) {
212 (*env)->DeleteLocalRef(env, properties_object);
213 }
214 if (original_credentials_object) {
215 (*env)->DeleteLocalRef(env, original_credentials_object);
216 }
217 aws_jni_release_thread_env(impl->jvm, env);
218 /********** JNI ENV RELEASE **********/
219 return result;
220 }
221
s_s3express_destroy_java(struct aws_s3express_credentials_provider * provider)222 static void s_s3express_destroy_java(struct aws_s3express_credentials_provider *provider) {
223 struct s3_client_s3express_provider_java_impl *impl = provider->impl;
224
225 /********** JNI ENV ACQUIRE **********/
226 JNIEnv *env = aws_jni_acquire_thread_env(impl->jvm);
227 if (!env) {
228 /* If we can't get an environment, then the JVM is probably shutting down. Don't crash. */
229 return;
230 }
231 /* Invoke the java call */
232 (*env)->CallVoidMethod(
233 env, impl->java_s3express_provider, s3express_credentials_provider_properties.destroyProvider);
234
235 (*env)->DeleteGlobalRef(env, impl->java_s3express_provider);
236
237 aws_jni_release_thread_env(impl->jvm, env);
238 /********** JNI ENV RELEASE **********/
239 /* Once the java call returns, the java resource should be cleaned up already. We can finish up the shutdown
240 * process. Clean up the native part. */
241 aws_simple_completion_callback *callback = provider->shutdown_complete_callback;
242 void *user_data = provider->shutdown_user_data;
243 aws_mem_release(provider->allocator, provider);
244 callback(user_data);
245 }
246
247 static struct aws_s3express_credentials_provider_vtable s_java_s3express_vtable = {
248 .get_credentials = s_s3express_get_creds_java,
249 .destroy = s_s3express_destroy_java,
250 };
251
s_s3express_provider_jni_factory(struct aws_allocator * allocator,struct aws_s3_client * client,aws_simple_completion_callback shutdown_complete_callback,void * shutdown_user_data,void * factory_user_data)252 struct aws_s3express_credentials_provider *s_s3express_provider_jni_factory(
253 struct aws_allocator *allocator,
254 struct aws_s3_client *client,
255 aws_simple_completion_callback shutdown_complete_callback,
256 void *shutdown_user_data,
257 void *factory_user_data) {
258
259 (void)client;
260 struct s3_client_callback_data *client_data = factory_user_data;
261
262 struct aws_s3express_credentials_provider *provider = NULL;
263 struct s3_client_s3express_provider_java_impl *impl = NULL;
264
265 /********** JNI ENV ACQUIRE **********/
266 JNIEnv *env = aws_jni_acquire_thread_env(client_data->jvm);
267 if (env == NULL) {
268 /* If we can't get an environment, then the JVM is probably shutting down. Don't crash. */
269 return NULL;
270 }
271
272 aws_mem_acquire_many(
273 allocator,
274 2,
275 &provider,
276 sizeof(struct aws_s3express_credentials_provider),
277 &impl,
278 sizeof(struct s3_client_s3express_provider_java_impl));
279 /* Call into the java factory to create the java impl */
280 AWS_FATAL_ASSERT(client_data->java_s3express_provider_factory != NULL);
281 jobject java_s3express_provider = (*env)->CallObjectMethod(
282 env,
283 client_data->java_s3express_provider_factory,
284 s3express_credentials_provider_factory_properties.createS3ExpressCredentialsProvider,
285 client_data->java_s3_client);
286
287 if (aws_jni_check_and_clear_exception(env)) {
288 AWS_LOGF_ERROR(
289 AWS_LS_S3_META_REQUEST,
290 "id=%p: Failed to create Java S3Express Provider",
291 (void *)client_data->java_s3express_provider_factory);
292 aws_mem_release(allocator, provider);
293 provider = NULL;
294 goto done;
295 }
296 impl->java_s3express_provider = (*env)->NewGlobalRef(env, java_s3express_provider);
297
298 jint jvmresult = (*env)->GetJavaVM(env, &impl->jvm);
299 (void)jvmresult;
300 AWS_FATAL_ASSERT(jvmresult == 0);
301
302 aws_s3express_credentials_provider_init_base(provider, allocator, &s_java_s3express_vtable, impl);
303 provider->shutdown_complete_callback = shutdown_complete_callback;
304 provider->shutdown_user_data = shutdown_user_data;
305
306 /* We are done using the factory, when succeed, clean it up. TODO: we don't have to clean it up here */
307 (*env)->DeleteGlobalRef(env, client_data->java_s3express_provider_factory);
308 client_data->java_s3express_provider_factory = NULL;
309
310 done:
311 aws_jni_release_thread_env(client_data->jvm, env);
312 /********** JNI ENV RELEASE **********/
313 return provider;
314 }
315
Java_software_amazon_awssdk_crt_s3_S3Client_s3ClientNew(JNIEnv * env,jclass jni_class,jobject s3_client_jobject,jbyteArray jni_region,jlong jni_client_bootstrap,jlong jni_tls_ctx,jobject java_signing_config,jlong part_size_jlong,jlong multipart_upload_threshold_jlong,jdouble throughput_target_gbps,jboolean enable_read_backpressure,jlong initial_read_window_jlong,int max_connections,jobject jni_standard_retry_options,jboolean compute_content_md5,jint jni_proxy_connection_type,jbyteArray jni_proxy_host,jint jni_proxy_port,jlong jni_proxy_tls_context,jint jni_proxy_authorization_type,jbyteArray jni_proxy_authorization_username,jbyteArray jni_proxy_authorization_password,jint jni_environment_variable_proxy_connection_type,jlong jni_environment_variable_proxy_tls_connection_options,jint jni_environment_variable_type,int connect_timeout_ms,jobject jni_s3_tcp_keep_alive_options,jlong jni_monitoring_throughput_threshold_in_bytes_per_second,jint jni_monitoring_failure_interval_in_seconds,jboolean enable_s3express,jobject java_s3express_provider_factory,jlong jni_memory_limit_bytes_jlong)316 JNIEXPORT jlong JNICALL Java_software_amazon_awssdk_crt_s3_S3Client_s3ClientNew(
317 JNIEnv *env,
318 jclass jni_class,
319 jobject s3_client_jobject,
320 jbyteArray jni_region,
321 jlong jni_client_bootstrap,
322 jlong jni_tls_ctx,
323 jobject java_signing_config,
324 jlong part_size_jlong,
325 jlong multipart_upload_threshold_jlong,
326 jdouble throughput_target_gbps,
327 jboolean enable_read_backpressure,
328 jlong initial_read_window_jlong,
329 int max_connections,
330 jobject jni_standard_retry_options,
331 jboolean compute_content_md5,
332 jint jni_proxy_connection_type,
333 jbyteArray jni_proxy_host,
334 jint jni_proxy_port,
335 jlong jni_proxy_tls_context,
336 jint jni_proxy_authorization_type,
337 jbyteArray jni_proxy_authorization_username,
338 jbyteArray jni_proxy_authorization_password,
339 jint jni_environment_variable_proxy_connection_type,
340 jlong jni_environment_variable_proxy_tls_connection_options,
341 jint jni_environment_variable_type,
342 int connect_timeout_ms,
343 jobject jni_s3_tcp_keep_alive_options,
344 jlong jni_monitoring_throughput_threshold_in_bytes_per_second,
345 jint jni_monitoring_failure_interval_in_seconds,
346 jboolean enable_s3express,
347 jobject java_s3express_provider_factory,
348 jlong jni_memory_limit_bytes_jlong) {
349 (void)jni_class;
350 aws_cache_jni_ids(env);
351
352 struct aws_allocator *allocator = aws_jni_get_allocator();
353
354 struct aws_client_bootstrap *client_bootstrap = (struct aws_client_bootstrap *)jni_client_bootstrap;
355
356 if (!client_bootstrap) {
357 aws_jni_throw_illegal_argument_exception(env, "Invalid Client Bootstrap");
358 return (jlong)NULL;
359 }
360
361 uint64_t part_size = (uint64_t)part_size_jlong;
362 uint64_t multipart_upload_threshold = (uint64_t)multipart_upload_threshold_jlong;
363 uint64_t memory_limit_in_bytes = (uint64_t)jni_memory_limit_bytes_jlong;
364
365 size_t initial_read_window;
366 if (aws_size_t_from_java(env, &initial_read_window, initial_read_window_jlong, "Initial read window")) {
367 return (jlong)NULL;
368 }
369
370 struct aws_retry_strategy *retry_strategy = NULL;
371
372 if (jni_standard_retry_options != NULL) {
373 struct aws_standard_retry_options retry_options;
374
375 if (aws_standard_retry_options_from_java(env, jni_standard_retry_options, &retry_options)) {
376 return (jlong)NULL;
377 }
378
379 if (retry_options.backoff_retry_options.el_group == NULL) {
380 retry_options.backoff_retry_options.el_group = client_bootstrap->event_loop_group;
381 }
382
383 retry_strategy = aws_retry_strategy_new_standard(allocator, &retry_options);
384
385 if (retry_strategy == NULL) {
386 aws_jni_throw_runtime_exception(env, "Could not create retry strategy with standard-retry-options");
387 return (jlong)NULL;
388 }
389 }
390 struct aws_s3_tcp_keep_alive_options *s3_tcp_keep_alive_options = NULL;
391
392 if (jni_s3_tcp_keep_alive_options != NULL) {
393 s3_tcp_keep_alive_options = aws_mem_calloc(allocator, 1, sizeof(struct aws_s3_tcp_keep_alive_options));
394 if (aws_s3_tcp_keep_alive_options_from_java(env, jni_s3_tcp_keep_alive_options, s3_tcp_keep_alive_options)) {
395 aws_jni_throw_runtime_exception(env, "Could not create s3_tcp_keep_alive_options");
396 return (jlong)NULL;
397 }
398 }
399
400 struct aws_byte_cursor region = aws_jni_byte_cursor_from_jbyteArray_acquire(env, jni_region);
401
402 struct s3_client_callback_data *callback_data =
403 aws_mem_calloc(allocator, 1, sizeof(struct s3_client_callback_data));
404
405 struct aws_signing_config_aws signing_config;
406 struct aws_credentials *anonymous_credentials = NULL;
407 AWS_ZERO_STRUCT(signing_config);
408 if (java_signing_config != NULL) {
409 if (aws_build_signing_config(env, java_signing_config, &callback_data->signing_config_data, &signing_config)) {
410 aws_jni_throw_runtime_exception(env, "Invalid signingConfig");
411 aws_mem_release(allocator, callback_data);
412 return (jlong)NULL;
413 }
414 } else {
415 anonymous_credentials = aws_credentials_new_anonymous(allocator);
416 signing_config.credentials = anonymous_credentials;
417 }
418
419 if (java_s3express_provider_factory != NULL && enable_s3express) {
420 /* Create a JNI factory */
421 callback_data->java_s3express_provider_factory = (*env)->NewGlobalRef(env, java_s3express_provider_factory);
422 }
423
424 AWS_FATAL_ASSERT(callback_data);
425 callback_data->java_s3_client = (*env)->NewGlobalRef(env, s3_client_jobject);
426
427 jint jvmresult = (*env)->GetJavaVM(env, &callback_data->jvm);
428 (void)jvmresult;
429 AWS_FATAL_ASSERT(jvmresult == 0);
430
431 struct aws_tls_connection_options *tls_options = NULL;
432 struct aws_tls_connection_options tls_options_storage;
433 AWS_ZERO_STRUCT(tls_options_storage);
434 if (jni_tls_ctx) {
435 struct aws_tls_ctx *tls_ctx = (void *)jni_tls_ctx;
436 tls_options = &tls_options_storage;
437 aws_tls_connection_options_init_from_ctx(tls_options, tls_ctx);
438 }
439
440 struct aws_s3_client_config client_config = {
441 .max_active_connections_override = max_connections,
442 .region = region,
443 .client_bootstrap = client_bootstrap,
444 .tls_connection_options = tls_options,
445 .signing_config = &signing_config,
446 .part_size = part_size,
447 .multipart_upload_threshold = multipart_upload_threshold,
448 .throughput_target_gbps = throughput_target_gbps,
449 .enable_read_backpressure = enable_read_backpressure,
450 .initial_read_window = initial_read_window,
451 .retry_strategy = retry_strategy,
452 .shutdown_callback = s_on_s3_client_shutdown_complete_callback,
453 .shutdown_callback_user_data = callback_data,
454 .compute_content_md5 = compute_content_md5 ? AWS_MR_CONTENT_MD5_ENABLED : AWS_MR_CONTENT_MD5_DISABLED,
455 .connect_timeout_ms = connect_timeout_ms,
456 .tcp_keep_alive_options = s3_tcp_keep_alive_options,
457 .enable_s3express = enable_s3express,
458 .s3express_provider_override_factory =
459 java_s3express_provider_factory ? s_s3express_provider_jni_factory : NULL,
460 .factory_user_data = callback_data,
461 .memory_limit_in_bytes = memory_limit_in_bytes,
462 };
463
464 struct aws_http_connection_monitoring_options monitoring_options;
465 AWS_ZERO_STRUCT(monitoring_options);
466 if (jni_monitoring_throughput_threshold_in_bytes_per_second >= 0 &&
467 jni_monitoring_failure_interval_in_seconds >= 2) {
468 monitoring_options.minimum_throughput_bytes_per_second =
469 jni_monitoring_throughput_threshold_in_bytes_per_second;
470 monitoring_options.allowable_throughput_failure_interval_seconds = jni_monitoring_failure_interval_in_seconds;
471 client_config.monitoring_options = &monitoring_options;
472 }
473
474 struct aws_http_proxy_options proxy_options;
475 AWS_ZERO_STRUCT(proxy_options);
476
477 struct aws_tls_connection_options proxy_tls_conn_options;
478 AWS_ZERO_STRUCT(proxy_tls_conn_options);
479
480 aws_http_proxy_options_jni_init(
481 env,
482 &proxy_options,
483 jni_proxy_connection_type,
484 &proxy_tls_conn_options,
485 jni_proxy_host,
486 jni_proxy_port,
487 jni_proxy_authorization_username,
488 jni_proxy_authorization_password,
489 jni_proxy_authorization_type,
490 (struct aws_tls_ctx *)jni_proxy_tls_context);
491
492 if (jni_proxy_host != NULL) {
493 client_config.proxy_options = &proxy_options;
494 }
495
496 struct proxy_env_var_settings proxy_ev_settings;
497 AWS_ZERO_STRUCT(proxy_ev_settings);
498
499 aws_http_proxy_environment_variable_setting_jni_init(
500 &proxy_ev_settings,
501 jni_environment_variable_proxy_connection_type,
502 jni_environment_variable_type,
503 (struct aws_tls_connection_options *)jni_environment_variable_proxy_tls_connection_options);
504
505 client_config.proxy_ev_settings = &proxy_ev_settings;
506
507 struct aws_s3_client *client = aws_s3_client_new(allocator, &client_config);
508 if (!client) {
509 aws_jni_throw_runtime_exception(env, "S3Client.aws_s3_client_new: creating aws_s3_client failed");
510 /* Clean up stuff */
511 aws_signing_config_data_clean_up(&callback_data->signing_config_data, env);
512 aws_mem_release(allocator, callback_data);
513 }
514 aws_credentials_release(anonymous_credentials);
515
516 aws_retry_strategy_release(retry_strategy);
517
518 aws_jni_byte_cursor_from_jbyteArray_release(env, jni_region, region);
519
520 aws_http_proxy_options_jni_clean_up(
521 env, &proxy_options, jni_proxy_host, jni_proxy_authorization_username, jni_proxy_authorization_password);
522
523 aws_mem_release(aws_jni_get_allocator(), s3_tcp_keep_alive_options);
524
525 return (jlong)client;
526 }
527
528 JNIEXPORT void JNICALL
Java_software_amazon_awssdk_crt_s3_S3Client_s3ClientDestroy(JNIEnv * env,jclass jni_class,jlong jni_s3_client)529 Java_software_amazon_awssdk_crt_s3_S3Client_s3ClientDestroy(JNIEnv *env, jclass jni_class, jlong jni_s3_client) {
530 (void)jni_class;
531 aws_cache_jni_ids(env);
532
533 struct aws_s3_client *client = (struct aws_s3_client *)jni_s3_client;
534 if (!client) {
535 aws_jni_throw_runtime_exception(env, "S3Client.s3_client_clean_up: Invalid/null client");
536 return;
537 }
538
539 aws_s3_client_release(client);
540 }
541
s_on_s3_client_shutdown_complete_callback(void * user_data)542 static void s_on_s3_client_shutdown_complete_callback(void *user_data) {
543 struct s3_client_callback_data *callback = (struct s3_client_callback_data *)user_data;
544
545 /********** JNI ENV ACQUIRE **********/
546 JNIEnv *env = aws_jni_acquire_thread_env(callback->jvm);
547 if (env == NULL) {
548 /* If we can't get an environment, then the JVM is probably shutting down. Don't crash. */
549 return;
550 }
551
552 AWS_LOGF_DEBUG(AWS_LS_S3_CLIENT, "S3 Client Shutdown Complete");
553 if (callback->java_s3_client != NULL) {
554 (*env)->CallVoidMethod(env, callback->java_s3_client, s3_client_properties.onShutdownComplete);
555
556 if (aws_jni_check_and_clear_exception(env)) {
557 AWS_LOGF_ERROR(
558 AWS_LS_S3_META_REQUEST,
559 "id=%p: Ignored Exception from S3Client.onShutdownCompete callback",
560 (void *)callback->java_s3_client);
561 }
562 }
563
564 // We're done with this callback data, free it.
565 if (callback->java_s3express_provider_factory) {
566 /* Clean up factory data if still exist */
567 (*env)->DeleteGlobalRef(env, callback->java_s3express_provider_factory);
568 callback->java_s3express_provider_factory = NULL;
569 }
570 (*env)->DeleteGlobalRef(env, callback->java_s3_client);
571
572 aws_signing_config_data_clean_up(&callback->signing_config_data, env);
573
574 aws_jni_release_thread_env(callback->jvm, env);
575 /********** JNI ENV RELEASE **********/
576
577 aws_mem_release(aws_jni_get_allocator(), user_data);
578 }
579
s_on_s3_meta_request_body_callback(struct aws_s3_meta_request * meta_request,const struct aws_byte_cursor * body,uint64_t range_start,void * user_data)580 static int s_on_s3_meta_request_body_callback(
581 struct aws_s3_meta_request *meta_request,
582 const struct aws_byte_cursor *body,
583 uint64_t range_start,
584 void *user_data) {
585 (void)body;
586 (void)range_start;
587 int return_value = AWS_OP_ERR;
588
589 uint64_t range_end = range_start + body->len;
590
591 struct s3_client_make_meta_request_callback_data *callback_data =
592 (struct s3_client_make_meta_request_callback_data *)user_data;
593
594 /********** JNI ENV ACQUIRE **********/
595 JNIEnv *env = aws_jni_acquire_thread_env(callback_data->jvm);
596 if (env == NULL) {
597 /* If we can't get an environment, then the JVM is probably shutting down. Don't crash. */
598 return AWS_OP_ERR;
599 }
600
601 jobject jni_payload = aws_jni_byte_array_from_cursor(env, body);
602 if (jni_payload == NULL) {
603 /* JVM is out of memory, but native code can still have memory available, handle it and don't crash. */
604 aws_jni_check_and_clear_exception(env);
605 aws_jni_release_thread_env(callback_data->jvm, env);
606 /********** JNI ENV RELEASE **********/
607 return aws_raise_error(AWS_ERROR_JAVA_CRT_JVM_OUT_OF_MEMORY);
608 }
609
610 jint body_response_result = 0;
611
612 if (callback_data->java_s3_meta_request_response_handler_native_adapter != NULL) {
613 body_response_result = (*env)->CallIntMethod(
614 env,
615 callback_data->java_s3_meta_request_response_handler_native_adapter,
616 s3_meta_request_response_handler_native_adapter_properties.onResponseBody,
617 jni_payload,
618 range_start,
619 range_end);
620
621 if (aws_jni_get_and_clear_exception(env, &(callback_data->java_exception))) {
622 AWS_LOGF_ERROR(
623 AWS_LS_S3_META_REQUEST,
624 "id=%p: Received exception from S3MetaRequest.onResponseBody callback",
625 (void *)meta_request);
626 aws_raise_error(AWS_ERROR_HTTP_CALLBACK_FAILURE);
627 goto cleanup;
628 }
629
630 /* The Java onResponseBody API lets users return a size for auto-incrementing the read window */
631 if (body_response_result > 0) {
632 aws_s3_meta_request_increment_read_window(meta_request, (uint64_t)body_response_result);
633 }
634 }
635 return_value = AWS_OP_SUCCESS;
636
637 cleanup:
638 (*env)->DeleteLocalRef(env, jni_payload);
639
640 aws_jni_release_thread_env(callback_data->jvm, env);
641 /********** JNI ENV RELEASE **********/
642
643 return return_value;
644 }
645
s_marshal_http_headers_to_buf(const struct aws_http_headers * headers,struct aws_byte_buf * out_headers_buf)646 static int s_marshal_http_headers_to_buf(const struct aws_http_headers *headers, struct aws_byte_buf *out_headers_buf) {
647 /* calculate initial header capacity */
648 size_t headers_initial_capacity = 0;
649 for (size_t header_index = 0; header_index < aws_http_headers_count(headers); ++header_index) {
650 struct aws_http_header header;
651 aws_http_headers_get_index(headers, header_index, &header);
652 /* aws_marshal_http_headers_array_to_dynamic_buffer() impl drives this calculation */
653 headers_initial_capacity += header.name.len + header.value.len + 8;
654 }
655
656 struct aws_allocator *allocator = aws_jni_get_allocator();
657
658 if (aws_byte_buf_init(out_headers_buf, allocator, headers_initial_capacity)) {
659 return AWS_OP_ERR;
660 }
661
662 if (aws_marshal_http_headers_to_dynamic_buffer(out_headers_buf, headers)) {
663 aws_byte_buf_clean_up(out_headers_buf);
664 return AWS_OP_ERR;
665 }
666
667 return AWS_OP_SUCCESS;
668 }
669
s_on_s3_meta_request_headers_callback(struct aws_s3_meta_request * meta_request,const struct aws_http_headers * headers,int response_status,void * user_data)670 static int s_on_s3_meta_request_headers_callback(
671 struct aws_s3_meta_request *meta_request,
672 const struct aws_http_headers *headers,
673 int response_status,
674 void *user_data) {
675 int return_value = AWS_OP_ERR;
676 struct s3_client_make_meta_request_callback_data *callback_data =
677 (struct s3_client_make_meta_request_callback_data *)user_data;
678
679 /********** JNI ENV ACQUIRE **********/
680 JNIEnv *env = aws_jni_acquire_thread_env(callback_data->jvm);
681 if (env == NULL) {
682 /* If we can't get an environment, then the JVM is probably shutting down. Don't crash. */
683 return AWS_OP_ERR;
684 }
685
686 jobject java_headers_buffer = NULL;
687 struct aws_byte_buf headers_buf;
688 AWS_ZERO_STRUCT(headers_buf);
689
690 if (s_marshal_http_headers_to_buf(headers, &headers_buf)) {
691 goto cleanup;
692 }
693
694 java_headers_buffer = aws_jni_direct_byte_buffer_from_raw_ptr(env, headers_buf.buffer, headers_buf.len);
695 if (java_headers_buffer == NULL) {
696 aws_jni_check_and_clear_exception(env);
697 aws_raise_error(AWS_ERROR_JAVA_CRT_JVM_OUT_OF_MEMORY);
698 goto cleanup;
699 }
700
701 if (callback_data->java_s3_meta_request_response_handler_native_adapter != NULL) {
702 (*env)->CallVoidMethod(
703 env,
704 callback_data->java_s3_meta_request_response_handler_native_adapter,
705 s3_meta_request_response_handler_native_adapter_properties.onResponseHeaders,
706 response_status,
707 java_headers_buffer);
708
709 if (aws_jni_get_and_clear_exception(env, &(callback_data->java_exception))) {
710 AWS_LOGF_ERROR(
711 AWS_LS_S3_META_REQUEST,
712 "id=%p: Exception thrown from S3MetaRequest.onResponseHeaders callback",
713 (void *)meta_request);
714
715 aws_raise_error(AWS_ERROR_HTTP_CALLBACK_FAILURE);
716 goto cleanup;
717 }
718 }
719 return_value = AWS_OP_SUCCESS;
720
721 cleanup:
722 aws_byte_buf_clean_up(&headers_buf);
723 if (java_headers_buffer) {
724 (*env)->DeleteLocalRef(env, java_headers_buffer);
725 }
726
727 aws_jni_release_thread_env(callback_data->jvm, env);
728 /********** JNI ENV RELEASE **********/
729
730 return return_value;
731 }
732
s_on_s3_meta_request_finish_callback(struct aws_s3_meta_request * meta_request,const struct aws_s3_meta_request_result * meta_request_result,void * user_data)733 static void s_on_s3_meta_request_finish_callback(
734 struct aws_s3_meta_request *meta_request,
735 const struct aws_s3_meta_request_result *meta_request_result,
736 void *user_data) {
737
738 (void)meta_request;
739
740 struct s3_client_make_meta_request_callback_data *callback_data =
741 (struct s3_client_make_meta_request_callback_data *)user_data;
742
743 /********** JNI ENV ACQUIRE **********/
744 JNIEnv *env = aws_jni_acquire_thread_env(callback_data->jvm);
745 if (env == NULL) {
746 /* If we can't get an environment, then the JVM is probably shutting down. Don't crash. */
747 return;
748 }
749
750 if (callback_data->java_s3_meta_request_response_handler_native_adapter != NULL) {
751 struct aws_byte_buf *error_response_body = meta_request_result->error_response_body;
752 struct aws_byte_cursor error_response_cursor;
753 AWS_ZERO_STRUCT(error_response_cursor);
754 if (error_response_body) {
755 error_response_cursor = aws_byte_cursor_from_buf(error_response_body);
756 }
757 jbyteArray jni_payload = aws_jni_byte_array_from_cursor(env, &error_response_cursor);
758 /* Only propagate java_exception if crt error code is callback failure */
759 jthrowable java_exception =
760 meta_request_result->error_code == AWS_ERROR_HTTP_CALLBACK_FAILURE ? callback_data->java_exception : NULL;
761
762 jobject java_error_headers_buffer = NULL;
763 struct aws_byte_buf headers_buf;
764 AWS_ZERO_STRUCT(headers_buf);
765 if (meta_request_result->error_response_headers) {
766 /* Ignore any errors and just report the original error without headers */
767 if (s_marshal_http_headers_to_buf(meta_request_result->error_response_headers, &headers_buf) ==
768 AWS_OP_SUCCESS) {
769 java_error_headers_buffer =
770 aws_jni_direct_byte_buffer_from_raw_ptr(env, headers_buf.buffer, headers_buf.len);
771 if (java_error_headers_buffer == NULL) {
772 AWS_LOGF_ERROR(
773 AWS_LS_S3_META_REQUEST,
774 "id=%p: Ignored Exception from "
775 "S3MetaRequest.onFinished.aws_jni_direct_byte_buffer_from_raw_ptr",
776 (void *)meta_request);
777 aws_jni_check_and_clear_exception(env);
778 }
779 } else {
780 AWS_LOGF_ERROR(
781 AWS_LS_S3_META_REQUEST,
782 "id=%p: Ignored Exception from S3MetaRequest.onFinished.s_marshal_http_headers_to_buf",
783 (void *)meta_request);
784 }
785 }
786
787 (*env)->CallVoidMethod(
788 env,
789 callback_data->java_s3_meta_request_response_handler_native_adapter,
790 s3_meta_request_response_handler_native_adapter_properties.onFinished,
791 meta_request_result->error_code,
792 meta_request_result->response_status,
793 jni_payload,
794 meta_request_result->validation_algorithm,
795 meta_request_result->did_validate,
796 java_exception,
797 java_error_headers_buffer);
798
799 if (aws_jni_check_and_clear_exception(env)) {
800 AWS_LOGF_ERROR(
801 AWS_LS_S3_META_REQUEST,
802 "id=%p: Ignored Exception from S3MetaRequest.onFinished callback",
803 (void *)meta_request);
804 }
805 if (jni_payload) {
806 (*env)->DeleteLocalRef(env, jni_payload);
807 }
808
809 aws_byte_buf_clean_up(&headers_buf);
810 if (java_error_headers_buffer) {
811 (*env)->DeleteLocalRef(env, java_error_headers_buffer);
812 }
813 }
814
815 aws_jni_release_thread_env(callback_data->jvm, env);
816 /********** JNI ENV RELEASE **********/
817 }
818
s_on_s3_meta_request_progress_callback(struct aws_s3_meta_request * meta_request,const struct aws_s3_meta_request_progress * progress,void * user_data)819 static void s_on_s3_meta_request_progress_callback(
820 struct aws_s3_meta_request *meta_request,
821 const struct aws_s3_meta_request_progress *progress,
822 void *user_data) {
823
824 (void)meta_request;
825
826 struct s3_client_make_meta_request_callback_data *callback_data =
827 (struct s3_client_make_meta_request_callback_data *)user_data;
828
829 /********** JNI ENV ACQUIRE **********/
830 JNIEnv *env = aws_jni_acquire_thread_env(callback_data->jvm);
831 if (env == NULL) {
832 /* If we can't get an environment, then the JVM is probably shutting down. Don't crash. */
833 return;
834 }
835
836 jobject progress_object = (*env)->NewObject(
837 env,
838 s3_meta_request_progress_properties.s3_meta_request_progress_class,
839 s3_meta_request_progress_properties.s3_meta_request_progress_constructor_method_id);
840 if ((*env)->ExceptionCheck(env) || progress_object == NULL) {
841 aws_jni_throw_runtime_exception(
842 env, "S3MetaRequestResponseHandler.onProgress: Failed to create S3MetaRequestProgress object.");
843 goto done;
844 }
845
846 (*env)->SetLongField(
847 env,
848 progress_object,
849 s3_meta_request_progress_properties.bytes_transferred_field_id,
850 progress->bytes_transferred);
851 (*env)->SetLongField(
852 env, progress_object, s3_meta_request_progress_properties.content_length_field_id, progress->content_length);
853
854 if (callback_data->java_s3_meta_request_response_handler_native_adapter != NULL) {
855
856 (*env)->CallVoidMethod(
857 env,
858 callback_data->java_s3_meta_request_response_handler_native_adapter,
859 s3_meta_request_response_handler_native_adapter_properties.onProgress,
860 progress_object);
861
862 if (aws_jni_check_and_clear_exception(env)) {
863 AWS_LOGF_ERROR(
864 AWS_LS_S3_META_REQUEST,
865 "id=%p: Ignored Exception from S3MetaRequest.onProgress callback",
866 (void *)meta_request);
867 }
868 }
869
870 (*env)->DeleteLocalRef(env, progress_object);
871
872 done:
873
874 aws_jni_release_thread_env(callback_data->jvm, env);
875 /********** JNI ENV RELEASE **********/
876 }
877
s_s3_meta_request_callback_cleanup(JNIEnv * env,struct s3_client_make_meta_request_callback_data * callback_data)878 static void s_s3_meta_request_callback_cleanup(
879 JNIEnv *env,
880 struct s3_client_make_meta_request_callback_data *callback_data) {
881 if (callback_data) {
882 (*env)->DeleteGlobalRef(env, callback_data->java_s3_meta_request);
883 (*env)->DeleteGlobalRef(env, callback_data->java_s3_meta_request_response_handler_native_adapter);
884 (*env)->DeleteGlobalRef(env, callback_data->java_exception);
885 aws_signing_config_data_clean_up(&callback_data->signing_config_data, env);
886 aws_mem_release(aws_jni_get_allocator(), callback_data);
887 }
888 }
889
s_native_resume_token_from_java_new(JNIEnv * env,jobject resume_token_jni)890 static struct aws_s3_meta_request_resume_token *s_native_resume_token_from_java_new(
891 JNIEnv *env,
892 jobject resume_token_jni) {
893
894 if (resume_token_jni == NULL) {
895 return NULL;
896 }
897
898 struct aws_allocator *allocator = aws_jni_get_allocator();
899
900 jint native_type =
901 (*env)->GetIntField(env, resume_token_jni, s3_meta_request_resume_token_properties.native_type_field_id);
902
903 if (native_type != AWS_S3_META_REQUEST_TYPE_PUT_OBJECT) {
904 aws_jni_throw_illegal_argument_exception(
905 env, "ResumeToken: Operations other than PutObject are not supported for resume.");
906 return NULL;
907 }
908
909 jlong part_size_jni =
910 (*env)->GetLongField(env, resume_token_jni, s3_meta_request_resume_token_properties.part_size_field_id);
911 jlong total_num_parts_jni =
912 (*env)->GetLongField(env, resume_token_jni, s3_meta_request_resume_token_properties.total_num_parts_field_id);
913 jlong num_parts_completed_jni = (*env)->GetLongField(
914 env, resume_token_jni, s3_meta_request_resume_token_properties.num_parts_completed_field_id);
915
916 jstring upload_id_jni =
917 (*env)->GetObjectField(env, resume_token_jni, s3_meta_request_resume_token_properties.upload_id_field_id);
918 if (upload_id_jni == NULL) {
919 aws_jni_throw_illegal_argument_exception(env, "ResumeToken: UploadId must not be NULL.");
920 return NULL;
921 }
922
923 struct aws_string *upload_id = aws_jni_new_string_from_jstring(env, upload_id_jni);
924
925 struct aws_s3_upload_resume_token_options upload_options = {
926 .part_size = (uint64_t)part_size_jni,
927 .total_num_parts = (size_t)total_num_parts_jni,
928 .num_parts_completed = (size_t)num_parts_completed_jni,
929 .upload_id = aws_byte_cursor_from_string(upload_id),
930 };
931
932 struct aws_s3_meta_request_resume_token *resume_token =
933 aws_s3_meta_request_resume_token_new_upload(allocator, &upload_options);
934 aws_string_destroy(upload_id);
935
936 return resume_token;
937 }
938
Java_software_amazon_awssdk_crt_s3_S3Client_s3ClientMakeMetaRequest(JNIEnv * env,jclass jni_class,jlong jni_s3_client,jobject java_s3_meta_request_jobject,jbyteArray jni_region,jint meta_request_type,jint checksum_location,jint checksum_algorithm,jboolean validate_response,jintArray jni_marshalled_validate_algorithms,jbyteArray jni_marshalled_message_data,jobject jni_http_request_body_stream,jbyteArray jni_request_filepath,jobject java_signing_config,jobject java_response_handler_jobject,jbyteArray jni_endpoint,jobject java_resume_token_jobject)939 JNIEXPORT jlong JNICALL Java_software_amazon_awssdk_crt_s3_S3Client_s3ClientMakeMetaRequest(
940 JNIEnv *env,
941 jclass jni_class,
942 jlong jni_s3_client,
943 jobject java_s3_meta_request_jobject,
944 jbyteArray jni_region,
945 jint meta_request_type,
946 jint checksum_location,
947 jint checksum_algorithm,
948 jboolean validate_response,
949 jintArray jni_marshalled_validate_algorithms,
950 jbyteArray jni_marshalled_message_data,
951 jobject jni_http_request_body_stream,
952 jbyteArray jni_request_filepath,
953 jobject java_signing_config,
954 jobject java_response_handler_jobject,
955 jbyteArray jni_endpoint,
956 jobject java_resume_token_jobject) {
957 (void)jni_class;
958 aws_cache_jni_ids(env);
959
960 struct aws_allocator *allocator = aws_jni_get_allocator();
961 struct aws_s3_client *client = (struct aws_s3_client *)jni_s3_client;
962 struct aws_byte_cursor request_filepath;
963 AWS_ZERO_STRUCT(request_filepath);
964 struct aws_s3_meta_request_resume_token *resume_token =
965 s_native_resume_token_from_java_new(env, java_resume_token_jobject);
966 struct aws_s3_meta_request *meta_request = NULL;
967 bool success = false;
968 struct aws_byte_cursor region = aws_jni_byte_cursor_from_jbyteArray_acquire(env, jni_region);
969 struct aws_http_message *request_message = NULL;
970
971 struct s3_client_make_meta_request_callback_data *callback_data =
972 aws_mem_calloc(allocator, 1, sizeof(struct s3_client_make_meta_request_callback_data));
973 AWS_FATAL_ASSERT(callback_data);
974 struct aws_signing_config_aws signing_config;
975 AWS_ZERO_STRUCT(signing_config);
976 if (java_signing_config != NULL) {
977 if (aws_build_signing_config(env, java_signing_config, &callback_data->signing_config_data, &signing_config)) {
978 goto done;
979 }
980 }
981
982 jint jvmresult = (*env)->GetJavaVM(env, &callback_data->jvm);
983 (void)jvmresult;
984 AWS_FATAL_ASSERT(jvmresult == 0);
985
986 callback_data->java_s3_meta_request = (*env)->NewGlobalRef(env, java_s3_meta_request_jobject);
987 AWS_FATAL_ASSERT(callback_data->java_s3_meta_request != NULL);
988
989 callback_data->java_s3_meta_request_response_handler_native_adapter =
990 (*env)->NewGlobalRef(env, java_response_handler_jobject);
991 AWS_FATAL_ASSERT(callback_data->java_s3_meta_request_response_handler_native_adapter != NULL);
992
993 request_message = aws_http_message_new_request(allocator);
994 AWS_FATAL_ASSERT(request_message);
995
996 AWS_FATAL_ASSERT(
997 AWS_OP_SUCCESS == aws_apply_java_http_request_changes_to_native_request(
998 env, jni_marshalled_message_data, jni_http_request_body_stream, request_message));
999
1000 if (jni_request_filepath) {
1001 request_filepath = aws_jni_byte_cursor_from_jbyteArray_acquire(env, jni_request_filepath);
1002 if (request_filepath.ptr == NULL) {
1003 goto done;
1004 }
1005 if (request_filepath.len == 0) {
1006 aws_jni_throw_illegal_argument_exception(env, "Request file path cannot be empty");
1007 goto done;
1008 }
1009 }
1010
1011 struct aws_uri endpoint;
1012 AWS_ZERO_STRUCT(endpoint);
1013 if (jni_endpoint != NULL) {
1014 struct aws_byte_cursor endpoint_str = aws_jni_byte_cursor_from_jbyteArray_acquire(env, jni_endpoint);
1015 int uri_parse = aws_uri_init_parse(&endpoint, allocator, &endpoint_str);
1016 aws_jni_byte_cursor_from_jbyteArray_release(env, jni_endpoint, endpoint_str);
1017 if (uri_parse) {
1018 aws_jni_throw_runtime_exception(env, "S3Client.aws_s3_client_make_meta_request: failed to parse endpoint");
1019 goto done;
1020 }
1021 }
1022
1023 struct aws_s3_checksum_config checksum_config = {
1024 .location = checksum_location,
1025 .checksum_algorithm = checksum_algorithm,
1026 .validate_response_checksum = validate_response,
1027 };
1028
1029 struct aws_array_list response_checksum_list;
1030 AWS_ZERO_STRUCT(response_checksum_list);
1031 if (jni_marshalled_validate_algorithms != NULL) {
1032 jint *marshalled_algorithms = (*env)->GetIntArrayElements(env, jni_marshalled_validate_algorithms, NULL);
1033 const size_t marshalled_len = (*env)->GetArrayLength(env, jni_marshalled_validate_algorithms);
1034 aws_array_list_init_dynamic(&response_checksum_list, allocator, marshalled_len, sizeof(int));
1035 for (size_t i = 0; i < marshalled_len; ++i) {
1036 enum aws_s3_checksum_algorithm algorithm = (int)marshalled_algorithms[i];
1037 aws_array_list_push_back(&response_checksum_list, &algorithm);
1038 }
1039 checksum_config.validate_checksum_algorithms = &response_checksum_list;
1040 }
1041
1042 struct aws_s3_meta_request_options meta_request_options = {
1043 .type = meta_request_type,
1044 .checksum_config = &checksum_config,
1045 .message = request_message,
1046 .send_filepath = request_filepath,
1047 .user_data = callback_data,
1048 .signing_config = java_signing_config ? &signing_config : NULL,
1049 .headers_callback = s_on_s3_meta_request_headers_callback,
1050 .body_callback = s_on_s3_meta_request_body_callback,
1051 .finish_callback = s_on_s3_meta_request_finish_callback,
1052 .progress_callback = s_on_s3_meta_request_progress_callback,
1053 .shutdown_callback = s_on_s3_meta_request_shutdown_complete_callback,
1054 .endpoint = jni_endpoint != NULL ? &endpoint : NULL,
1055 .resume_token = resume_token,
1056 };
1057
1058 meta_request = aws_s3_client_make_meta_request(client, &meta_request_options);
1059 /* We are done using the list, it can be safely cleaned up now. */
1060 aws_array_list_clean_up(&response_checksum_list);
1061 if (!meta_request) {
1062 aws_jni_throw_runtime_exception(
1063 env, "S3Client.aws_s3_client_make_meta_request: creating aws_s3_meta_request failed");
1064 goto done;
1065 }
1066
1067 success = true;
1068
1069 done:
1070 aws_s3_meta_request_resume_token_release(resume_token);
1071 aws_jni_byte_cursor_from_jbyteArray_release(env, jni_region, region);
1072 aws_http_message_release(request_message);
1073 aws_jni_byte_cursor_from_jbyteArray_release(env, jni_request_filepath, request_filepath);
1074 aws_uri_clean_up(&endpoint);
1075 if (success) {
1076 return (jlong)meta_request;
1077 }
1078 s_s3_meta_request_callback_cleanup(env, callback_data);
1079 return (jlong)0;
1080 }
1081
s_on_s3_meta_request_shutdown_complete_callback(void * user_data)1082 static void s_on_s3_meta_request_shutdown_complete_callback(void *user_data) {
1083 struct s3_client_make_meta_request_callback_data *callback_data =
1084 (struct s3_client_make_meta_request_callback_data *)user_data;
1085
1086 /********** JNI ENV ACQUIRE **********/
1087 JNIEnv *env = aws_jni_acquire_thread_env(callback_data->jvm);
1088 if (env == NULL) {
1089 /* If we can't get an environment, then the JVM is probably shutting down. Don't crash. */
1090 return;
1091 }
1092
1093 if (callback_data->java_s3_meta_request != NULL) {
1094 (*env)->CallVoidMethod(env, callback_data->java_s3_meta_request, s3_meta_request_properties.onShutdownComplete);
1095
1096 if (aws_jni_check_and_clear_exception(env)) {
1097 AWS_LOGF_ERROR(
1098 AWS_LS_S3_META_REQUEST,
1099 "id=%p: Ignored Exception from S3MetaRequest.onShutdownCompete callback",
1100 (void *)callback_data->java_s3_meta_request);
1101 }
1102 }
1103
1104 // We're done with this callback data, free it.
1105 JavaVM *jvm = callback_data->jvm;
1106 s_s3_meta_request_callback_cleanup(env, callback_data);
1107
1108 aws_jni_release_thread_env(jvm, env);
1109 /********** JNI ENV RELEASE **********/
1110 }
1111
Java_software_amazon_awssdk_crt_s3_S3MetaRequest_s3MetaRequestDestroy(JNIEnv * env,jclass jni_class,jlong jni_s3_meta_request)1112 JNIEXPORT void JNICALL Java_software_amazon_awssdk_crt_s3_S3MetaRequest_s3MetaRequestDestroy(
1113 JNIEnv *env,
1114 jclass jni_class,
1115 jlong jni_s3_meta_request) {
1116 (void)jni_class;
1117 aws_cache_jni_ids(env);
1118
1119 struct aws_s3_meta_request *meta_request = (struct aws_s3_meta_request *)jni_s3_meta_request;
1120 if (!meta_request) {
1121 aws_raise_error(AWS_ERROR_INVALID_ARGUMENT);
1122 aws_jni_throw_runtime_exception(env, "S3MetaRequest.s3MetaRequestDestroy: Invalid/null meta request");
1123 return;
1124 }
1125
1126 aws_s3_meta_request_release(meta_request);
1127 }
1128
Java_software_amazon_awssdk_crt_s3_S3MetaRequest_s3MetaRequestCancel(JNIEnv * env,jclass jni_class,jlong jni_s3_meta_request)1129 JNIEXPORT void JNICALL Java_software_amazon_awssdk_crt_s3_S3MetaRequest_s3MetaRequestCancel(
1130 JNIEnv *env,
1131 jclass jni_class,
1132 jlong jni_s3_meta_request) {
1133
1134 (void)jni_class;
1135 aws_cache_jni_ids(env);
1136
1137 struct aws_s3_meta_request *meta_request = (struct aws_s3_meta_request *)jni_s3_meta_request;
1138 if (!meta_request) {
1139 /* It's fine if this particular function does nothing when it's called
1140 * after CrtResource is closed and the handle is NULL */
1141 return;
1142 }
1143
1144 aws_s3_meta_request_cancel(meta_request);
1145 }
1146
Java_software_amazon_awssdk_crt_s3_S3MetaRequest_s3MetaRequestPause(JNIEnv * env,jclass jni_class,jlong jni_s3_meta_request)1147 JNIEXPORT jobject JNICALL Java_software_amazon_awssdk_crt_s3_S3MetaRequest_s3MetaRequestPause(
1148 JNIEnv *env,
1149 jclass jni_class,
1150 jlong jni_s3_meta_request) {
1151
1152 (void)jni_class;
1153 aws_cache_jni_ids(env);
1154
1155 struct aws_s3_meta_request *meta_request = (struct aws_s3_meta_request *)jni_s3_meta_request;
1156 if (!meta_request) {
1157 aws_raise_error(AWS_ERROR_INVALID_ARGUMENT);
1158 aws_jni_throw_illegal_argument_exception(env, "S3MetaRequest.s3MetaRequestPause: Invalid/null meta request");
1159 return NULL;
1160 }
1161
1162 struct aws_s3_meta_request_resume_token *resume_token = NULL;
1163
1164 if (aws_s3_meta_request_pause(meta_request, &resume_token)) {
1165 aws_jni_throw_runtime_exception(env, "S3MetaRequest.s3MetaRequestPause: Failed to pause request");
1166 return NULL;
1167 }
1168
1169 jobject resume_token_jni = NULL;
1170 if (resume_token != NULL) {
1171 resume_token_jni = (*env)->NewObject(
1172 env,
1173 s3_meta_request_resume_token_properties.s3_meta_request_resume_token_class,
1174 s3_meta_request_resume_token_properties.s3_meta_request_resume_token_constructor_method_id);
1175 if ((*env)->ExceptionCheck(env) || resume_token_jni == NULL) {
1176 aws_jni_throw_runtime_exception(env, "S3MetaRequest.s3MetaRequestPause: Failed to create ResumeToken.");
1177 goto on_done;
1178 }
1179
1180 enum aws_s3_meta_request_type type = aws_s3_meta_request_resume_token_type(resume_token);
1181 if (type != AWS_S3_META_REQUEST_TYPE_PUT_OBJECT) {
1182 aws_jni_throw_runtime_exception(env, "S3MetaRequest.s3MetaRequestPause: Failed to convert resume token.");
1183 goto on_done;
1184 }
1185
1186 (*env)->SetIntField(env, resume_token_jni, s3_meta_request_resume_token_properties.native_type_field_id, type);
1187 (*env)->SetLongField(
1188 env,
1189 resume_token_jni,
1190 s3_meta_request_resume_token_properties.part_size_field_id,
1191 aws_s3_meta_request_resume_token_part_size(resume_token));
1192 (*env)->SetLongField(
1193 env,
1194 resume_token_jni,
1195 s3_meta_request_resume_token_properties.total_num_parts_field_id,
1196 aws_s3_meta_request_resume_token_total_num_parts(resume_token));
1197 (*env)->SetLongField(
1198 env,
1199 resume_token_jni,
1200 s3_meta_request_resume_token_properties.num_parts_completed_field_id,
1201 aws_s3_meta_request_resume_token_num_parts_completed(resume_token));
1202
1203 struct aws_byte_cursor upload_id_cur = aws_s3_meta_request_resume_token_upload_id(resume_token);
1204 jstring upload_id_jni = aws_jni_string_from_cursor(env, &upload_id_cur);
1205 (*env)->SetObjectField(
1206 env, resume_token_jni, s3_meta_request_resume_token_properties.upload_id_field_id, upload_id_jni);
1207
1208 (*env)->DeleteLocalRef(env, upload_id_jni);
1209 }
1210
1211 on_done:
1212 aws_s3_meta_request_resume_token_release(resume_token);
1213 return resume_token_jni;
1214 }
1215
Java_software_amazon_awssdk_crt_s3_S3MetaRequest_s3MetaRequestIncrementReadWindow(JNIEnv * env,jclass jni_class,jlong jni_s3_meta_request,jlong increment)1216 JNIEXPORT void JNICALL Java_software_amazon_awssdk_crt_s3_S3MetaRequest_s3MetaRequestIncrementReadWindow(
1217 JNIEnv *env,
1218 jclass jni_class,
1219 jlong jni_s3_meta_request,
1220 jlong increment) {
1221
1222 (void)jni_class;
1223 aws_cache_jni_ids(env);
1224
1225 struct aws_s3_meta_request *meta_request = (struct aws_s3_meta_request *)jni_s3_meta_request;
1226 if (!meta_request) {
1227 /* It's fine if this particular function does nothing when it's called
1228 * after CrtResource is closed and the handle is NULL */
1229 return;
1230 }
1231
1232 if (increment < 0) {
1233 aws_jni_throw_illegal_argument_exception(
1234 env, "S3MetaRequest.s3MetaRequestIncrementReadWindow: Number cannot be negative");
1235 return;
1236 }
1237
1238 aws_s3_meta_request_increment_read_window(meta_request, (uint64_t)increment);
1239 }
1240
1241 #if UINTPTR_MAX == 0xffffffff
1242 # if defined(_MSC_VER)
1243 # pragma warning(pop)
1244 # else
1245 # pragma GCC diagnostic pop
1246 # endif
1247 #endif
1248