Skip to content

Commit

Permalink
Adding user-agent information to request headers (#102)
Browse files Browse the repository at this point in the history
  • Loading branch information
rccarper authored Mar 10, 2021
1 parent 6855775 commit 50e505c
Show file tree
Hide file tree
Showing 7 changed files with 354 additions and 7 deletions.
3 changes: 3 additions & 0 deletions include/aws/s3/private/s3_client_impl.h
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,9 @@
#include <aws/common/task_scheduler.h>
#include <aws/http/connection_manager.h>

/* TODO automate this value in the future to prevent it from becoming out-of-sync. */
#define AWS_S3_CLIENT_VERSION "0.1.x"

struct aws_http_connection;
struct aws_http_connection_manager;

Expand Down
24 changes: 18 additions & 6 deletions include/aws/s3/private/s3_util.h
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@
struct aws_allocator;
struct aws_http_stream;
struct aws_http_headers;
struct aws_http_message;
struct aws_event_loop;

enum aws_s3_response_status {
Expand All @@ -38,20 +39,28 @@ struct aws_cached_signing_config_aws {
struct aws_signing_config_aws config;
};

AWS_EXTERN_C_BEGIN

extern const struct aws_byte_cursor g_s3_service_name;
extern const struct aws_byte_cursor g_range_header_name;
extern const struct aws_byte_cursor g_content_range_header_name;
extern const struct aws_byte_cursor g_accept_ranges_header_name;

AWS_S3_API
extern const struct aws_byte_cursor g_acl_header_name;

extern const struct aws_byte_cursor g_post_method;
extern const struct aws_byte_cursor g_delete_method;
extern const uint32_t g_s3_max_num_upload_parts;

AWS_EXTERN_C_BEGIN

AWS_S3_API
extern const struct aws_byte_cursor g_s3_client_version;

AWS_S3_API
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_acl_header_name;

AWS_S3_API
extern const struct aws_byte_cursor g_host_header_name;

Expand Down Expand Up @@ -88,6 +97,9 @@ void replace_quote_entities(struct aws_allocator *allocator, struct aws_string *
/* TODO could be moved to aws-c-common. */
int aws_last_error_or_unknown(void);

AWS_S3_API
void aws_s3_add_user_agent_header(struct aws_allocator *allocator, struct aws_http_message *message);

AWS_EXTERN_C_END

#endif /* AWS_S3_UTIL_H */
2 changes: 2 additions & 0 deletions source/s3_meta_request.c
Original file line number Diff line number Diff line change
Expand Up @@ -123,6 +123,8 @@ int aws_s3_meta_request_init_base(
meta_request->initial_request_message = options->message;
aws_http_message_acquire(options->message);

aws_s3_add_user_agent_header(meta_request->allocator, meta_request->initial_request_message);

if (aws_mutex_init(&meta_request->synced_data.lock)) {
AWS_LOGF_ERROR(
AWS_LS_S3_META_REQUEST, "id=%p Could not initialize mutex for meta request", (void *)meta_request);
Expand Down
3 changes: 2 additions & 1 deletion source/s3_request_messages.c
Original file line number Diff line number Diff line change
Expand Up @@ -427,7 +427,8 @@ struct aws_http_message *aws_s3_message_util_copy_http_message(
if (multipart_upload_ops) {
if (aws_byte_cursor_eq_c_str_ignore_case(&header.name, "host") ||
aws_byte_cursor_eq_c_str_ignore_case(&header.name, "x-amz-request-payer") ||
aws_byte_cursor_eq_c_str_ignore_case(&header.name, "x-amz-expected-bucket-owner")) {
aws_byte_cursor_eq_c_str_ignore_case(&header.name, "x-amz-expected-bucket-owner") ||
aws_byte_cursor_eq_ignore_case(&header.name, &g_user_agent_header_name)) {
if (aws_http_message_add_header(message, header)) {
goto error_clean_up;
}
Expand Down
59 changes: 59 additions & 0 deletions source/s3_util.c
Original file line number Diff line number Diff line change
Expand Up @@ -4,13 +4,15 @@
*/

#include "aws/s3/private/s3_util.h"
#include "aws/s3/private/s3_client_impl.h"
#include <aws/auth/credentials.h>
#include <aws/common/string.h>
#include <aws/common/xml_parser.h>
#include <aws/http/request_response.h>
#include <aws/s3/s3.h>
#include <aws/s3/s3_client.h>

const struct aws_byte_cursor g_s3_client_version = AWS_BYTE_CUR_INIT_FROM_STRING_LITERAL(AWS_S3_CLIENT_VERSION);
const struct aws_byte_cursor g_s3_service_name = AWS_BYTE_CUR_INIT_FROM_STRING_LITERAL("s3");
const struct aws_byte_cursor g_host_header_name = AWS_BYTE_CUR_INIT_FROM_STRING_LITERAL("Host");
const struct aws_byte_cursor g_range_header_name = AWS_BYTE_CUR_INIT_FROM_STRING_LITERAL("Range");
Expand All @@ -23,6 +25,10 @@ const struct aws_byte_cursor g_acl_header_name = AWS_BYTE_CUR_INIT_FROM_STRING_L
const struct aws_byte_cursor g_post_method = AWS_BYTE_CUR_INIT_FROM_STRING_LITERAL("POST");
const struct aws_byte_cursor g_delete_method = AWS_BYTE_CUR_INIT_FROM_STRING_LITERAL("DELETE");

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 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 @@ -249,3 +255,56 @@ int aws_last_error_or_unknown() {

return error;
}

void aws_s3_add_user_agent_header(struct aws_allocator *allocator, struct aws_http_message *message) {
AWS_PRECONDITION(allocator);
AWS_PRECONDITION(message);

const struct aws_byte_cursor space_delimeter = 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_http_headers *headers = aws_http_message_get_headers(message);
AWS_ASSERT(headers != NULL);

struct aws_byte_cursor current_user_agent_header;
AWS_ZERO_STRUCT(current_user_agent_header);

struct aws_byte_buf user_agent_buffer;
AWS_ZERO_STRUCT(user_agent_buffer);

if (!aws_http_headers_get(headers, g_user_agent_header_name, &current_user_agent_header)) {
/* If the header was found, then create a buffer with the total size we'll need, and append the curent user
* agent header with a trailing space. */
aws_byte_buf_init(
&user_agent_buffer,
allocator,
current_user_agent_header.len + space_delimeter.len + user_agent_product_version_length);

aws_byte_buf_append_dynamic(&user_agent_buffer, &current_user_agent_header);

aws_byte_buf_append_dynamic(&user_agent_buffer, &space_delimeter);

} else {
AWS_ASSERT(aws_last_error() == AWS_ERROR_HTTP_HEADER_NOT_FOUND);

/* 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);
}

/* 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);
}

/* Apply the updated header. */
aws_http_headers_set(headers, g_user_agent_header_name, aws_byte_cursor_from_buf(&user_agent_buffer));

/* Clean up the scratch buffer. */
aws_byte_buf_clean_up(&user_agent_buffer);
}
4 changes: 4 additions & 0 deletions tests/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -64,6 +64,10 @@ add_net_test_case(test_s3_bad_endpoint)
add_net_test_case(test_s3_put_object_clamp_part_size)
add_net_test_case(test_s3_replace_quote_entities)
add_net_test_case(test_s3_different_endpoints)
add_test_case(test_add_user_agent_header)
add_net_test_case(test_s3_auto_ranged_get_sending_user_agent)
add_net_test_case(test_s3_auto_ranged_put_sending_user_agent)
add_net_test_case(test_s3_default_sending_meta_request)

add_test_case(test_get_existing_compute_platform_info)
add_test_case(test_get_nonexistent_compute_platform_info)
Expand Down
Loading

0 comments on commit 50e505c

Please sign in to comment.