/** * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. * SPDX-License-Identifier: Apache-2.0. */ #include #include #include #include #include #include #include #include #include #include #if defined(_MSC_VER) # pragma warning(disable : 4204) #endif /* _MSC_VER */ #define DEFAULT_QUERY_PARAM_COUNT 10 /* * Uses the signing result to rebuild the request's URI. If the signing was not done via * query params, then this ends up doing nothing. */ static int s_build_request_uri( struct aws_allocator *allocator, struct aws_http_message *request, const struct aws_signing_result *signing_result) { /* first let's see if we need to do anything at all */ struct aws_array_list *result_param_list = NULL; aws_signing_result_get_property_list( signing_result, g_aws_http_query_params_property_list_name, &result_param_list); if (result_param_list == NULL) { return AWS_OP_SUCCESS; } /* * There are query params to apply. Use the following algorithm: * * (1) Take the old uri and parse it into a URI structure * (2) Make a new URI builder and add the old URI's components to it * (3) Add the signing query params to the builder * (4) Use the builder to make a new URI */ int result = AWS_OP_ERR; size_t signed_query_param_count = aws_array_list_length(result_param_list); struct aws_uri old_uri; AWS_ZERO_STRUCT(old_uri); struct aws_uri new_uri; AWS_ZERO_STRUCT(new_uri); struct aws_uri_builder_options new_uri_builder; AWS_ZERO_STRUCT(new_uri_builder); struct aws_array_list query_params; AWS_ZERO_STRUCT(query_params); struct aws_byte_cursor old_path; aws_http_message_get_request_path(request, &old_path); /* start with the old uri and parse it */ if (aws_uri_init_parse(&old_uri, allocator, &old_path)) { goto done; } /* pull out the old query params */ if (aws_array_list_init_dynamic( &query_params, allocator, DEFAULT_QUERY_PARAM_COUNT, sizeof(struct aws_uri_param))) { goto done; } if (aws_uri_query_string_params(&old_uri, &query_params)) { goto done; } /* initialize a builder for the new uri matching the old uri */ new_uri_builder.host_name = old_uri.host_name; new_uri_builder.path = old_uri.path; new_uri_builder.port = old_uri.port; new_uri_builder.scheme = old_uri.scheme; new_uri_builder.query_params = &query_params; /* and now add any signing query params */ for (size_t i = 0; i < signed_query_param_count; ++i) { struct aws_signing_result_property source_param; if (aws_array_list_get_at(result_param_list, &source_param, i)) { goto done; } struct aws_uri_param signed_param; signed_param.key = aws_byte_cursor_from_string(source_param.name); signed_param.value = aws_byte_cursor_from_string(source_param.value); aws_array_list_push_back(&query_params, &signed_param); } /* create the new uri */ if (aws_uri_init_from_builder_options(&new_uri, allocator, &new_uri_builder)) { goto done; } /* copy the full string */ struct aws_byte_cursor new_uri_cursor = aws_byte_cursor_from_buf(&new_uri.uri_str); if (aws_http_message_set_request_path(request, new_uri_cursor)) { goto done; } result = AWS_OP_SUCCESS; done: aws_array_list_clean_up(&query_params); aws_uri_clean_up(&new_uri); aws_uri_clean_up(&old_uri); return result; } /* * Takes a mutable http request and adds all the additional query params and/or headers generated by the * signing process. */ int aws_apply_signing_result_to_http_request( struct aws_http_message *request, struct aws_allocator *allocator, const struct aws_signing_result *result) { /* uri/query params */ if (s_build_request_uri(allocator, request, result)) { return AWS_OP_ERR; } /* headers */ size_t signing_header_count = 0; struct aws_array_list *result_header_list = NULL; aws_signing_result_get_property_list(result, g_aws_http_headers_property_list_name, &result_header_list); if (result_header_list != NULL) { signing_header_count = aws_array_list_length(result_header_list); } for (size_t i = 0; i < signing_header_count; ++i) { struct aws_signing_result_property source_header; AWS_ZERO_STRUCT(source_header); if (aws_array_list_get_at(result_header_list, &source_header, i)) { return AWS_OP_ERR; } if (source_header.name == NULL || source_header.value == NULL) { return aws_raise_error(AWS_ERROR_INVALID_ARGUMENT); } struct aws_http_header dest_header = { .name = aws_byte_cursor_from_string(source_header.name), .value = aws_byte_cursor_from_string(source_header.value), }; aws_http_message_add_header(request, dest_header); } return AWS_OP_SUCCESS; }