Skip to content

Commit f1a52b5

Browse files
fix unknown checksum handling (#633)
1 parent 10be224 commit f1a52b5

12 files changed

Lines changed: 114 additions & 27 deletions

include/aws/s3/private/s3_checksum_context.h

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,8 @@ struct aws_s3_upload_request_checksum_context {
4040

4141
/* Validation */
4242
size_t encoded_checksum_size;
43+
44+
bool has_review_callback;
4345
};
4446

4547
/**
@@ -54,7 +56,8 @@ struct aws_s3_upload_request_checksum_context {
5456
AWS_S3_API
5557
struct aws_s3_upload_request_checksum_context *aws_s3_upload_request_checksum_context_new(
5658
struct aws_allocator *allocator,
57-
const struct aws_s3_meta_request_checksum_config_storage *checksum_config);
59+
const struct aws_s3_meta_request_checksum_config_storage *checksum_config,
60+
bool has_review_callback);
5861

5962
/**
6063
* Create a new upload request checksum context with an existing base64 encoded checksum value.
@@ -70,7 +73,8 @@ AWS_S3_API
7073
struct aws_s3_upload_request_checksum_context *aws_s3_upload_request_checksum_context_new_with_existing_base64_checksum(
7174
struct aws_allocator *allocator,
7275
const struct aws_s3_meta_request_checksum_config_storage *checksum_config,
73-
struct aws_byte_cursor existing_base64_checksum);
76+
struct aws_byte_cursor existing_base64_checksum,
77+
bool has_review_callback);
7478

7579
/**
7680
* Acquire a reference to the upload request checksum context.

include/aws/s3/private/s3_util.h

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -385,6 +385,14 @@ int aws_s3_calculate_request_optimal_range_size(
385385
AWS_S3_API
386386
int aws_s3_extract_parts_from_etag(struct aws_byte_cursor etag_header_value, uint32_t *out_num_parts);
387387

388+
/**
389+
* Helper to figure out if given header name is one of the checksum value headers.
390+
* ex. returns true for x-amz-checksum-crc32 or x-amz-checksum-sha256, but false for x-amz-checksum-type.
391+
* Note: relies on hardcoded list of non-checksum headers, which needs to be updated if s3 expands list of those.
392+
*/
393+
AWS_S3_API
394+
bool aws_s3_is_checksum_value_header_name(struct aws_byte_cursor header_name);
395+
388396
AWS_EXTERN_C_END
389397

390398
#endif /* AWS_S3_UTIL_H */

source/s3_auto_ranged_put.c

Lines changed: 9 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -200,10 +200,15 @@ static int s_process_part_info_synced(const struct aws_s3_part_info *info, void
200200
if ((checksum_cur != NULL) && (checksum_cur->len > 0)) {
201201
/* Create checksum context with pre-calculated checksum */
202202
part->checksum_context = aws_s3_upload_request_checksum_context_new_with_existing_base64_checksum(
203-
auto_ranged_put->base.allocator, &auto_ranged_put->base.checksum_config, *checksum_cur);
203+
auto_ranged_put->base.allocator,
204+
&auto_ranged_put->base.checksum_config,
205+
*checksum_cur,
206+
meta_request->upload_review_callback != NULL);
204207
} else {
205208
part->checksum_context = aws_s3_upload_request_checksum_context_new(
206-
auto_ranged_put->base.allocator, &auto_ranged_put->base.checksum_config);
209+
auto_ranged_put->base.allocator,
210+
&auto_ranged_put->base.checksum_config,
211+
meta_request->upload_review_callback != NULL);
207212
}
208213
if (part->checksum_context == NULL) {
209214
aws_mem_release(meta_request->allocator, part);
@@ -1072,8 +1077,8 @@ static int s_s3_new_upload_part_info_after_body(
10721077
/* Add part to array-list */
10731078
struct aws_s3_mpu_part_info *part =
10741079
aws_mem_calloc(meta_request->allocator, 1, sizeof(struct aws_s3_mpu_part_info));
1075-
part->checksum_context =
1076-
aws_s3_upload_request_checksum_context_new(meta_request->allocator, &meta_request->checksum_config);
1080+
part->checksum_context = aws_s3_upload_request_checksum_context_new(
1081+
meta_request->allocator, &meta_request->checksum_config, meta_request->upload_review_callback != NULL);
10771082
part->size = request->request_body.len;
10781083
aws_array_list_set_at(&auto_ranged_put->synced_data.part_list, &part, request->part_number - 1);
10791084
}

source/s3_checksum_context.c

Lines changed: 11 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,8 @@ static void s_aws_s3_upload_request_checksum_context_destroy(void *context) {
2525

2626
static struct aws_s3_upload_request_checksum_context *s_s3_upload_request_checksum_context_new_base(
2727
struct aws_allocator *allocator,
28-
const struct aws_s3_meta_request_checksum_config_storage *checksum_config) {
28+
const struct aws_s3_meta_request_checksum_config_storage *checksum_config,
29+
bool has_review_callback) {
2930
AWS_PRECONDITION(allocator);
3031

3132
struct aws_s3_upload_request_checksum_context *context =
@@ -48,6 +49,7 @@ static struct aws_s3_upload_request_checksum_context *s_s3_upload_request_checks
4849
context->algorithm = checksum_config->checksum_algorithm;
4950
context->location = checksum_config->location;
5051
context->encoded_checksum_size = aws_get_digest_size_from_checksum_algorithm(context->algorithm);
52+
context->has_review_callback = has_review_callback;
5153

5254
/* Convert to base64 encoded size */
5355
size_t encoded_size = 0;
@@ -62,9 +64,10 @@ static struct aws_s3_upload_request_checksum_context *s_s3_upload_request_checks
6264

6365
struct aws_s3_upload_request_checksum_context *aws_s3_upload_request_checksum_context_new(
6466
struct aws_allocator *allocator,
65-
const struct aws_s3_meta_request_checksum_config_storage *checksum_config) {
67+
const struct aws_s3_meta_request_checksum_config_storage *checksum_config,
68+
bool has_review_callback) {
6669
struct aws_s3_upload_request_checksum_context *context =
67-
s_s3_upload_request_checksum_context_new_base(allocator, checksum_config);
70+
s_s3_upload_request_checksum_context_new_base(allocator, checksum_config, has_review_callback);
6871
if (context && context->encoded_checksum_size > 0) {
6972
/* Initial the buffer for checksum */
7073
aws_byte_buf_init(&context->synced_data.base64_checksum, allocator, context->encoded_checksum_size);
@@ -75,9 +78,10 @@ struct aws_s3_upload_request_checksum_context *aws_s3_upload_request_checksum_co
7578
struct aws_s3_upload_request_checksum_context *aws_s3_upload_request_checksum_context_new_with_existing_base64_checksum(
7679
struct aws_allocator *allocator,
7780
const struct aws_s3_meta_request_checksum_config_storage *checksum_config,
78-
struct aws_byte_cursor existing_base64_checksum) {
81+
struct aws_byte_cursor existing_base64_checksum,
82+
bool has_review_callback) {
7983
struct aws_s3_upload_request_checksum_context *context =
80-
s_s3_upload_request_checksum_context_new_base(allocator, checksum_config);
84+
s_s3_upload_request_checksum_context_new_base(allocator, checksum_config, has_review_callback);
8185
if (context) {
8286
/* Initial the buffer for checksum from the exist checksum */
8387
if (context->encoded_checksum_size != existing_base64_checksum.len) {
@@ -115,7 +119,8 @@ struct aws_s3_upload_request_checksum_context *aws_s3_upload_request_checksum_co
115119
}
116120

117121
bool aws_s3_upload_request_checksum_context_should_calculate(struct aws_s3_upload_request_checksum_context *context) {
118-
if (!context || context->algorithm == AWS_SCA_NONE) {
122+
if (!context || context->algorithm == AWS_SCA_NONE || context->algorithm == AWS_SCA_UNKNOWN ||
123+
(context->location == AWS_SCL_NONE && !context->has_review_callback)) {
119124
return false;
120125
}
121126

source/s3_checksums.c

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -453,8 +453,6 @@ int aws_checksum_compute(
453453
}
454454
}
455455

456-
static const struct aws_byte_cursor s_checksum_prefix = AWS_BYTE_CUR_INIT_FROM_STRING_LITERAL("x-amz-checksum-");
457-
458456
static void s_byte_buf_to_upper(struct aws_byte_buf *buf) {
459457
AWS_PRECONDITION(buf);
460458

@@ -489,7 +487,7 @@ static int s_init_and_verify_checksum_config_from_headers(
489487
return aws_raise_error(AWS_ERROR_INVALID_ARGUMENT);
490488
}
491489

492-
if (aws_byte_cursor_starts_with_ignore_case(&header.name, &s_checksum_prefix)) {
490+
if (aws_s3_is_checksum_value_header_name(header.name)) {
493491
checksum_header_name = header.name;
494492
has_checksum_value_header = true;
495493
break;
@@ -551,7 +549,7 @@ static int s_init_and_verify_checksum_config_from_headers(
551549
checksum_config->location = AWS_SCL_NONE;
552550

553551
if (header_algo == AWS_SCA_UNKNOWN) {
554-
aws_byte_cursor_advance(&checksum_header_name, s_checksum_prefix.len);
552+
aws_byte_cursor_advance(&checksum_header_name, sizeof("x-amz-checksum-") - 1);
555553
aws_byte_buf_init_copy_from_cursor(
556554
&checksum_config->unknown_checksum_algo, checksum_config->allocator, checksum_header_name);
557555
s_byte_buf_to_upper(&checksum_config->unknown_checksum_algo);

source/s3_default_meta_request.c

Lines changed: 12 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -347,7 +347,7 @@ static void s_s3_default_prepare_request_finish(
347347
struct aws_http_message *message = aws_s3_message_util_copy_http_message_no_body_all_headers(
348348
meta_request->allocator, meta_request->initial_request_message);
349349

350-
bool flexible_checksum = meta_request->checksum_config.location != AWS_SCL_NONE;
350+
bool flexible_checksum = meta_request->checksum_config.checksum_algorithm != AWS_SCA_NONE;
351351
if (!flexible_checksum && meta_request->should_compute_content_md5) {
352352
/* If flexible checksum used, client MUST skip Content-MD5 header computation */
353353
aws_s3_message_util_add_content_md5_header(meta_request->allocator, &request->request_body, message);
@@ -362,8 +362,17 @@ static void s_s3_default_prepare_request_finish(
362362
/* Only PUT Object and Upload part support trailing checksum, that needs the special encoding even if the body
363363
* has 0 length. */
364364
/* Create checksum context from config if needed */
365-
struct aws_s3_upload_request_checksum_context *checksum_context =
366-
aws_s3_upload_request_checksum_context_new(meta_request->allocator, &meta_request->checksum_config);
365+
struct aws_s3_upload_request_checksum_context *checksum_context = NULL;
366+
367+
/**
368+
* Note: CompleteMPU is unique in the sence that checksum on the object level is the full object checksum for
369+
* all parts and not checksum of the body. So avoid any additional checksum handling if default req is
370+
* completeMPU.
371+
*/
372+
if (meta_request_default->request_type != AWS_S3_REQUEST_TYPE_COMPLETE_MULTIPART_UPLOAD) {
373+
checksum_context = aws_s3_upload_request_checksum_context_new(
374+
meta_request->allocator, &meta_request->checksum_config, meta_request->upload_review_callback != NULL);
375+
}
367376

368377
aws_s3_message_util_assign_body(
369378
meta_request->allocator, &request->request_body, NULL, message, checksum_context);

source/s3_request_messages.c

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -239,7 +239,6 @@ const struct aws_byte_cursor g_s3_create_session_allowed_headers[] = {
239239
const size_t g_s3_create_session_allowed_headers_count = AWS_ARRAY_SIZE(g_s3_create_session_allowed_headers);
240240

241241
static const struct aws_byte_cursor s_x_amz_meta_prefix = AWS_BYTE_CUR_INIT_FROM_STRING_LITERAL("x-amz-meta-");
242-
static const struct aws_byte_cursor s_x_amz_checksum_prefix = AWS_BYTE_CUR_INIT_FROM_STRING_LITERAL("x-amz-checksum-");
243242

244243
static const struct aws_byte_cursor s_checksum_type_header =
245244
AWS_BYTE_CUR_INIT_FROM_STRING_LITERAL("x-amz-checksum-type");
@@ -1234,7 +1233,7 @@ void aws_s3_message_util_copy_headers(
12341233
}
12351234

12361235
if (exclude_x_amz_checksum) {
1237-
if (aws_byte_cursor_starts_with_ignore_case(&header.name, &s_x_amz_checksum_prefix)) {
1236+
if (aws_s3_is_checksum_value_header_name(header.name)) {
12381237
continue;
12391238
}
12401239
}

source/s3_util.c

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1019,3 +1019,12 @@ int aws_s3_extract_parts_from_etag(struct aws_byte_cursor etag_header_value, uin
10191019

10201020
return AWS_OP_SUCCESS;
10211021
}
1022+
1023+
static const struct aws_byte_cursor s_checksum_prefix = AWS_BYTE_CUR_INIT_FROM_STRING_LITERAL("x-amz-checksum-");
1024+
1025+
bool aws_s3_is_checksum_value_header_name(struct aws_byte_cursor header_name) {
1026+
return aws_byte_cursor_starts_with_ignore_case(&header_name, &s_checksum_prefix) &&
1027+
!aws_byte_cursor_eq_c_str_ignore_case(&header_name, "x-amz-checksum-type") &&
1028+
!aws_byte_cursor_eq_c_str_ignore_case(&header_name, "x-amz-checksum-mode") &&
1029+
!aws_byte_cursor_eq_c_str_ignore_case(&header_name, "x-amz-checksum-algorithm");
1030+
}

tests/CMakeLists.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -261,6 +261,7 @@ add_test_case(test_s3_calculate_client_optimal_range_size)
261261
add_test_case(test_s3_calculate_request_optimal_range_size)
262262
add_test_case(test_s3_extract_parts_from_etag)
263263
add_test_case(test_add_user_agent_header)
264+
add_test_case(test_s3_checksum_header)
264265

265266
add_test_case(test_get_existing_platform_info)
266267
add_test_case(test_get_nonexistent_platform_info)

tests/s3_checksum_context_test.c

Lines changed: 35 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,7 @@ static int s_test_upload_request_checksum_context_get_checksum_cursor(struct aws
2121

2222
/* Test get checksum cursor with context that has no calculated checksum */
2323
struct aws_s3_upload_request_checksum_context *context =
24-
aws_s3_upload_request_checksum_context_new(allocator, &config);
24+
aws_s3_upload_request_checksum_context_new(allocator, &config, false);
2525
ASSERT_NOT_NULL(context);
2626

2727
struct aws_byte_cursor cursor = aws_s3_upload_request_checksum_context_get_checksum_cursor(context);
@@ -32,8 +32,8 @@ static int s_test_upload_request_checksum_context_get_checksum_cursor(struct aws
3232

3333
/* Test get checksum cursor with context that has calculated checksum */
3434
struct aws_byte_cursor existing_checksum = aws_byte_cursor_from_c_str("dGVzdA==");
35-
context =
36-
aws_s3_upload_request_checksum_context_new_with_existing_base64_checksum(allocator, &config, existing_checksum);
35+
context = aws_s3_upload_request_checksum_context_new_with_existing_base64_checksum(
36+
allocator, &config, existing_checksum, false);
3737
ASSERT_NOT_NULL(context);
3838

3939
cursor = aws_s3_upload_request_checksum_context_get_checksum_cursor(context);
@@ -49,6 +49,7 @@ static int s_test_upload_request_checksum_context_get_checksum_cursor(struct aws
4949

5050
return AWS_OP_SUCCESS;
5151
}
52+
5253
AWS_TEST_CASE(
5354
test_upload_request_checksum_context_get_checksum_cursor,
5455
s_test_upload_request_checksum_context_get_checksum_cursor)
@@ -68,7 +69,7 @@ static int s_test_upload_request_checksum_context_error_cases(struct aws_allocat
6869
struct aws_byte_cursor wrong_size_checksum = aws_byte_cursor_from_c_str("short");
6970
struct aws_s3_upload_request_checksum_context *context =
7071
aws_s3_upload_request_checksum_context_new_with_existing_base64_checksum(
71-
allocator, &config, wrong_size_checksum);
72+
allocator, &config, wrong_size_checksum, false);
7273
ASSERT_NULL(context);
7374

7475
/* Test helper functions with NULL context */
@@ -80,6 +81,35 @@ static int s_test_upload_request_checksum_context_error_cases(struct aws_allocat
8081
ASSERT_NULL(aws_s3_upload_request_checksum_context_acquire(NULL));
8182
ASSERT_NULL(aws_s3_upload_request_checksum_context_release(NULL));
8283

84+
/* unknown algo */
85+
struct aws_s3_meta_request_checksum_config_storage config2 = {
86+
.allocator = allocator,
87+
.checksum_algorithm = AWS_SCA_UNKNOWN,
88+
.location = AWS_SCL_NONE,
89+
.has_full_object_checksum = false,
90+
};
91+
struct aws_s3_upload_request_checksum_context *context2 =
92+
aws_s3_upload_request_checksum_context_new(allocator, &config2, false);
93+
94+
ASSERT_NOT_NULL(context2);
95+
ASSERT_FALSE(aws_s3_upload_request_checksum_context_should_calculate(context2));
96+
97+
/* unknown algo */
98+
struct aws_s3_meta_request_checksum_config_storage config3 = {
99+
.allocator = allocator,
100+
.checksum_algorithm = AWS_SCA_CRC32,
101+
.location = AWS_SCL_NONE,
102+
.has_full_object_checksum = false,
103+
};
104+
struct aws_s3_upload_request_checksum_context *context3 =
105+
aws_s3_upload_request_checksum_context_new(allocator, &config3, false);
106+
107+
ASSERT_NOT_NULL(context3);
108+
ASSERT_FALSE(aws_s3_upload_request_checksum_context_should_calculate(context3));
109+
110+
aws_s3_upload_request_checksum_context_release(context2);
111+
aws_s3_upload_request_checksum_context_release(context3);
112+
83113
return AWS_OP_SUCCESS;
84114
}
85115
AWS_TEST_CASE(test_upload_request_checksum_context_error_cases, s_test_upload_request_checksum_context_error_cases)
@@ -101,7 +131,7 @@ static int s_test_upload_request_checksum_context_different_algorithms(struct aw
101131
AWS_ZERO_STRUCT(config.full_object_checksum);
102132

103133
struct aws_s3_upload_request_checksum_context *context =
104-
aws_s3_upload_request_checksum_context_new(allocator, &config);
134+
aws_s3_upload_request_checksum_context_new(allocator, &config, false);
105135
ASSERT_NOT_NULL(context);
106136
ASSERT_INT_EQUALS(algorithms[i], context->algorithm);
107137
ASSERT_INT_EQUALS(AWS_SCL_HEADER, context->location);

0 commit comments

Comments
 (0)