1 /**
2  * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
3  * SPDX-License-Identifier: Apache-2.0.
4  */
5 
6 #include <aws/auth/signing_result.h>
7 
8 #include <aws/common/byte_buf.h>
9 #include <aws/common/string.h>
10 
11 #define INITIAL_SIGNING_RESULT_PROPERTIES_SIZE 10
12 #define INITIAL_SIGNING_RESULT_PROPERTY_LISTS_TABLE_SIZE 10
13 #define INITIAL_SIGNING_RESULT_PROPERTY_LIST_SIZE 10
14 
s_aws_signing_result_property_clean_up(struct aws_signing_result_property * pair)15 static void s_aws_signing_result_property_clean_up(struct aws_signing_result_property *pair) {
16     aws_string_destroy(pair->name);
17     aws_string_destroy(pair->value);
18 }
19 
s_aws_hash_callback_property_list_destroy(void * value)20 static void s_aws_hash_callback_property_list_destroy(void *value) {
21     struct aws_array_list *property_list = value;
22 
23     size_t property_count = aws_array_list_length(property_list);
24     for (size_t i = 0; i < property_count; ++i) {
25         struct aws_signing_result_property property;
26         AWS_ZERO_STRUCT(property);
27 
28         if (aws_array_list_get_at(property_list, &property, i)) {
29             continue;
30         }
31 
32         s_aws_signing_result_property_clean_up(&property);
33     }
34 
35     struct aws_allocator *allocator = property_list->alloc;
36     aws_array_list_clean_up(property_list);
37 
38     aws_mem_release(allocator, property_list);
39 }
40 
aws_signing_result_init(struct aws_signing_result * result,struct aws_allocator * allocator)41 int aws_signing_result_init(struct aws_signing_result *result, struct aws_allocator *allocator) {
42     AWS_ZERO_STRUCT(*result);
43 
44     result->allocator = allocator;
45     if (aws_hash_table_init(
46             &result->properties,
47             allocator,
48             INITIAL_SIGNING_RESULT_PROPERTIES_SIZE,
49             aws_hash_string,
50             aws_hash_callback_string_eq,
51             aws_hash_callback_string_destroy,
52             aws_hash_callback_string_destroy) ||
53         aws_hash_table_init(
54             &result->property_lists,
55             allocator,
56             INITIAL_SIGNING_RESULT_PROPERTY_LISTS_TABLE_SIZE,
57             aws_hash_string,
58             aws_hash_callback_string_eq,
59             aws_hash_callback_string_destroy,
60             s_aws_hash_callback_property_list_destroy)) {
61         goto on_error;
62     }
63 
64     return AWS_OP_SUCCESS;
65 
66 on_error:
67 
68     aws_signing_result_clean_up(result);
69 
70     return AWS_OP_ERR;
71 }
72 
aws_signing_result_clean_up(struct aws_signing_result * result)73 void aws_signing_result_clean_up(struct aws_signing_result *result) {
74     aws_hash_table_clean_up(&result->properties);
75     aws_hash_table_clean_up(&result->property_lists);
76 }
77 
aws_signing_result_set_property(struct aws_signing_result * result,const struct aws_string * property_name,const struct aws_byte_cursor * property_value)78 int aws_signing_result_set_property(
79     struct aws_signing_result *result,
80     const struct aws_string *property_name,
81     const struct aws_byte_cursor *property_value) {
82 
83     struct aws_string *name = NULL;
84     struct aws_string *value = NULL;
85 
86     name = aws_string_new_from_string(result->allocator, property_name);
87     value = aws_string_new_from_array(result->allocator, property_value->ptr, property_value->len);
88     if (name == NULL || value == NULL) {
89         goto on_error;
90     }
91 
92     if (aws_hash_table_put(&result->properties, name, value, NULL)) {
93         goto on_error;
94     }
95 
96     return AWS_OP_SUCCESS;
97 
98 on_error:
99 
100     aws_string_destroy(name);
101     aws_string_destroy(value);
102 
103     return AWS_OP_ERR;
104 }
105 
aws_signing_result_get_property(const struct aws_signing_result * result,const struct aws_string * property_name,struct aws_string ** out_property_value)106 int aws_signing_result_get_property(
107     const struct aws_signing_result *result,
108     const struct aws_string *property_name,
109     struct aws_string **out_property_value) {
110 
111     struct aws_hash_element *element = NULL;
112     aws_hash_table_find(&result->properties, property_name, &element);
113 
114     *out_property_value = NULL;
115     if (element != NULL) {
116         *out_property_value = element->value;
117     }
118 
119     return AWS_OP_SUCCESS;
120 }
121 
s_get_or_create_property_list(struct aws_signing_result * result,const struct aws_string * list_name)122 static struct aws_array_list *s_get_or_create_property_list(
123     struct aws_signing_result *result,
124     const struct aws_string *list_name) {
125     struct aws_hash_element *element = NULL;
126     aws_hash_table_find(&result->property_lists, list_name, &element);
127 
128     if (element != NULL) {
129         return element->value;
130     }
131 
132     struct aws_array_list *properties = aws_mem_acquire(result->allocator, sizeof(struct aws_array_list));
133     if (properties == NULL) {
134         return NULL;
135     }
136 
137     AWS_ZERO_STRUCT(*properties);
138     struct aws_string *name_copy = aws_string_new_from_string(result->allocator, list_name);
139     if (name_copy == NULL) {
140         goto on_error;
141     }
142 
143     if (aws_array_list_init_dynamic(
144             properties,
145             result->allocator,
146             INITIAL_SIGNING_RESULT_PROPERTY_LIST_SIZE,
147             sizeof(struct aws_signing_result_property))) {
148         goto on_error;
149     }
150 
151     if (aws_hash_table_put(&result->property_lists, name_copy, properties, NULL)) {
152         goto on_error;
153     }
154 
155     return properties;
156 
157 on_error:
158 
159     aws_string_destroy(name_copy);
160     aws_array_list_clean_up(properties);
161     aws_mem_release(result->allocator, properties);
162 
163     return NULL;
164 }
165 
aws_signing_result_append_property_list(struct aws_signing_result * result,const struct aws_string * list_name,const struct aws_byte_cursor * property_name,const struct aws_byte_cursor * property_value)166 int aws_signing_result_append_property_list(
167     struct aws_signing_result *result,
168     const struct aws_string *list_name,
169     const struct aws_byte_cursor *property_name,
170     const struct aws_byte_cursor *property_value) {
171 
172     struct aws_array_list *properties = s_get_or_create_property_list(result, list_name);
173     if (properties == NULL) {
174         return AWS_OP_ERR;
175     }
176 
177     struct aws_string *name = NULL;
178     struct aws_string *value = NULL;
179 
180     name = aws_string_new_from_array(result->allocator, property_name->ptr, property_name->len);
181     value = aws_string_new_from_array(result->allocator, property_value->ptr, property_value->len);
182 
183     struct aws_signing_result_property property;
184     property.name = name;
185     property.value = value;
186 
187     if (aws_array_list_push_back(properties, &property)) {
188         goto on_error;
189     }
190 
191     return AWS_OP_SUCCESS;
192 
193 on_error:
194 
195     aws_string_destroy(name);
196     aws_string_destroy(value);
197 
198     return AWS_OP_ERR;
199 }
200 
aws_signing_result_get_property_list(const struct aws_signing_result * result,const struct aws_string * list_name,struct aws_array_list ** out_list)201 void aws_signing_result_get_property_list(
202     const struct aws_signing_result *result,
203     const struct aws_string *list_name,
204     struct aws_array_list **out_list) {
205 
206     *out_list = NULL;
207 
208     struct aws_hash_element *element = NULL;
209     aws_hash_table_find(&result->property_lists, list_name, &element);
210 
211     if (element != NULL) {
212         *out_list = element->value;
213     }
214 }
215 
aws_signing_result_get_property_value_in_property_list(const struct aws_signing_result * result,const struct aws_string * list_name,const struct aws_string * property_name,struct aws_string ** out_value)216 void aws_signing_result_get_property_value_in_property_list(
217     const struct aws_signing_result *result,
218     const struct aws_string *list_name,
219     const struct aws_string *property_name,
220     struct aws_string **out_value) {
221 
222     *out_value = NULL;
223 
224     struct aws_array_list *property_list = NULL;
225     aws_signing_result_get_property_list(result, list_name, &property_list);
226     if (property_list == NULL) {
227         return;
228     }
229 
230     size_t pair_count = aws_array_list_length(property_list);
231     for (size_t i = 0; i < pair_count; ++i) {
232         struct aws_signing_result_property pair;
233         AWS_ZERO_STRUCT(pair);
234         if (aws_array_list_get_at(property_list, &pair, i)) {
235             continue;
236         }
237 
238         if (pair.name == NULL) {
239             continue;
240         }
241 
242         if (aws_string_eq_ignore_case(property_name, pair.name)) {
243             *out_value = pair.value;
244             break;
245         }
246     }
247 }
248