Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

UserAgent Updates #414

Merged
merged 17 commits into from
Mar 22, 2024
2 changes: 1 addition & 1 deletion include/aws/s3/private/s3_platform_info.h
Original file line number Diff line number Diff line change
Expand Up @@ -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

Expand Down
6 changes: 6 additions & 0 deletions include/aws/s3/private/s3_util.h
Original file line number Diff line number Diff line change
Expand Up @@ -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;

Expand Down
7 changes: 7 additions & 0 deletions include/aws/s3/s3.h
Original file line number Diff line number Diff line change
Expand Up @@ -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<aws_byte_cursor>. The caller is responsible for cleaning up the array list.
Expand Down
4 changes: 4 additions & 0 deletions source/s3.c
Original file line number Diff line number Diff line change
Expand Up @@ -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);
}
Expand Down
12 changes: 10 additions & 2 deletions source/s3_platform_info.c
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand All @@ -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,
Expand Down Expand Up @@ -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;
}
Expand Down
23 changes: 16 additions & 7 deletions source/s3_util.c
Original file line number Diff line number Diff line change
Expand Up @@ -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 <aws/auth/credentials.h>
#include <aws/common/clock.h>
Expand Down Expand Up @@ -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);
Expand Down Expand Up @@ -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);
Expand All @@ -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, &current_user_agent_header);

Expand All @@ -382,14 +387,18 @@ 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. */
{
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. */
Expand Down
22 changes: 13 additions & 9 deletions tests/s3_data_plane_tests.c
Original file line number Diff line number Diff line change
Expand Up @@ -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;
}

Expand All @@ -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;
Expand All @@ -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);
}

Expand All @@ -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);
Expand All @@ -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);
Expand Down
Loading