aboutsummaryrefslogtreecommitdiffstats
path: root/contrib/restricted/aws/aws-c-auth/source/sigv4_http_request.c
blob: 6e73f2e7f9e07036204af792de56d8b8b12f5039 (plain) (blame)
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_OP_ERR;
        }

        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;
}