From efeb625c7d8e6d789ee71c6863da3fff820c2dc2 Mon Sep 17 00:00:00 2001 From: Waqar Ahmed Khan Date: Fri, 22 Mar 2024 08:34:43 -0700 Subject: [PATCH] UserAgent Updates (#414) --- include/aws/s3/private/s3_platform_info.h | 2 +- include/aws/s3/private/s3_util.h | 6 ++++++ include/aws/s3/s3.h | 7 +++++++ source/s3.c | 4 ++++ source/s3_platform_info.c | 12 ++++++++++-- source/s3_util.c | 23 ++++++++++++++++------- tests/s3_data_plane_tests.c | 22 +++++++++++++--------- 7 files changed, 57 insertions(+), 19 deletions(-) diff --git a/include/aws/s3/private/s3_platform_info.h b/include/aws/s3/private/s3_platform_info.h index 7aceee011..9e9671282 100644 --- a/include/aws/s3/private/s3_platform_info.h +++ b/include/aws/s3/private/s3_platform_info.h @@ -73,7 +73,7 @@ bool aws_s3_is_running_on_ec2_nitro(struct aws_s3_platform_info_loader *loader); * @return byte_cursor containing the instance type. If this is empty, the instance type could not be determined. */ AWS_S3_API -struct aws_byte_cursor aws_s3_get_ec2_instance_type(struct aws_s3_platform_info_loader *loader); +struct aws_byte_cursor aws_s3_get_ec2_instance_type(struct aws_s3_platform_info_loader *loader, bool cached_only); AWS_EXTERN_C_END diff --git a/include/aws/s3/private/s3_util.h b/include/aws/s3/private/s3_util.h index 2b8053044..d9c06b8a0 100644 --- a/include/aws/s3/private/s3_util.h +++ b/include/aws/s3/private/s3_util.h @@ -108,6 +108,12 @@ extern const struct aws_byte_cursor g_user_agent_header_name; AWS_S3_API extern const struct aws_byte_cursor g_user_agent_header_product_name; +AWS_S3_API +extern const struct aws_byte_cursor g_user_agent_header_platform; + +AWS_S3_API +extern const struct aws_byte_cursor g_user_agent_header_unknown; + AWS_S3_API extern const struct aws_byte_cursor g_acl_header_name; diff --git a/include/aws/s3/s3.h b/include/aws/s3/s3.h index bb187cd86..99b897c84 100644 --- a/include/aws/s3/s3.h +++ b/include/aws/s3/s3.h @@ -118,6 +118,13 @@ void aws_s3_library_clean_up(void); AWS_S3_API const struct aws_s3_platform_info *aws_s3_get_current_platform_info(void); +/* + * Returns the ec2 instance_type for current platform if possible + * NOTE: THIS API IS EXPERIMENTAL AND UNSTABLE + */ +AWS_S3_API +struct aws_byte_cursor aws_s3_get_current_platform_ec2_intance_type(bool cached_only); + /* * Retrieves a list of EC2 instance types with recommended configuration. * Returns aws_array_list. The caller is responsible for cleaning up the array list. diff --git a/source/s3.c b/source/s3.c index d92c017fd..61bc0ee3e 100644 --- a/source/s3.c +++ b/source/s3.c @@ -104,6 +104,10 @@ const struct aws_s3_platform_info *aws_s3_get_current_platform_info(void) { return aws_s3_get_platform_info_for_current_environment(s_loader); } +struct aws_byte_cursor aws_s3_get_current_platform_ec2_intance_type(bool cached_only) { + return aws_s3_get_ec2_instance_type(s_loader, cached_only); +} + struct aws_array_list aws_s3_get_platforms_with_recommended_config(void) { return aws_s3_get_recommended_platforms(s_loader); } diff --git a/source/s3_platform_info.c b/source/s3_platform_info.c index 84e87aa80..05deedd9f 100644 --- a/source/s3_platform_info.c +++ b/source/s3_platform_info.c @@ -486,7 +486,7 @@ struct aws_string *s_query_imds_for_instance_type(struct aws_allocator *allocato return callback_info.instance_type; } -struct aws_byte_cursor aws_s3_get_ec2_instance_type(struct aws_s3_platform_info_loader *loader) { +struct aws_byte_cursor aws_s3_get_ec2_instance_type(struct aws_s3_platform_info_loader *loader, bool cached_only) { aws_mutex_lock(&loader->lock_data.lock); struct aws_byte_cursor return_cur; AWS_ZERO_STRUCT(return_cur); @@ -499,6 +499,14 @@ struct aws_byte_cursor aws_s3_get_ec2_instance_type(struct aws_s3_platform_info_ aws_string_bytes(loader->lock_data.detected_instance_type)); goto return_instance_and_unlock; } + if (cached_only) { + AWS_LOGF_TRACE( + AWS_LS_S3_CLIENT, + "id=%p: Instance type has not been cached. Returning without trying to determine instance type since " + "cached_only is set.", + (void *)loader); + goto return_instance_and_unlock; + } AWS_LOGF_TRACE( AWS_LS_S3_CLIENT, @@ -556,7 +564,7 @@ struct aws_byte_cursor aws_s3_get_ec2_instance_type(struct aws_s3_platform_info_ const struct aws_s3_platform_info *aws_s3_get_platform_info_for_current_environment( struct aws_s3_platform_info_loader *loader) { /* getting the instance type will set it on the loader the first time if it can */ - aws_s3_get_ec2_instance_type(loader); + aws_s3_get_ec2_instance_type(loader, false /*cached_only*/); /* will never be mutated after the above call. */ return &loader->lock_data.current_env_platform_info; } diff --git a/source/s3_util.c b/source/s3_util.c index 5eedf191e..ac21402a2 100644 --- a/source/s3_util.c +++ b/source/s3_util.c @@ -6,6 +6,7 @@ #include "aws/s3/private/s3_util.h" #include "aws/s3/private/s3_client_impl.h" #include "aws/s3/private/s3_meta_request_impl.h" +#include "aws/s3/private/s3_platform_info.h" #include "aws/s3/private/s3_request.h" #include #include @@ -66,6 +67,8 @@ const struct aws_byte_cursor g_delete_method = AWS_BYTE_CUR_INIT_FROM_STRING_LIT const struct aws_byte_cursor g_user_agent_header_name = AWS_BYTE_CUR_INIT_FROM_STRING_LITERAL("User-Agent"); const struct aws_byte_cursor g_user_agent_header_product_name = AWS_BYTE_CUR_INIT_FROM_STRING_LITERAL("CRTS3NativeClient"); +const struct aws_byte_cursor g_user_agent_header_platform = AWS_BYTE_CUR_INIT_FROM_STRING_LITERAL("platform"); +const struct aws_byte_cursor g_user_agent_header_unknown = AWS_BYTE_CUR_INIT_FROM_STRING_LITERAL("unknown"); const uint32_t g_s3_max_num_upload_parts = 10000; const size_t g_s3_min_upload_part_size = MB_TO_BYTES(5); @@ -352,9 +355,13 @@ void aws_s3_add_user_agent_header(struct aws_allocator *allocator, struct aws_ht const struct aws_byte_cursor space_delimiter = AWS_BYTE_CUR_INIT_FROM_STRING_LITERAL(" "); const struct aws_byte_cursor forward_slash = AWS_BYTE_CUR_INIT_FROM_STRING_LITERAL("/"); - - const size_t user_agent_product_version_length = - g_user_agent_header_product_name.len + forward_slash.len + g_s3_client_version.len; + struct aws_byte_cursor platform_cursor = aws_s3_get_current_platform_ec2_intance_type(true /* cached_only */); + if (!platform_cursor.len) { + platform_cursor = g_user_agent_header_unknown; + } + const size_t user_agent_length = g_user_agent_header_product_name.len + forward_slash.len + + g_s3_client_version.len + space_delimiter.len + g_user_agent_header_platform.len + + forward_slash.len + platform_cursor.len; struct aws_http_headers *headers = aws_http_message_get_headers(message); AWS_ASSERT(headers != NULL); @@ -369,9 +376,7 @@ void aws_s3_add_user_agent_header(struct aws_allocator *allocator, struct aws_ht /* If the header was found, then create a buffer with the total size we'll need, and append the current user * agent header with a trailing space. */ aws_byte_buf_init( - &user_agent_buffer, - allocator, - current_user_agent_header.len + space_delimiter.len + user_agent_product_version_length); + &user_agent_buffer, allocator, current_user_agent_header.len + space_delimiter.len + user_agent_length); aws_byte_buf_append_dynamic(&user_agent_buffer, ¤t_user_agent_header); @@ -382,7 +387,7 @@ void aws_s3_add_user_agent_header(struct aws_allocator *allocator, struct aws_ht /* If the header was not found, then create a buffer with just the size of the user agent string that is about * to be appended to the buffer. */ - aws_byte_buf_init(&user_agent_buffer, allocator, user_agent_product_version_length); + aws_byte_buf_init(&user_agent_buffer, allocator, user_agent_length); } /* Append the client's user-agent string. */ @@ -390,6 +395,10 @@ void aws_s3_add_user_agent_header(struct aws_allocator *allocator, struct aws_ht aws_byte_buf_append_dynamic(&user_agent_buffer, &g_user_agent_header_product_name); aws_byte_buf_append_dynamic(&user_agent_buffer, &forward_slash); aws_byte_buf_append_dynamic(&user_agent_buffer, &g_s3_client_version); + aws_byte_buf_append_dynamic(&user_agent_buffer, &space_delimiter); + aws_byte_buf_append_dynamic(&user_agent_buffer, &g_user_agent_header_platform); + aws_byte_buf_append_dynamic(&user_agent_buffer, &forward_slash); + aws_byte_buf_append_dynamic(&user_agent_buffer, &platform_cursor); } /* Apply the updated header. */ diff --git a/tests/s3_data_plane_tests.c b/tests/s3_data_plane_tests.c index e64b75a10..36047a72e 100644 --- a/tests/s3_data_plane_tests.c +++ b/tests/s3_data_plane_tests.c @@ -5253,12 +5253,16 @@ static int s_get_expected_user_agent(struct aws_allocator *allocator, struct aws AWS_ASSERT(dest); const struct aws_byte_cursor forward_slash = AWS_BYTE_CUR_INIT_FROM_STRING_LITERAL("/"); + const struct aws_byte_cursor single_space = AWS_BYTE_CUR_INIT_FROM_STRING_LITERAL(" "); ASSERT_SUCCESS(aws_byte_buf_init(dest, allocator, 32)); ASSERT_SUCCESS(aws_byte_buf_append_dynamic(dest, &g_user_agent_header_product_name)); ASSERT_SUCCESS(aws_byte_buf_append_dynamic(dest, &forward_slash)); ASSERT_SUCCESS(aws_byte_buf_append_dynamic(dest, &g_s3_client_version)); - + ASSERT_SUCCESS(aws_byte_buf_append_dynamic(dest, &single_space)); + ASSERT_SUCCESS(aws_byte_buf_append_dynamic(dest, &g_user_agent_header_platform)); + ASSERT_SUCCESS(aws_byte_buf_append_dynamic(dest, &forward_slash)); + ASSERT_SUCCESS(aws_byte_buf_append_dynamic(dest, &g_user_agent_header_unknown)); return AWS_OP_SUCCESS; } @@ -5270,7 +5274,6 @@ static int s_test_add_user_agent_header(struct aws_allocator *allocator, void *c AWS_ZERO_STRUCT(tester); ASSERT_SUCCESS(aws_s3_tester_init(allocator, &tester)); - const struct aws_byte_cursor forward_slash = AWS_BYTE_CUR_INIT_FROM_STRING_LITERAL("/"); const struct aws_byte_cursor single_space = AWS_BYTE_CUR_INIT_FROM_STRING_LITERAL(" "); struct aws_byte_buf expected_user_agent_value_buf; @@ -5290,8 +5293,8 @@ static int s_test_add_user_agent_header(struct aws_allocator *allocator, void *c ASSERT_TRUE(headers != NULL); ASSERT_SUCCESS(aws_http_headers_get(headers, g_user_agent_header_name, &user_agent_value)); - ASSERT_TRUE(aws_byte_cursor_eq(&user_agent_value, &expected_user_agent_value)); - + ASSERT_BIN_ARRAYS_EQUALS( + user_agent_value.ptr, user_agent_value.len, expected_user_agent_value.ptr, expected_user_agent_value.len); aws_http_message_release(message); } @@ -5303,10 +5306,7 @@ static int s_test_add_user_agent_header(struct aws_allocator *allocator, void *c aws_byte_buf_init(&total_expected_user_agent_value_buf, allocator, 64); aws_byte_buf_append_dynamic(&total_expected_user_agent_value_buf, &dummy_agent_header_value); aws_byte_buf_append_dynamic(&total_expected_user_agent_value_buf, &single_space); - - aws_byte_buf_append_dynamic(&total_expected_user_agent_value_buf, &g_user_agent_header_product_name); - aws_byte_buf_append_dynamic(&total_expected_user_agent_value_buf, &forward_slash); - aws_byte_buf_append_dynamic(&total_expected_user_agent_value_buf, &g_s3_client_version); + aws_byte_buf_append_dynamic(&total_expected_user_agent_value_buf, &expected_user_agent_value); struct aws_byte_cursor total_expected_user_agent_value = aws_byte_cursor_from_buf(&total_expected_user_agent_value_buf); @@ -5323,7 +5323,11 @@ static int s_test_add_user_agent_header(struct aws_allocator *allocator, void *c struct aws_byte_cursor user_agent_value; AWS_ZERO_STRUCT(user_agent_value); ASSERT_SUCCESS(aws_http_headers_get(headers, g_user_agent_header_name, &user_agent_value)); - ASSERT_TRUE(aws_byte_cursor_eq(&user_agent_value, &total_expected_user_agent_value)); + ASSERT_BIN_ARRAYS_EQUALS( + user_agent_value.ptr, + user_agent_value.len, + total_expected_user_agent_value.ptr, + total_expected_user_agent_value.len); } aws_byte_buf_clean_up(&total_expected_user_agent_value_buf);