in source/s3_auto_ranged_put.c [429:639]
static void s_s3_auto_ranged_put_request_finished(
struct aws_s3_meta_request *meta_request,
struct aws_s3_request *request,
int error_code) {
AWS_PRECONDITION(meta_request);
AWS_PRECONDITION(meta_request->impl);
AWS_PRECONDITION(request);
struct aws_s3_auto_ranged_put *auto_ranged_put = meta_request->impl;
switch (request->request_tag) {
case AWS_S3_AUTO_RANGED_PUT_REQUEST_TAG_CREATE_MULTIPART_UPLOAD: {
struct aws_http_headers *needed_response_headers = NULL;
if (error_code == AWS_ERROR_SUCCESS) {
needed_response_headers = aws_http_headers_new(meta_request->allocator);
const size_t copy_header_count =
sizeof(s_create_multipart_upload_copy_headers) / sizeof(struct aws_byte_cursor);
/* Copy any headers now that we'll need for the final, transformed headers later. */
for (size_t header_index = 0; header_index < copy_header_count; ++header_index) {
const struct aws_byte_cursor *header_name = &s_create_multipart_upload_copy_headers[header_index];
struct aws_byte_cursor header_value;
AWS_ZERO_STRUCT(header_value);
if (!aws_http_headers_get(request->send_data.response_headers, *header_name, &header_value)) {
aws_http_headers_set(needed_response_headers, *header_name, header_value);
}
}
struct aws_byte_cursor buffer_byte_cursor = aws_byte_cursor_from_buf(&request->send_data.response_body);
/* Find the upload id for this multipart upload. */
struct aws_string *upload_id =
get_top_level_xml_tag_value(meta_request->allocator, &s_upload_id, &buffer_byte_cursor);
if (upload_id == NULL) {
AWS_LOGF_ERROR(
AWS_LS_S3_META_REQUEST,
"id=%p Could not find upload-id in create-multipart-upload response",
(void *)meta_request);
aws_raise_error(AWS_ERROR_S3_MISSING_UPLOAD_ID);
error_code = AWS_ERROR_S3_MISSING_UPLOAD_ID;
} else {
/* Store the multipart upload id. */
auto_ranged_put->upload_id = upload_id;
}
}
aws_s3_meta_request_lock_synced_data(meta_request);
AWS_ASSERT(auto_ranged_put->synced_data.needed_response_headers == NULL)
auto_ranged_put->synced_data.needed_response_headers = needed_response_headers;
auto_ranged_put->synced_data.create_multipart_upload_completed = true;
auto_ranged_put->synced_data.create_multipart_upload_error_code = error_code;
if (error_code != AWS_ERROR_SUCCESS) {
aws_s3_meta_request_set_fail_synced(meta_request, request, error_code);
}
aws_s3_meta_request_unlock_synced_data(meta_request);
break;
}
case AWS_S3_AUTO_RANGED_PUT_REQUEST_TAG_PART: {
size_t part_number = request->part_number;
AWS_FATAL_ASSERT(part_number > 0);
size_t part_index = part_number - 1;
struct aws_string *etag = NULL;
if (error_code == AWS_ERROR_SUCCESS) {
/* Find the ETag header if it exists and cache it. */
struct aws_byte_cursor etag_within_quotes;
AWS_ASSERT(request->send_data.response_headers);
if (aws_http_headers_get(
request->send_data.response_headers, g_etag_header_name, &etag_within_quotes)) {
AWS_LOGF_ERROR(
AWS_LS_S3_META_REQUEST,
"id=%p Could not find ETag header for request %p",
(void *)meta_request,
(void *)request);
error_code = AWS_ERROR_S3_MISSING_UPLOAD_ID;
} else {
/* The ETag value arrives in quotes, but we don't want it in quotes when we send it back up
* later, so just get rid of the quotes now. */
if (etag_within_quotes.len >= 2 && etag_within_quotes.ptr[0] == '"' &&
etag_within_quotes.ptr[etag_within_quotes.len - 1] == '"') {
aws_byte_cursor_advance(&etag_within_quotes, 1);
--etag_within_quotes.len;
}
etag = aws_string_new_from_cursor(meta_request->allocator, &etag_within_quotes);
}
}
aws_s3_meta_request_lock_synced_data(meta_request);
++auto_ranged_put->synced_data.num_parts_completed;
AWS_LOGF_DEBUG(
AWS_LS_S3_META_REQUEST,
"id=%p: %d out of %d parts have completed.",
(void *)meta_request,
auto_ranged_put->synced_data.num_parts_completed,
auto_ranged_put->synced_data.total_num_parts);
if (error_code == AWS_ERROR_SUCCESS) {
AWS_ASSERT(etag != NULL);
++auto_ranged_put->synced_data.num_parts_successful;
struct aws_string *null_etag = NULL;
/* ETags need to be associated with their part number, so we keep the etag indices consistent with
* part numbers. This means we may have to add padding to the list in the case that parts finish out
* of order. */
while (aws_array_list_length(&auto_ranged_put->synced_data.etag_list) < part_number) {
int push_back_result =
aws_array_list_push_back(&auto_ranged_put->synced_data.etag_list, &null_etag);
AWS_FATAL_ASSERT(push_back_result == AWS_OP_SUCCESS);
}
aws_array_list_set_at(&auto_ranged_put->synced_data.etag_list, &etag, part_index);
} else {
++auto_ranged_put->synced_data.num_parts_failed;
aws_s3_meta_request_set_fail_synced(meta_request, request, error_code);
}
aws_s3_meta_request_unlock_synced_data(meta_request);
break;
}
case AWS_S3_AUTO_RANGED_PUT_REQUEST_TAG_COMPLETE_MULTIPART_UPLOAD: {
if (error_code == AWS_ERROR_SUCCESS && meta_request->headers_callback != NULL) {
struct aws_http_headers *final_response_headers = aws_http_headers_new(meta_request->allocator);
/* Copy all the response headers from this request. */
copy_http_headers(request->send_data.response_headers, final_response_headers);
/* Copy over any response headers that we've previously determined are needed for this final
* response.
*/
aws_s3_meta_request_lock_synced_data(meta_request);
copy_http_headers(auto_ranged_put->synced_data.needed_response_headers, final_response_headers);
aws_s3_meta_request_unlock_synced_data(meta_request);
struct aws_byte_cursor response_body_cursor =
aws_byte_cursor_from_buf(&request->send_data.response_body);
/* Grab the ETag for the entire object, and set it as a header. */
struct aws_string *etag_header_value =
get_top_level_xml_tag_value(meta_request->allocator, &g_etag_header_name, &response_body_cursor);
if (etag_header_value != NULL) {
struct aws_byte_buf etag_header_value_byte_buf;
AWS_ZERO_STRUCT(etag_header_value_byte_buf);
replace_quote_entities(meta_request->allocator, etag_header_value, &etag_header_value_byte_buf);
aws_http_headers_set(
final_response_headers,
g_etag_header_name,
aws_byte_cursor_from_buf(&etag_header_value_byte_buf));
aws_string_destroy(etag_header_value);
aws_byte_buf_clean_up(&etag_header_value_byte_buf);
}
/* Notify the user of the headers. */
if (meta_request->headers_callback(
meta_request,
final_response_headers,
request->send_data.response_status,
meta_request->user_data)) {
error_code = aws_last_error_or_unknown();
}
meta_request->headers_callback = NULL;
aws_http_headers_release(final_response_headers);
}
aws_s3_meta_request_lock_synced_data(meta_request);
auto_ranged_put->synced_data.complete_multipart_upload_completed = true;
auto_ranged_put->synced_data.complete_multipart_upload_error_code = error_code;
if (error_code != AWS_ERROR_SUCCESS) {
aws_s3_meta_request_set_fail_synced(meta_request, request, error_code);
}
aws_s3_meta_request_unlock_synced_data(meta_request);
break;
}
case AWS_S3_AUTO_RANGED_PUT_REQUEST_TAG_ABORT_MULTIPART_UPLOAD: {
aws_s3_meta_request_lock_synced_data(meta_request);
auto_ranged_put->synced_data.abort_multipart_upload_error_code = error_code;
auto_ranged_put->synced_data.abort_multipart_upload_completed = true;
aws_s3_meta_request_unlock_synced_data(meta_request);
break;
}
}
}