Skip to content

Commit d1fe086

Browse files
committed
let's see what breaks
1 parent e6a395b commit d1fe086

File tree

5 files changed

+83
-64
lines changed

5 files changed

+83
-64
lines changed

include/aws/s3/private/s3_util.h

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -249,12 +249,21 @@ void aws_s3_add_user_agent_header(struct aws_allocator *allocator, struct aws_ht
249249
* object-size. All output arguments are optional.*/
250250
AWS_S3_API
251251
int aws_s3_parse_content_range_response_header(
252-
struct aws_allocator *allocator,
253252
struct aws_http_headers *response_headers,
254253
uint64_t *out_range_start,
255254
uint64_t *out_range_end,
256255
uint64_t *out_object_size);
257256

257+
/* Given a Content-Range header value as a byte cursor, parses the range-start, range-end and
258+
* object-size. All output arguments are optional. This is an optimized version that doesn't
259+
* require string allocation. */
260+
AWS_S3_API
261+
int aws_s3_parse_content_range_cursor(
262+
struct aws_byte_cursor content_range_cursor,
263+
uint64_t *out_range_start,
264+
uint64_t *out_range_end,
265+
uint64_t *out_object_size);
266+
258267
/* Given response headers, parses the content-length from a content-length response header.*/
259268
AWS_S3_API
260269
int aws_s3_parse_content_length_response_header(

source/s3_auto_ranged_get.c

Lines changed: 3 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -613,11 +613,7 @@ static int s_discover_object_range_and_size(
613613
object_range_end = content_length - 1; /* range-end is inclusive */
614614
}
615615
} else if (aws_s3_parse_content_range_response_header(
616-
meta_request->allocator,
617-
request->send_data.response_headers,
618-
&object_range_start,
619-
&object_range_end,
620-
&object_size)) {
616+
request->send_data.response_headers, &object_range_start, &object_range_end, &object_size)) {
621617

622618
AWS_LOGF_ERROR(
623619
AWS_LS_S3_META_REQUEST,
@@ -648,7 +644,7 @@ static int s_discover_object_range_and_size(
648644
if (first_part_size > 0) {
649645
/* Parse the object size from the part response. */
650646
if (aws_s3_parse_content_range_response_header(
651-
meta_request->allocator, request->send_data.response_headers, NULL, NULL, &object_size)) {
647+
request->send_data.response_headers, NULL, NULL, &object_size)) {
652648

653649
AWS_LOGF_ERROR(
654650
AWS_LS_S3_META_REQUEST,
@@ -693,11 +689,7 @@ static int s_discover_object_range_and_size(
693689

694690
/* Parse the object size from the part response. */
695691
if (aws_s3_parse_content_range_response_header(
696-
meta_request->allocator,
697-
request->send_data.response_headers,
698-
&object_range_start,
699-
&object_range_end,
700-
&object_size)) {
692+
request->send_data.response_headers, &object_range_start, &object_range_end, &object_size)) {
701693

702694
AWS_LOGF_ERROR(
703695
AWS_LS_S3_META_REQUEST,

source/s3_meta_request.c

Lines changed: 18 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -1361,23 +1361,6 @@ static int s_s3_meta_request_incoming_headers(
13611361
s_get_part_response_headers_checksum_helper(connection, meta_request, headers, headers_count);
13621362
}
13631363

1364-
#if DEBUG_BUILD
1365-
/* Only perform this validation during debug build, since it's a programming bug and "expensive" for each response
1366-
* received */
1367-
if (successful_response && request->request_type == AWS_S3_REQUEST_TYPE_GET_OBJECT) {
1368-
uint64_t object_size = 0;
1369-
uint64_t object_range_start = 0;
1370-
uint64_t object_range_end = 0;
1371-
if (aws_s3_parse_content_range_response_header(
1372-
meta_request->allocator, headers, &object_range_start, &object_range_end, &object_size) ==
1373-
AWS_OP_SUCCESS) {
1374-
/* Validate that the content-range response matches the request. */
1375-
AWS_ASSERT(request->part_range_start == object_range_start);
1376-
AWS_ASSERT(request->part_range_end == object_range_end);
1377-
}
1378-
}
1379-
#endif /* DEBUG_BUILD */
1380-
13811364
/* Only record headers if an error has taken place, or if the request_desc has asked for them. */
13821365
bool should_record_headers = !successful_response || request->record_response_headers;
13831366

@@ -1400,6 +1383,24 @@ static int s_s3_meta_request_incoming_headers(
14001383
if (request->send_data.amz_id_2 == NULL && aws_byte_cursor_eq(name, &g_amz_id_2_header_name)) {
14011384
request->send_data.amz_id_2 = aws_string_new_from_cursor(connection->request->allocator, value);
14021385
}
1386+
if (aws_byte_cursor_eq(name, &g_content_range_header_name) && successful_response &&
1387+
request->request_type == AWS_S3_REQUEST_TYPE_GET_OBJECT) {
1388+
uint64_t object_range_start = 0;
1389+
uint64_t object_range_end = 0;
1390+
if (aws_s3_parse_content_range_cursor(
1391+
*value, &object_range_start, &object_range_end, NULL /*Object Size*/)) {
1392+
AWS_LOGF_ERROR(
1393+
AWS_LS_S3_META_REQUEST,
1394+
"id=%p: Could not parse content range header (%s)",
1395+
(void *)meta_request,
1396+
aws_error_str(aws_last_error()));
1397+
return AWS_OP_ERR;
1398+
} else {
1399+
AWS_FATAL_ASSERT(request->part_range_start == object_range_start);
1400+
AWS_FATAL_ASSERT(request->part_range_end == object_range_end);
1401+
}
1402+
}
1403+
14031404
if (collect_metrics) {
14041405
aws_http_headers_add(request->send_data.metrics->req_resp_info_metrics.response_headers, *name, *value);
14051406
}

source/s3_util.c

Lines changed: 47 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -417,44 +417,52 @@ void aws_s3_add_user_agent_header(struct aws_allocator *allocator, struct aws_ht
417417
aws_byte_buf_clean_up(&user_agent_buffer);
418418
}
419419

420-
int aws_s3_parse_content_range_response_header(
421-
struct aws_allocator *allocator,
422-
struct aws_http_headers *response_headers,
420+
int aws_s3_parse_content_range_cursor(
421+
struct aws_byte_cursor content_range_cursor,
423422
uint64_t *out_range_start,
424423
uint64_t *out_range_end,
425424
uint64_t *out_object_size) {
426-
AWS_PRECONDITION(allocator);
427-
AWS_PRECONDITION(response_headers);
428425

429-
struct aws_byte_cursor content_range_header_value;
426+
/* Expected Format of header is: "bytes StartByte-EndByte/TotalObjectSize" */
430427

431-
if (aws_http_headers_get(response_headers, g_content_range_header_name, &content_range_header_value)) {
432-
aws_raise_error(AWS_ERROR_S3_MISSING_CONTENT_RANGE_HEADER);
433-
return AWS_OP_ERR;
428+
/* Check if it starts with "bytes " */
429+
struct aws_byte_cursor bytes_prefix = aws_byte_cursor_from_c_str("bytes ");
430+
if (!aws_byte_cursor_starts_with(&content_range_cursor, &bytes_prefix)) {
431+
return aws_raise_error(AWS_ERROR_S3_INVALID_CONTENT_RANGE_HEADER);
434432
}
435433

436-
int result = AWS_OP_ERR;
434+
/* Skip past "bytes " */
435+
aws_byte_cursor_advance(&content_range_cursor, bytes_prefix.len);
436+
437+
/* Parse range start */
438+
struct aws_byte_cursor range_start_cursor;
439+
if (!aws_byte_cursor_next_split(&content_range_cursor, '-', &range_start_cursor)) {
440+
return aws_raise_error(AWS_ERROR_S3_INVALID_CONTENT_RANGE_HEADER);
441+
}
437442

438443
uint64_t range_start = 0;
439-
uint64_t range_end = 0;
440-
uint64_t object_size = 0;
444+
if (aws_byte_cursor_utf8_parse_u64(range_start_cursor, &range_start)) {
445+
return aws_raise_error(AWS_ERROR_S3_INVALID_CONTENT_RANGE_HEADER);
446+
}
441447

442-
struct aws_string *content_range_header_value_str =
443-
aws_string_new_from_cursor(allocator, &content_range_header_value);
448+
/* Parse range end */
449+
struct aws_byte_cursor range_end_cursor;
450+
if (!aws_byte_cursor_next_split(&content_range_cursor, '/', &range_end_cursor)) {
451+
return aws_raise_error(AWS_ERROR_S3_INVALID_CONTENT_RANGE_HEADER);
452+
}
444453

445-
/* Expected Format of header is: "bytes StartByte-EndByte/TotalObjectSize" */
446-
int num_fields_found = sscanf(
447-
(const char *)content_range_header_value_str->bytes,
448-
"bytes %" PRIu64 "-%" PRIu64 "/%" PRIu64,
449-
&range_start,
450-
&range_end,
451-
&object_size);
454+
uint64_t range_end = 0;
455+
if (aws_byte_cursor_utf8_parse_u64(range_end_cursor, &range_end)) {
456+
return aws_raise_error(AWS_ERROR_S3_INVALID_CONTENT_RANGE_HEADER);
457+
}
452458

453-
if (num_fields_found < 3) {
454-
aws_raise_error(AWS_ERROR_S3_INVALID_CONTENT_RANGE_HEADER);
455-
goto clean_up;
459+
/* Parse object size (remaining part) */
460+
uint64_t object_size = 0;
461+
if (aws_byte_cursor_utf8_parse_u64(content_range_cursor, &object_size)) {
462+
return aws_raise_error(AWS_ERROR_S3_INVALID_CONTENT_RANGE_HEADER);
456463
}
457464

465+
/* Set output values */
458466
if (out_range_start != NULL) {
459467
*out_range_start = range_start;
460468
}
@@ -467,13 +475,23 @@ int aws_s3_parse_content_range_response_header(
467475
*out_object_size = object_size;
468476
}
469477

470-
result = AWS_OP_SUCCESS;
478+
return AWS_OP_SUCCESS;
479+
}
471480

472-
clean_up:
473-
aws_string_destroy(content_range_header_value_str);
474-
content_range_header_value_str = NULL;
481+
int aws_s3_parse_content_range_response_header(
482+
struct aws_http_headers *response_headers,
483+
uint64_t *out_range_start,
484+
uint64_t *out_range_end,
485+
uint64_t *out_object_size) {
486+
AWS_ERROR_PRECONDITION(response_headers);
487+
struct aws_byte_cursor content_range_header_value;
475488

476-
return result;
489+
if (aws_http_headers_get(response_headers, g_content_range_header_name, &content_range_header_value)) {
490+
aws_raise_error(AWS_ERROR_S3_MISSING_CONTENT_RANGE_HEADER);
491+
return AWS_OP_ERR;
492+
}
493+
return aws_s3_parse_content_range_cursor(
494+
content_range_header_value, out_range_start, out_range_end, out_object_size);
477495
}
478496

479497
int aws_s3_parse_content_length_response_header(

tests/s3_util_tests.c

Lines changed: 5 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -314,7 +314,7 @@ static int s_test_s3_parse_content_range_response_header(struct aws_allocator *a
314314
{
315315
uint64_t object_size = 0ULL;
316316

317-
ASSERT_FAILS(aws_s3_parse_content_range_response_header(allocator, response_headers, NULL, NULL, &object_size));
317+
ASSERT_FAILS(aws_s3_parse_content_range_response_header(response_headers, NULL, NULL, &object_size));
318318
ASSERT_TRUE(aws_last_error() == AWS_ERROR_S3_MISSING_CONTENT_RANGE_HEADER);
319319
}
320320

@@ -326,8 +326,8 @@ static int s_test_s3_parse_content_range_response_header(struct aws_allocator *a
326326
uint64_t range_start = 0ULL;
327327
uint64_t range_end = 0ULL;
328328

329-
ASSERT_SUCCESS(aws_s3_parse_content_range_response_header(
330-
allocator, response_headers, &range_start, &range_end, &object_size));
329+
ASSERT_SUCCESS(
330+
aws_s3_parse_content_range_response_header(response_headers, &range_start, &range_end, &object_size));
331331
ASSERT_TRUE(range_start == 55ULL);
332332
ASSERT_TRUE(range_end == 100ULL);
333333
ASSERT_TRUE(object_size == 12345ULL);
@@ -337,8 +337,7 @@ static int s_test_s3_parse_content_range_response_header(struct aws_allocator *a
337337
{
338338
uint64_t object_size = 0ULL;
339339

340-
ASSERT_SUCCESS(
341-
aws_s3_parse_content_range_response_header(allocator, response_headers, NULL, NULL, &object_size));
340+
ASSERT_SUCCESS(aws_s3_parse_content_range_response_header(response_headers, NULL, NULL, &object_size));
342341
ASSERT_TRUE(object_size == 12345ULL);
343342
}
344343

@@ -347,7 +346,7 @@ static int s_test_s3_parse_content_range_response_header(struct aws_allocator *a
347346
/* Try to parse an invalid header. */
348347
{
349348
uint64_t object_size = 0ULL;
350-
ASSERT_FAILS(aws_s3_parse_content_range_response_header(allocator, response_headers, NULL, NULL, &object_size));
349+
ASSERT_FAILS(aws_s3_parse_content_range_response_header(response_headers, NULL, NULL, &object_size));
351350
ASSERT_TRUE(aws_last_error() == AWS_ERROR_S3_INVALID_CONTENT_RANGE_HEADER);
352351
}
353352

0 commit comments

Comments
 (0)