1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168
|
/**
* Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
* SPDX-License-Identifier: Apache-2.0.
*/
#include <aws/auth/private/sigv4_http_request.h>
#include <aws/auth/credentials.h>
#include <aws/auth/signable.h>
#include <aws/auth/signing.h>
#include <aws/auth/signing_result.h>
#include <aws/common/condition_variable.h>
#include <aws/common/mutex.h>
#include <aws/common/string.h>
#include <aws/http/request_response.h>
#include <aws/io/uri.h>
#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;
}
|