s3_util.c 22 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558
  1. /**
  2. * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
  3. * SPDX-License-Identifier: Apache-2.0.
  4. */
  5. #include "aws/s3/private/s3_util.h"
  6. #include "aws/s3/private/s3_client_impl.h"
  7. #include <aws/auth/credentials.h>
  8. #include <aws/common/string.h>
  9. #include <aws/common/xml_parser.h>
  10. #include <aws/http/request_response.h>
  11. #include <aws/s3/s3.h>
  12. #include <aws/s3/s3_client.h>
  13. #include <inttypes.h>
  14. #ifdef _MSC_VER
  15. /* sscanf warning (not currently scanning for strings) */
  16. # pragma warning(disable : 4996)
  17. #endif
  18. const struct aws_byte_cursor g_s3_client_version = AWS_BYTE_CUR_INIT_FROM_STRING_LITERAL(AWS_S3_CLIENT_VERSION);
  19. const struct aws_byte_cursor g_s3_service_name = AWS_BYTE_CUR_INIT_FROM_STRING_LITERAL("s3");
  20. const struct aws_byte_cursor g_host_header_name = AWS_BYTE_CUR_INIT_FROM_STRING_LITERAL("Host");
  21. const struct aws_byte_cursor g_range_header_name = AWS_BYTE_CUR_INIT_FROM_STRING_LITERAL("Range");
  22. const struct aws_byte_cursor g_if_match_header_name = AWS_BYTE_CUR_INIT_FROM_STRING_LITERAL("If-Match");
  23. const struct aws_byte_cursor g_etag_header_name = AWS_BYTE_CUR_INIT_FROM_STRING_LITERAL("ETag");
  24. const struct aws_byte_cursor g_content_range_header_name = AWS_BYTE_CUR_INIT_FROM_STRING_LITERAL("Content-Range");
  25. const struct aws_byte_cursor g_content_type_header_name = AWS_BYTE_CUR_INIT_FROM_STRING_LITERAL("Content-Type");
  26. const struct aws_byte_cursor g_content_encoding_header_name = AWS_BYTE_CUR_INIT_FROM_STRING_LITERAL("Content-Encoding");
  27. const struct aws_byte_cursor g_content_encoding_header_aws_chunked =
  28. AWS_BYTE_CUR_INIT_FROM_STRING_LITERAL("aws-chunked");
  29. const struct aws_byte_cursor g_content_length_header_name = AWS_BYTE_CUR_INIT_FROM_STRING_LITERAL("Content-Length");
  30. const struct aws_byte_cursor g_decoded_content_length_header_name =
  31. AWS_BYTE_CUR_INIT_FROM_STRING_LITERAL("x-amz-decoded-content-length");
  32. const struct aws_byte_cursor g_content_md5_header_name = AWS_BYTE_CUR_INIT_FROM_STRING_LITERAL("Content-MD5");
  33. const struct aws_byte_cursor g_trailer_header_name = AWS_BYTE_CUR_INIT_FROM_STRING_LITERAL("x-amz-trailer");
  34. const struct aws_byte_cursor g_request_validation_mode = AWS_BYTE_CUR_INIT_FROM_STRING_LITERAL("x-amz-checksum-mode");
  35. const struct aws_byte_cursor g_enabled = AWS_BYTE_CUR_INIT_FROM_STRING_LITERAL("enabled");
  36. const struct aws_byte_cursor g_create_mpu_checksum_header_name =
  37. AWS_BYTE_CUR_INIT_FROM_STRING_LITERAL("x-amz-checksum-algorithm");
  38. const struct aws_byte_cursor g_crc32c_header_name = AWS_BYTE_CUR_INIT_FROM_STRING_LITERAL("x-amz-checksum-crc32c");
  39. const struct aws_byte_cursor g_crc32_header_name = AWS_BYTE_CUR_INIT_FROM_STRING_LITERAL("x-amz-checksum-crc32");
  40. const struct aws_byte_cursor g_sha1_header_name = AWS_BYTE_CUR_INIT_FROM_STRING_LITERAL("x-amz-checksum-sha1");
  41. const struct aws_byte_cursor g_sha256_header_name = AWS_BYTE_CUR_INIT_FROM_STRING_LITERAL("x-amz-checksum-sha256");
  42. const struct aws_byte_cursor g_crc32c_create_mpu_header_name = AWS_BYTE_CUR_INIT_FROM_STRING_LITERAL("CRC32C");
  43. const struct aws_byte_cursor g_crc32_create_mpu_header_name = AWS_BYTE_CUR_INIT_FROM_STRING_LITERAL("CRC32");
  44. const struct aws_byte_cursor g_sha1_create_mpu_header_name = AWS_BYTE_CUR_INIT_FROM_STRING_LITERAL("SHA1");
  45. const struct aws_byte_cursor g_sha256_create_mpu_header_name = AWS_BYTE_CUR_INIT_FROM_STRING_LITERAL("SHA256");
  46. const struct aws_byte_cursor g_crc32c_complete_mpu_name = AWS_BYTE_CUR_INIT_FROM_STRING_LITERAL("ChecksumCRC32C");
  47. const struct aws_byte_cursor g_crc32_complete_mpu_name = AWS_BYTE_CUR_INIT_FROM_STRING_LITERAL("ChecksumCRC32");
  48. const struct aws_byte_cursor g_sha1_complete_mpu_name = AWS_BYTE_CUR_INIT_FROM_STRING_LITERAL("ChecksumSHA1");
  49. const struct aws_byte_cursor g_sha256_complete_mpu_name = AWS_BYTE_CUR_INIT_FROM_STRING_LITERAL("ChecksumSHA256");
  50. const struct aws_byte_cursor g_accept_ranges_header_name = AWS_BYTE_CUR_INIT_FROM_STRING_LITERAL("accept-ranges");
  51. const struct aws_byte_cursor g_acl_header_name = AWS_BYTE_CUR_INIT_FROM_STRING_LITERAL("x-amz-acl");
  52. const struct aws_byte_cursor g_post_method = AWS_BYTE_CUR_INIT_FROM_STRING_LITERAL("POST");
  53. const struct aws_byte_cursor g_head_method = AWS_BYTE_CUR_INIT_FROM_STRING_LITERAL("HEAD");
  54. const struct aws_byte_cursor g_delete_method = AWS_BYTE_CUR_INIT_FROM_STRING_LITERAL("DELETE");
  55. const struct aws_byte_cursor g_user_agent_header_name = AWS_BYTE_CUR_INIT_FROM_STRING_LITERAL("User-Agent");
  56. const struct aws_byte_cursor g_user_agent_header_product_name =
  57. AWS_BYTE_CUR_INIT_FROM_STRING_LITERAL("CRTS3NativeClient");
  58. const struct aws_byte_cursor g_error_body_xml_name = AWS_BYTE_CUR_INIT_FROM_STRING_LITERAL("Error");
  59. const struct aws_byte_cursor g_code_body_xml_name = AWS_BYTE_CUR_INIT_FROM_STRING_LITERAL("Code");
  60. const struct aws_byte_cursor g_s3_internal_error_code = AWS_BYTE_CUR_INIT_FROM_STRING_LITERAL("InternalError");
  61. const struct aws_byte_cursor g_s3_slow_down_error_code = AWS_BYTE_CUR_INIT_FROM_STRING_LITERAL("SlowDown");
  62. /* The special error code as Asynchronous Error Codes */
  63. const struct aws_byte_cursor g_s3_internal_errors_code = AWS_BYTE_CUR_INIT_FROM_STRING_LITERAL("InternalErrors");
  64. const uint32_t g_s3_max_num_upload_parts = 10000;
  65. const size_t g_s3_min_upload_part_size = MB_TO_BYTES(5);
  66. void copy_http_headers(const struct aws_http_headers *src, struct aws_http_headers *dest) {
  67. AWS_PRECONDITION(src);
  68. AWS_PRECONDITION(dest);
  69. size_t headers_count = aws_http_headers_count(src);
  70. for (size_t header_index = 0; header_index < headers_count; ++header_index) {
  71. struct aws_http_header header;
  72. aws_http_headers_get_index(src, header_index, &header);
  73. aws_http_headers_set(dest, header.name, header.value);
  74. }
  75. }
  76. struct top_level_xml_tag_value_with_root_value_user_data {
  77. struct aws_allocator *allocator;
  78. const struct aws_byte_cursor *tag_name;
  79. const struct aws_byte_cursor *expected_root_name;
  80. bool *root_name_mismatch;
  81. struct aws_string *result;
  82. };
  83. static bool s_top_level_xml_tag_value_child_xml_node(
  84. struct aws_xml_parser *parser,
  85. struct aws_xml_node *node,
  86. void *user_data) {
  87. struct aws_byte_cursor node_name;
  88. /* If we can't get the name of the node, stop traversing. */
  89. if (aws_xml_node_get_name(node, &node_name)) {
  90. return false;
  91. }
  92. struct top_level_xml_tag_value_with_root_value_user_data *xml_user_data = user_data;
  93. /* If the name of the node is what we are looking for, store the body of the node in our result, and stop
  94. * traversing. */
  95. if (aws_byte_cursor_eq(&node_name, xml_user_data->tag_name)) {
  96. struct aws_byte_cursor node_body;
  97. aws_xml_node_as_body(parser, node, &node_body);
  98. xml_user_data->result = aws_string_new_from_cursor(xml_user_data->allocator, &node_body);
  99. return false;
  100. }
  101. /* If we made it here, the tag hasn't been found yet, so return true to keep looking. */
  102. return true;
  103. }
  104. static bool s_top_level_xml_tag_value_root_xml_node(
  105. struct aws_xml_parser *parser,
  106. struct aws_xml_node *node,
  107. void *user_data) {
  108. struct top_level_xml_tag_value_with_root_value_user_data *xml_user_data = user_data;
  109. if (xml_user_data->expected_root_name) {
  110. /* If we can't get the name of the node, stop traversing. */
  111. struct aws_byte_cursor node_name;
  112. if (aws_xml_node_get_name(node, &node_name)) {
  113. return false;
  114. }
  115. if (!aws_byte_cursor_eq(&node_name, xml_user_data->expected_root_name)) {
  116. /* Not match the expected root name, stop parsing. */
  117. *xml_user_data->root_name_mismatch = true;
  118. return false;
  119. }
  120. }
  121. /* Traverse the root node, and then return false to stop. */
  122. aws_xml_node_traverse(parser, node, s_top_level_xml_tag_value_child_xml_node, user_data);
  123. return false;
  124. }
  125. struct aws_string *aws_xml_get_top_level_tag_with_root_name(
  126. struct aws_allocator *allocator,
  127. const struct aws_byte_cursor *tag_name,
  128. const struct aws_byte_cursor *expected_root_name,
  129. bool *out_root_name_mismatch,
  130. struct aws_byte_cursor *xml_body) {
  131. AWS_PRECONDITION(allocator);
  132. AWS_PRECONDITION(tag_name);
  133. AWS_PRECONDITION(xml_body);
  134. struct aws_xml_parser_options parser_options = {.doc = *xml_body};
  135. struct aws_xml_parser *parser = aws_xml_parser_new(allocator, &parser_options);
  136. bool root_name_mismatch = false;
  137. struct top_level_xml_tag_value_with_root_value_user_data xml_user_data = {
  138. allocator,
  139. tag_name,
  140. expected_root_name,
  141. &root_name_mismatch,
  142. NULL,
  143. };
  144. if (aws_xml_parser_parse(parser, s_top_level_xml_tag_value_root_xml_node, (void *)&xml_user_data)) {
  145. aws_string_destroy(xml_user_data.result);
  146. xml_user_data.result = NULL;
  147. goto clean_up;
  148. }
  149. if (out_root_name_mismatch) {
  150. *out_root_name_mismatch = root_name_mismatch;
  151. }
  152. clean_up:
  153. aws_xml_parser_destroy(parser);
  154. return xml_user_data.result;
  155. }
  156. struct aws_string *aws_xml_get_top_level_tag(
  157. struct aws_allocator *allocator,
  158. const struct aws_byte_cursor *tag_name,
  159. struct aws_byte_cursor *xml_body) {
  160. return aws_xml_get_top_level_tag_with_root_name(allocator, tag_name, NULL, NULL, xml_body);
  161. }
  162. struct aws_cached_signing_config_aws *aws_cached_signing_config_new(
  163. struct aws_allocator *allocator,
  164. const struct aws_signing_config_aws *signing_config) {
  165. AWS_PRECONDITION(allocator);
  166. AWS_PRECONDITION(signing_config);
  167. struct aws_cached_signing_config_aws *cached_signing_config =
  168. aws_mem_calloc(allocator, 1, sizeof(struct aws_cached_signing_config_aws));
  169. cached_signing_config->allocator = allocator;
  170. cached_signing_config->config.config_type = signing_config->config_type;
  171. cached_signing_config->config.algorithm = signing_config->algorithm;
  172. cached_signing_config->config.signature_type = signing_config->signature_type;
  173. AWS_ASSERT(aws_byte_cursor_is_valid(&signing_config->region));
  174. if (signing_config->region.len > 0) {
  175. cached_signing_config->region = aws_string_new_from_cursor(allocator, &signing_config->region);
  176. cached_signing_config->config.region = aws_byte_cursor_from_string(cached_signing_config->region);
  177. }
  178. AWS_ASSERT(aws_byte_cursor_is_valid(&signing_config->service));
  179. if (signing_config->service.len > 0) {
  180. cached_signing_config->service = aws_string_new_from_cursor(allocator, &signing_config->service);
  181. cached_signing_config->config.service = aws_byte_cursor_from_string(cached_signing_config->service);
  182. }
  183. cached_signing_config->config.date = signing_config->date;
  184. cached_signing_config->config.should_sign_header = signing_config->should_sign_header;
  185. cached_signing_config->config.flags = signing_config->flags;
  186. AWS_ASSERT(aws_byte_cursor_is_valid(&signing_config->signed_body_value));
  187. if (signing_config->service.len > 0) {
  188. cached_signing_config->signed_body_value =
  189. aws_string_new_from_cursor(allocator, &signing_config->signed_body_value);
  190. cached_signing_config->config.signed_body_value =
  191. aws_byte_cursor_from_string(cached_signing_config->signed_body_value);
  192. }
  193. cached_signing_config->config.signed_body_header = signing_config->signed_body_header;
  194. if (signing_config->credentials != NULL) {
  195. aws_credentials_acquire(signing_config->credentials);
  196. cached_signing_config->config.credentials = signing_config->credentials;
  197. }
  198. if (signing_config->credentials_provider != NULL) {
  199. aws_credentials_provider_acquire(signing_config->credentials_provider);
  200. cached_signing_config->config.credentials_provider = signing_config->credentials_provider;
  201. }
  202. cached_signing_config->config.expiration_in_seconds = signing_config->expiration_in_seconds;
  203. return cached_signing_config;
  204. }
  205. void aws_cached_signing_config_destroy(struct aws_cached_signing_config_aws *cached_signing_config) {
  206. if (cached_signing_config == NULL) {
  207. return;
  208. }
  209. aws_credentials_release(cached_signing_config->config.credentials);
  210. aws_credentials_provider_release(cached_signing_config->config.credentials_provider);
  211. aws_string_destroy(cached_signing_config->service);
  212. aws_string_destroy(cached_signing_config->region);
  213. aws_string_destroy(cached_signing_config->signed_body_value);
  214. aws_mem_release(cached_signing_config->allocator, cached_signing_config);
  215. }
  216. void aws_s3_init_default_signing_config(
  217. struct aws_signing_config_aws *signing_config,
  218. const struct aws_byte_cursor region,
  219. struct aws_credentials_provider *credentials_provider) {
  220. AWS_PRECONDITION(signing_config);
  221. AWS_PRECONDITION(credentials_provider);
  222. AWS_ZERO_STRUCT(*signing_config);
  223. signing_config->config_type = AWS_SIGNING_CONFIG_AWS;
  224. signing_config->algorithm = AWS_SIGNING_ALGORITHM_V4;
  225. signing_config->credentials_provider = credentials_provider;
  226. signing_config->region = region;
  227. signing_config->service = g_s3_service_name;
  228. signing_config->signed_body_header = AWS_SBHT_X_AMZ_CONTENT_SHA256;
  229. signing_config->signed_body_value = g_aws_signed_body_value_unsigned_payload;
  230. }
  231. void replace_quote_entities(struct aws_allocator *allocator, struct aws_string *str, struct aws_byte_buf *out_buf) {
  232. AWS_PRECONDITION(str);
  233. aws_byte_buf_init(out_buf, allocator, str->len);
  234. struct aws_byte_cursor quote_entity = AWS_BYTE_CUR_INIT_FROM_STRING_LITERAL("&quot;");
  235. struct aws_byte_cursor quote = AWS_BYTE_CUR_INIT_FROM_STRING_LITERAL("\"");
  236. size_t i = 0;
  237. while (i < str->len) {
  238. size_t chars_remaining = str->len - i;
  239. if (chars_remaining >= quote_entity.len &&
  240. !strncmp((const char *)&str->bytes[i], (const char *)quote_entity.ptr, quote_entity.len)) {
  241. /* Append quote */
  242. aws_byte_buf_append(out_buf, &quote);
  243. i += quote_entity.len;
  244. } else {
  245. /* Append character */
  246. struct aws_byte_cursor character_cursor = aws_byte_cursor_from_array(&str->bytes[i], 1);
  247. aws_byte_buf_append(out_buf, &character_cursor);
  248. ++i;
  249. }
  250. }
  251. }
  252. struct aws_string *aws_strip_quotes(struct aws_allocator *allocator, struct aws_byte_cursor in_cur) {
  253. if (in_cur.len >= 2 && in_cur.ptr[0] == '"' && in_cur.ptr[in_cur.len - 1] == '"') {
  254. aws_byte_cursor_advance(&in_cur, 1);
  255. --in_cur.len;
  256. }
  257. return aws_string_new_from_cursor(allocator, &in_cur);
  258. }
  259. int aws_last_error_or_unknown() {
  260. int error = aws_last_error();
  261. if (error == AWS_ERROR_SUCCESS) {
  262. return AWS_ERROR_UNKNOWN;
  263. }
  264. return error;
  265. }
  266. void aws_s3_add_user_agent_header(struct aws_allocator *allocator, struct aws_http_message *message) {
  267. AWS_PRECONDITION(allocator);
  268. AWS_PRECONDITION(message);
  269. const struct aws_byte_cursor space_delimeter = AWS_BYTE_CUR_INIT_FROM_STRING_LITERAL(" ");
  270. const struct aws_byte_cursor forward_slash = AWS_BYTE_CUR_INIT_FROM_STRING_LITERAL("/");
  271. const size_t user_agent_product_version_length =
  272. g_user_agent_header_product_name.len + forward_slash.len + g_s3_client_version.len;
  273. struct aws_http_headers *headers = aws_http_message_get_headers(message);
  274. AWS_ASSERT(headers != NULL);
  275. struct aws_byte_cursor current_user_agent_header;
  276. AWS_ZERO_STRUCT(current_user_agent_header);
  277. struct aws_byte_buf user_agent_buffer;
  278. AWS_ZERO_STRUCT(user_agent_buffer);
  279. if (aws_http_headers_get(headers, g_user_agent_header_name, &current_user_agent_header) == AWS_OP_SUCCESS) {
  280. /* If the header was found, then create a buffer with the total size we'll need, and append the curent user
  281. * agent header with a trailing space. */
  282. aws_byte_buf_init(
  283. &user_agent_buffer,
  284. allocator,
  285. current_user_agent_header.len + space_delimeter.len + user_agent_product_version_length);
  286. aws_byte_buf_append_dynamic(&user_agent_buffer, &current_user_agent_header);
  287. aws_byte_buf_append_dynamic(&user_agent_buffer, &space_delimeter);
  288. } else {
  289. AWS_ASSERT(aws_last_error() == AWS_ERROR_HTTP_HEADER_NOT_FOUND);
  290. /* If the header was not found, then create a buffer with just the size of the user agent string that is about
  291. * to be appended to the buffer. */
  292. aws_byte_buf_init(&user_agent_buffer, allocator, user_agent_product_version_length);
  293. }
  294. /* Append the client's user-agent string. */
  295. {
  296. aws_byte_buf_append_dynamic(&user_agent_buffer, &g_user_agent_header_product_name);
  297. aws_byte_buf_append_dynamic(&user_agent_buffer, &forward_slash);
  298. aws_byte_buf_append_dynamic(&user_agent_buffer, &g_s3_client_version);
  299. }
  300. /* Apply the updated header. */
  301. aws_http_headers_set(headers, g_user_agent_header_name, aws_byte_cursor_from_buf(&user_agent_buffer));
  302. /* Clean up the scratch buffer. */
  303. aws_byte_buf_clean_up(&user_agent_buffer);
  304. }
  305. int aws_s3_parse_content_range_response_header(
  306. struct aws_allocator *allocator,
  307. struct aws_http_headers *response_headers,
  308. uint64_t *out_range_start,
  309. uint64_t *out_range_end,
  310. uint64_t *out_object_size) {
  311. AWS_PRECONDITION(allocator);
  312. AWS_PRECONDITION(response_headers);
  313. struct aws_byte_cursor content_range_header_value;
  314. if (aws_http_headers_get(response_headers, g_content_range_header_name, &content_range_header_value)) {
  315. aws_raise_error(AWS_ERROR_S3_MISSING_CONTENT_RANGE_HEADER);
  316. return AWS_OP_ERR;
  317. }
  318. int result = AWS_OP_ERR;
  319. uint64_t range_start = 0;
  320. uint64_t range_end = 0;
  321. uint64_t object_size = 0;
  322. struct aws_string *content_range_header_value_str =
  323. aws_string_new_from_cursor(allocator, &content_range_header_value);
  324. /* Expected Format of header is: "bytes StartByte-EndByte/TotalObjectSize" */
  325. int num_fields_found = sscanf(
  326. (const char *)content_range_header_value_str->bytes,
  327. "bytes %" PRIu64 "-%" PRIu64 "/%" PRIu64,
  328. &range_start,
  329. &range_end,
  330. &object_size);
  331. if (num_fields_found < 3) {
  332. aws_raise_error(AWS_ERROR_S3_INVALID_CONTENT_RANGE_HEADER);
  333. goto clean_up;
  334. }
  335. if (out_range_start != NULL) {
  336. *out_range_start = range_start;
  337. }
  338. if (out_range_end != NULL) {
  339. *out_range_end = range_end;
  340. }
  341. if (out_object_size != NULL) {
  342. *out_object_size = object_size;
  343. }
  344. result = AWS_OP_SUCCESS;
  345. clean_up:
  346. aws_string_destroy(content_range_header_value_str);
  347. content_range_header_value_str = NULL;
  348. return result;
  349. }
  350. int aws_s3_parse_content_length_response_header(
  351. struct aws_allocator *allocator,
  352. struct aws_http_headers *response_headers,
  353. uint64_t *out_content_length) {
  354. AWS_PRECONDITION(allocator);
  355. AWS_PRECONDITION(response_headers);
  356. AWS_PRECONDITION(out_content_length);
  357. struct aws_byte_cursor content_length_header_value;
  358. if (aws_http_headers_get(response_headers, g_content_length_header_name, &content_length_header_value)) {
  359. aws_raise_error(AWS_ERROR_S3_MISSING_CONTENT_LENGTH_HEADER);
  360. return AWS_OP_ERR;
  361. }
  362. struct aws_string *content_length_header_value_str =
  363. aws_string_new_from_cursor(allocator, &content_length_header_value);
  364. int result = AWS_OP_ERR;
  365. if (sscanf((const char *)content_length_header_value_str->bytes, "%" PRIu64, out_content_length) == 1) {
  366. result = AWS_OP_SUCCESS;
  367. } else {
  368. aws_raise_error(AWS_ERROR_S3_INVALID_CONTENT_LENGTH_HEADER);
  369. }
  370. aws_string_destroy(content_length_header_value_str);
  371. return result;
  372. }
  373. uint32_t aws_s3_get_num_parts(size_t part_size, uint64_t object_range_start, uint64_t object_range_end) {
  374. uint32_t num_parts = 1;
  375. uint64_t first_part_size = part_size;
  376. uint64_t first_part_alignment_offset = object_range_start % part_size;
  377. /* If the first part size isn't aligned on the assumed part boundary, make it smaller so that it is. */
  378. if (first_part_alignment_offset > 0) {
  379. first_part_size = part_size - first_part_alignment_offset;
  380. }
  381. uint64_t second_part_start = object_range_start + first_part_size;
  382. /* If the range has room for a second part, calculate the additional amount of parts. */
  383. if (second_part_start <= object_range_end) {
  384. uint64_t aligned_range_remainder = object_range_end + 1 - second_part_start;
  385. num_parts += (uint32_t)(aligned_range_remainder / (uint64_t)part_size);
  386. if ((aligned_range_remainder % part_size) > 0) {
  387. ++num_parts;
  388. }
  389. }
  390. return num_parts;
  391. }
  392. void aws_s3_get_part_range(
  393. uint64_t object_range_start,
  394. uint64_t object_range_end,
  395. size_t part_size,
  396. uint32_t part_number,
  397. uint64_t *out_part_range_start,
  398. uint64_t *out_part_range_end) {
  399. AWS_PRECONDITION(out_part_range_start);
  400. AWS_PRECONDITION(out_part_range_end);
  401. AWS_ASSERT(part_number > 0);
  402. const uint32_t part_index = part_number - 1;
  403. /* Part index is assumed to be in a valid range. */
  404. AWS_ASSERT(part_index < aws_s3_get_num_parts(part_size, object_range_start, object_range_end));
  405. uint64_t part_size_uint64 = (uint64_t)part_size;
  406. uint64_t first_part_size = part_size_uint64;
  407. uint64_t first_part_alignment_offset = object_range_start % part_size_uint64;
  408. /* Shrink the part to a smaller size if need be to align to the assumed part boundary. */
  409. if (first_part_alignment_offset > 0) {
  410. first_part_size = part_size_uint64 - first_part_alignment_offset;
  411. }
  412. if (part_index == 0) {
  413. /* If this is the first part, then use the first part size. */
  414. *out_part_range_start = object_range_start;
  415. *out_part_range_end = *out_part_range_start + first_part_size - 1;
  416. } else {
  417. /* Else, find the next part by adding the object range + total number of whole parts before this one + initial
  418. * part size*/
  419. *out_part_range_start = object_range_start + ((uint64_t)(part_index - 1)) * part_size_uint64 + first_part_size;
  420. *out_part_range_end = *out_part_range_start + part_size_uint64 - 1;
  421. }
  422. /* Cap the part's range end using the object's range end. */
  423. if (*out_part_range_end > object_range_end) {
  424. *out_part_range_end = object_range_end;
  425. }
  426. }
  427. int aws_s3_crt_error_code_from_server_error_code_string(const struct aws_string *error_code_string) {
  428. if (aws_string_eq_byte_cursor(error_code_string, &g_s3_slow_down_error_code)) {
  429. return AWS_ERROR_S3_SLOW_DOWN;
  430. }
  431. if (aws_string_eq_byte_cursor(error_code_string, &g_s3_internal_error_code) ||
  432. aws_string_eq_byte_cursor(error_code_string, &g_s3_internal_errors_code)) {
  433. return AWS_ERROR_S3_INTERNAL_ERROR;
  434. }
  435. return AWS_ERROR_UNKNOWN;
  436. }