From e03689ec8884a9554271657b91c60db2966f9c1d Mon Sep 17 00:00:00 2001 From: Michael Graeb Date: Wed, 22 Nov 2023 11:36:13 -0800 Subject: [PATCH] Bring back request_type -> operation_name function --- .../aws/s3/private/s3_default_meta_request.h | 3 +- include/aws/s3/private/s3_request.h | 2 +- include/aws/s3/s3_client.h | 33 ++++++++++++++++--- source/s3_client.c | 5 +-- source/s3_default_meta_request.c | 13 +++++--- source/s3_util.c | 27 +++++++++++++++ tests/CMakeLists.txt | 1 + tests/s3_util_tests.c | 24 ++++++++++++++ 8 files changed, 93 insertions(+), 15 deletions(-) diff --git a/include/aws/s3/private/s3_default_meta_request.h b/include/aws/s3/private/s3_default_meta_request.h index b519fd597..4523cf8f2 100644 --- a/include/aws/s3/private/s3_default_meta_request.h +++ b/include/aws/s3/private/s3_default_meta_request.h @@ -15,7 +15,7 @@ struct aws_s3_meta_request_default { size_t content_length; - /* Actual type for the single request (AWS_S3_REQUEST_TYPE_DEFAULT if unknown) */ + /* Actual type for the single request (may be AWS_S3_REQUEST_TYPE_UNKNOWN) */ enum aws_s3_request_type request_type; /* S3 operation name for the single request (NULL if unknown) */ @@ -48,7 +48,6 @@ struct aws_s3_meta_request *aws_s3_meta_request_default_new( struct aws_allocator *allocator, struct aws_s3_client *client, enum aws_s3_request_type request_type, - const char *operation_name_override, uint64_t content_length, bool should_compute_content_md5, const struct aws_s3_meta_request_options *options); diff --git a/include/aws/s3/private/s3_request.h b/include/aws/s3/private/s3_request.h index b0bdb76fa..7350cb37b 100644 --- a/include/aws/s3/private/s3_request.h +++ b/include/aws/s3/private/s3_request.h @@ -160,7 +160,7 @@ struct aws_s3_request { /* TODO: this should be a union type to make it clear that this could be one of two enums for puts, and gets. */ int request_tag; - /* Actual S3 type for the single request (AWS_S3_REQUEST_TYPE_DEFAULT if unknown) */ + /* Actual S3 type for the single request (may be AWS_S3_REQUEST_TYPE_UNKNOWN) */ enum aws_s3_request_type request_type; /* S3 operation name for the single request (e.g. "CompleteMultipartUpload") (NULL if unknown) */ diff --git a/include/aws/s3/s3_client.h b/include/aws/s3/s3_client.h index d08786934..304ac9ef0 100644 --- a/include/aws/s3/s3_client.h +++ b/include/aws/s3/s3_client.h @@ -85,25 +85,39 @@ enum aws_s3_meta_request_type { }; /** - * The type of S3 request made. Used by metrics. + * The type of a single S3 HTTP request. Used by metrics. + * A meta-request can make multiple S3 HTTP requests under the hood. + * + * For example, AWS_S3_META_REQUEST_TYPE_PUT_OBJECT for a large file will + * do multipart upload, resulting in 3+ HTTP requests: + * AWS_S3_REQUEST_TYPE_CREATE_MULTIPART_UPLOAD, one or more AWS_S3_REQUEST_TYPE_UPLOAD_PART, + * and finally AWS_S3_REQUEST_TYPE_COMPLETE_MULTIPART_UPLOAD. + * + * aws_s3_request_type_operation_name() returns the S3 operation name + * for types that map (e.g. AWS_S3_REQUEST_TYPE_HEAD_OBJECT -> "HeadObject"), + * or empty string for types that don't map (e.g. AWS_S3_REQUEST_TYPE_UNKNOWN -> ""). */ enum aws_s3_request_type { - /* Same as the original HTTP request passed to aws_s3_meta_request_options */ - AWS_S3_REQUEST_TYPE_DEFAULT, + /* The actual type of the single S3 HTTP request is unknown */ + AWS_S3_REQUEST_TYPE_UNKNOWN, /* S3 APIs */ AWS_S3_REQUEST_TYPE_HEAD_OBJECT, AWS_S3_REQUEST_TYPE_GET_OBJECT, AWS_S3_REQUEST_TYPE_LIST_PARTS, - AWS_S3_REQUEST_TYPE_PUT_OBJECT, AWS_S3_REQUEST_TYPE_CREATE_MULTIPART_UPLOAD, AWS_S3_REQUEST_TYPE_UPLOAD_PART, AWS_S3_REQUEST_TYPE_ABORT_MULTIPART_UPLOAD, AWS_S3_REQUEST_TYPE_COMPLETE_MULTIPART_UPLOAD, AWS_S3_REQUEST_TYPE_UPLOAD_PART_COPY, AWS_S3_REQUEST_TYPE_COPY_OBJECT, + AWS_S3_REQUEST_TYPE_PUT_OBJECT, + /* Max enum value */ AWS_S3_REQUEST_TYPE_MAX, + + /** @deprecated Use AWS_S3_REQUEST_TYPE_UNKNOWN if the actual S3 HTTP request type is unknown */ + AWS_S3_REQUEST_TYPE_DEFAULT = AWS_S3_REQUEST_TYPE_UNKNOWN, }; /** @@ -845,6 +859,17 @@ void aws_s3_init_default_signing_config( const struct aws_byte_cursor region, struct aws_credentials_provider *credentials_provider); +/** + * Return operation name for aws_s3_request_type, + * or empty string if the type doesn't map to an actual operation. + * For example: + * AWS_S3_REQUEST_TYPE_HEAD_OBJECT -> "HeadObject" + * AWS_S3_REQUEST_TYPE_UNKNOWN -> "" + * AWS_S3_REQUEST_TYPE_MAX -> "" + */ +AWS_S3_API +const char *aws_s3_request_type_operation_name(enum aws_s3_request_type type); + /** * Add a reference, keeping this object alive. * The reference must be released when you are done with it, or it's memory will never be cleaned up. diff --git a/source/s3_client.c b/source/s3_client.c index 38cf7df8d..03fc32381 100644 --- a/source/s3_client.c +++ b/source/s3_client.c @@ -1047,7 +1047,6 @@ static struct aws_s3_meta_request *s_s3_client_meta_request_factory_default( client->allocator, client, AWS_S3_REQUEST_TYPE_GET_OBJECT, - "GetObject", content_length, false /*should_compute_content_md5*/, options); @@ -1100,7 +1099,6 @@ static struct aws_s3_meta_request *s_s3_client_meta_request_factory_default( client->allocator, client, AWS_S3_REQUEST_TYPE_PUT_OBJECT, - "PutObject", content_length, client->compute_content_md5 == AWS_MR_CONTENT_MD5_ENABLED && !aws_http_headers_has(initial_message_headers, g_content_md5_header_name), @@ -1150,8 +1148,7 @@ static struct aws_s3_meta_request *s_s3_client_meta_request_factory_default( return aws_s3_meta_request_default_new( client->allocator, client, - AWS_S3_REQUEST_TYPE_DEFAULT, - NULL /*operation_name_override*/, + AWS_S3_REQUEST_TYPE_UNKNOWN, content_length, false /*should_compute_content_md5*/, options); diff --git a/source/s3_default_meta_request.c b/source/s3_default_meta_request.c index b1098e12b..ec4d22c5b 100644 --- a/source/s3_default_meta_request.c +++ b/source/s3_default_meta_request.c @@ -52,7 +52,6 @@ struct aws_s3_meta_request *aws_s3_meta_request_default_new( struct aws_allocator *allocator, struct aws_s3_client *client, enum aws_s3_request_type request_type, - const char *operation_name_override, uint64_t content_length, bool should_compute_content_md5, const struct aws_s3_meta_request_options *options) { @@ -108,8 +107,14 @@ struct aws_s3_meta_request *aws_s3_meta_request_default_new( meta_request_default->content_length = (size_t)content_length; meta_request_default->request_type = request_type; - if (operation_name_override != NULL) { - meta_request_default->operation_name = aws_string_new_from_c_str(allocator, operation_name_override); + /* Try to get operation name. + * When internal aws-c-s3 code creates a default meta-request, + * a valid request_type is always passed in, and we can get its operation name. + * When external users create a default meta-request, they may have provided + * operation name in the options. */ + const char *operation_name = aws_s3_request_type_operation_name(request_type); + if (operation_name[0] != '\0') { + meta_request_default->operation_name = aws_string_new_from_c_str(allocator, operation_name); } else if (options->operation_name.len != 0) { meta_request_default->operation_name = aws_string_new_from_cursor(allocator, &options->operation_name); } @@ -161,7 +166,7 @@ static bool s_s3_meta_request_default_update( request = aws_s3_request_new( meta_request, 0 /*request_tag*/, - AWS_S3_REQUEST_TYPE_DEFAULT, + meta_request_default->request_type, meta_request_default->operation_name ? aws_string_c_str(meta_request_default->operation_name) : NULL, 1 /*part_number*/, diff --git a/source/s3_util.c b/source/s3_util.c index 451179fb0..c1137c41b 100644 --- a/source/s3_util.c +++ b/source/s3_util.c @@ -64,6 +64,33 @@ const struct aws_byte_cursor g_user_agent_header_product_name = const uint32_t g_s3_max_num_upload_parts = 10000; const size_t g_s3_min_upload_part_size = MB_TO_BYTES(5); +const char *aws_s3_request_type_operation_name(enum aws_s3_request_type type) { + switch (type) { + case AWS_S3_REQUEST_TYPE_HEAD_OBJECT: + return "HeadObject"; + case AWS_S3_REQUEST_TYPE_GET_OBJECT: + return "GetObject"; + case AWS_S3_REQUEST_TYPE_LIST_PARTS: + return "ListParts"; + case AWS_S3_REQUEST_TYPE_CREATE_MULTIPART_UPLOAD: + return "CreateMultipartUpload"; + case AWS_S3_REQUEST_TYPE_UPLOAD_PART: + return "UploadPart"; + case AWS_S3_REQUEST_TYPE_ABORT_MULTIPART_UPLOAD: + return "AbortMultipartUpload"; + case AWS_S3_REQUEST_TYPE_COMPLETE_MULTIPART_UPLOAD: + return "CompleteMultipartUpload"; + case AWS_S3_REQUEST_TYPE_UPLOAD_PART_COPY: + return "UploadPartCopy"; + case AWS_S3_REQUEST_TYPE_COPY_OBJECT: + return "CopyObject"; + case AWS_S3_REQUEST_TYPE_PUT_OBJECT: + return "PutObject"; + default: + return ""; + } +} + void copy_http_headers(const struct aws_http_headers *src, struct aws_http_headers *dest) { AWS_PRECONDITION(src); AWS_PRECONDITION(dest); diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt index 88f624f8c..bc9d2c612 100644 --- a/tests/CMakeLists.txt +++ b/tests/CMakeLists.txt @@ -179,6 +179,7 @@ add_net_test_case(test_s3_not_satisfiable_range) add_net_test_case(test_s3_bad_endpoint) add_net_test_case(test_s3_different_endpoints) +add_test_case(test_s3_request_type_operation_name) add_test_case(test_s3_replace_quote_entities) add_test_case(test_s3_strip_quotes) add_test_case(test_s3_parse_content_range_response_header) diff --git a/tests/s3_util_tests.c b/tests/s3_util_tests.c index 1233c391a..433dd32f2 100644 --- a/tests/s3_util_tests.c +++ b/tests/s3_util_tests.c @@ -22,6 +22,30 @@ #include #include +AWS_TEST_CASE(test_s3_request_type_operation_name, s_test_s3_request_type_operation_name) +static int s_test_s3_request_type_operation_name(struct aws_allocator *allocator, void *ctx) { + (void)allocator; + (void)ctx; + + /* sanity check */ + ASSERT_STR_EQUALS("HeadObject", aws_s3_request_type_operation_name(AWS_S3_REQUEST_TYPE_HEAD_OBJECT)); + + /* check that all valid enums give back valid strings */ + for (enum aws_s3_request_type type = AWS_S3_REQUEST_TYPE_UNKNOWN + 1; type < AWS_S3_REQUEST_TYPE_MAX; ++type) { + const char *operation_name = aws_s3_request_type_operation_name(type); + ASSERT_NOT_NULL(operation_name); + ASSERT_TRUE(strlen(operation_name) > 1); + } + + /* check that invalid enums give back empty strings */ + ASSERT_NOT_NULL(aws_s3_request_type_operation_name(AWS_S3_REQUEST_TYPE_UNKNOWN)); + ASSERT_STR_EQUALS("", aws_s3_request_type_operation_name(AWS_S3_REQUEST_TYPE_UNKNOWN)); + ASSERT_STR_EQUALS("", aws_s3_request_type_operation_name(AWS_S3_REQUEST_TYPE_MAX)); + ASSERT_STR_EQUALS("", aws_s3_request_type_operation_name(-1)); + + return 0; +} + AWS_TEST_CASE(test_s3_replace_quote_entities, s_test_s3_replace_quote_entities) static int s_test_s3_replace_quote_entities(struct aws_allocator *allocator, void *ctx) { (void)ctx;