1 /**
2 * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
3 * SPDX-License-Identifier: Apache-2.0.
4 */
5
6 #include "aws/s3/private/s3_client_impl.h"
7 #include "aws/s3/private/s3_meta_request_impl.h"
8 #include "aws/s3/private/s3_request_messages.h"
9 #include "aws/s3/private/s3_util.h"
10 #include "s3_tester.h"
11 #include <aws/common/atomics.h>
12 #include <aws/common/byte_buf.h>
13 #include <aws/common/clock.h>
14 #include <aws/common/common.h>
15 #include <aws/common/ref_count.h>
16 #include <aws/common/xml_parser.h>
17 #include <aws/http/request_response.h>
18 #include <aws/io/stream.h>
19 #include <aws/io/tls_channel_handler.h>
20 #include <aws/testing/aws_test_harness.h>
21 #include <inttypes.h>
22
23 static const struct aws_http_header get_object_test_headers[] = {
24 {
25 .name = AWS_BYTE_CUR_INIT_FROM_STRING_LITERAL("Host"),
26 .value = AWS_BYTE_CUR_INIT_FROM_STRING_LITERAL("HostValue"),
27 },
28 {
29 .name = AWS_BYTE_CUR_INIT_FROM_STRING_LITERAL("If-Match"),
30 .value = AWS_BYTE_CUR_INIT_FROM_STRING_LITERAL("If-MatchValue"),
31 },
32 {
33 .name = AWS_BYTE_CUR_INIT_FROM_STRING_LITERAL("If-Modified-Since"),
34 .value = AWS_BYTE_CUR_INIT_FROM_STRING_LITERAL("If-Modified-SinceValue"),
35 },
36 {
37 .name = AWS_BYTE_CUR_INIT_FROM_STRING_LITERAL("If-None-Match"),
38 .value = AWS_BYTE_CUR_INIT_FROM_STRING_LITERAL("If-None-MatchValue"),
39 },
40 {
41 .name = AWS_BYTE_CUR_INIT_FROM_STRING_LITERAL("Range"),
42 .value = AWS_BYTE_CUR_INIT_FROM_STRING_LITERAL("RangeValue"),
43 },
44 {
45 .name = AWS_BYTE_CUR_INIT_FROM_STRING_LITERAL("x-amz-server-side-encryption-customer-algorithm"),
46 .value = AWS_BYTE_CUR_INIT_FROM_STRING_LITERAL("x-amz-server-side-encryption-customer-algorithmValue"),
47 },
48 {
49 .name = AWS_BYTE_CUR_INIT_FROM_STRING_LITERAL("x-amz-server-side-encryption-customer-key"),
50 .value = AWS_BYTE_CUR_INIT_FROM_STRING_LITERAL("x-amz-server-side-encryption-customer-keyValue"),
51 },
52 {
53 .name = AWS_BYTE_CUR_INIT_FROM_STRING_LITERAL("x-amz-server-side-encryption-customer-key-MD5"),
54 .value = AWS_BYTE_CUR_INIT_FROM_STRING_LITERAL("x-amz-server-side-encryption-customer-key-MD5Value"),
55 },
56 {
57 .name = AWS_BYTE_CUR_INIT_FROM_STRING_LITERAL("x-amz-request-payer"),
58 .value = AWS_BYTE_CUR_INIT_FROM_STRING_LITERAL("x-amz-request-payerValue"),
59 },
60 {
61 .name = AWS_BYTE_CUR_INIT_FROM_STRING_LITERAL("x-amz-expected-bucket-owner"),
62 .value = AWS_BYTE_CUR_INIT_FROM_STRING_LITERAL("x-amz-expected-bucket-ownerValue"),
63 },
64 };
65
66 static const struct aws_http_header s_put_object_test_headers[] = {
67 {
68 .name = AWS_BYTE_CUR_INIT_FROM_STRING_LITERAL("x-amz-acl"),
69 .value = AWS_BYTE_CUR_INIT_FROM_STRING_LITERAL("ACLValue"),
70 },
71 {
72 .name = AWS_BYTE_CUR_INIT_FROM_STRING_LITERAL("Cache-Control"),
73 .value = AWS_BYTE_CUR_INIT_FROM_STRING_LITERAL("CacheControlValue"),
74 },
75 {
76 .name = AWS_BYTE_CUR_INIT_FROM_STRING_LITERAL("Content-Disposition"),
77 .value = AWS_BYTE_CUR_INIT_FROM_STRING_LITERAL("ContentDispositionValue"),
78 },
79 {
80 .name = AWS_BYTE_CUR_INIT_FROM_STRING_LITERAL("Content-Encoding"),
81 .value = AWS_BYTE_CUR_INIT_FROM_STRING_LITERAL("ContentEncodingValue"),
82 },
83 {
84 .name = AWS_BYTE_CUR_INIT_FROM_STRING_LITERAL("Content-Language"),
85 .value = AWS_BYTE_CUR_INIT_FROM_STRING_LITERAL("ContentLanguageValue"),
86 },
87 {
88 .name = AWS_BYTE_CUR_INIT_FROM_STRING_LITERAL("Content-Length"),
89 .value = AWS_BYTE_CUR_INIT_FROM_STRING_LITERAL("ContentLengthValue"),
90 },
91 {
92 .name = AWS_BYTE_CUR_INIT_FROM_STRING_LITERAL("Content-MD5"),
93 .value = AWS_BYTE_CUR_INIT_FROM_STRING_LITERAL("ContentMD5Value"),
94 },
95 {
96 .name = AWS_BYTE_CUR_INIT_FROM_STRING_LITERAL("Content-Type"),
97 .value = AWS_BYTE_CUR_INIT_FROM_STRING_LITERAL("ContentTypeValue"),
98 },
99 {
100 .name = AWS_BYTE_CUR_INIT_FROM_STRING_LITERAL("Expires"),
101 .value = AWS_BYTE_CUR_INIT_FROM_STRING_LITERAL("ExpiresValue"),
102 },
103 {
104 .name = AWS_BYTE_CUR_INIT_FROM_STRING_LITERAL("x-amz-grant-full-control"),
105 .value = AWS_BYTE_CUR_INIT_FROM_STRING_LITERAL("GrantFullControlValue"),
106 },
107 {
108 .name = AWS_BYTE_CUR_INIT_FROM_STRING_LITERAL("x-amz-grant-read"),
109 .value = AWS_BYTE_CUR_INIT_FROM_STRING_LITERAL("GrantReadValue"),
110 },
111 {
112 .name = AWS_BYTE_CUR_INIT_FROM_STRING_LITERAL("x-amz-grant-read-acp"),
113 .value = AWS_BYTE_CUR_INIT_FROM_STRING_LITERAL("GrantReadACPValue"),
114 },
115 {
116 .name = AWS_BYTE_CUR_INIT_FROM_STRING_LITERAL("x-amz-grant-write-acp"),
117 .value = AWS_BYTE_CUR_INIT_FROM_STRING_LITERAL("GrantWriteACPValue"),
118 },
119 {
120 .name = AWS_BYTE_CUR_INIT_FROM_STRING_LITERAL("x-amz-server-side-encryption"),
121 .value = AWS_BYTE_CUR_INIT_FROM_STRING_LITERAL("ServerSideEncryptionValue"),
122 },
123 {
124 .name = AWS_BYTE_CUR_INIT_FROM_STRING_LITERAL("x-amz-storage-class"),
125 .value = AWS_BYTE_CUR_INIT_FROM_STRING_LITERAL("StorageClassValue"),
126 },
127 {
128 .name = AWS_BYTE_CUR_INIT_FROM_STRING_LITERAL("x-amz-website-redirect-location"),
129 .value = AWS_BYTE_CUR_INIT_FROM_STRING_LITERAL("WebsiteRedirectLocationValue"),
130 },
131 {
132 .name = AWS_BYTE_CUR_INIT_FROM_STRING_LITERAL("x-amz-server-side-encryption-customer-algorithm"),
133 .value = AWS_BYTE_CUR_INIT_FROM_STRING_LITERAL("SSECustomerAlgorithmValue"),
134 },
135 {
136 .name = AWS_BYTE_CUR_INIT_FROM_STRING_LITERAL("x-amz-server-side-encryption-customer-key"),
137 .value = AWS_BYTE_CUR_INIT_FROM_STRING_LITERAL("SSECustomerKeyValue"),
138 },
139 {
140 .name = AWS_BYTE_CUR_INIT_FROM_STRING_LITERAL("x-amz-server-side-encryption-customer-key-MD5"),
141 .value = AWS_BYTE_CUR_INIT_FROM_STRING_LITERAL("SSECustomerKeyMD5Value"),
142 },
143 {
144 .name = AWS_BYTE_CUR_INIT_FROM_STRING_LITERAL("x-amz-server-side-encryption-aws-kms-key-id"),
145 .value = AWS_BYTE_CUR_INIT_FROM_STRING_LITERAL("SSEKMSKeyIdValue"),
146 },
147 {
148 .name = AWS_BYTE_CUR_INIT_FROM_STRING_LITERAL("x-amz-server-side-encryption-context"),
149 .value = AWS_BYTE_CUR_INIT_FROM_STRING_LITERAL("SSEKMSEncryptionContextValue"),
150 },
151 {
152 .name = AWS_BYTE_CUR_INIT_FROM_STRING_LITERAL("x-amz-server-side-encryption-bucket-key-enabled"),
153 .value = AWS_BYTE_CUR_INIT_FROM_STRING_LITERAL("BucketKeyEnabledValue"),
154 },
155 {
156 .name = AWS_BYTE_CUR_INIT_FROM_STRING_LITERAL("x-amz-request-payer"),
157 .value = AWS_BYTE_CUR_INIT_FROM_STRING_LITERAL("RequestPayerValue"),
158 },
159 {
160 .name = AWS_BYTE_CUR_INIT_FROM_STRING_LITERAL("x-amz-tagging"),
161 .value = AWS_BYTE_CUR_INIT_FROM_STRING_LITERAL("TaggingValue"),
162 },
163 {
164 .name = AWS_BYTE_CUR_INIT_FROM_STRING_LITERAL("x-amz-object-lock-mode"),
165 .value = AWS_BYTE_CUR_INIT_FROM_STRING_LITERAL("ObjectLockModeValue"),
166 },
167 {
168 .name = AWS_BYTE_CUR_INIT_FROM_STRING_LITERAL("x-amz-object-lock-retain-until-date"),
169 .value = AWS_BYTE_CUR_INIT_FROM_STRING_LITERAL("ObjectLockRetainUntilDateValue"),
170 },
171 {
172 .name = AWS_BYTE_CUR_INIT_FROM_STRING_LITERAL("x-amz-object-lock-legal-hold"),
173 .value = AWS_BYTE_CUR_INIT_FROM_STRING_LITERAL("ObjectLockLegalHoldStatusValue"),
174 },
175 {
176 .name = AWS_BYTE_CUR_INIT_FROM_STRING_LITERAL("x-amz-expected-bucket-owner"),
177 .value = AWS_BYTE_CUR_INIT_FROM_STRING_LITERAL("ExpectedBucketOwnerValue"),
178 },
179 };
180
s_fill_byte_buf(struct aws_byte_buf * buffer,struct aws_allocator * allocator,size_t buffer_size)181 static int s_fill_byte_buf(struct aws_byte_buf *buffer, struct aws_allocator *allocator, size_t buffer_size) {
182 ASSERT_TRUE(buffer != NULL);
183 ASSERT_TRUE(allocator != NULL);
184 ASSERT_TRUE(buffer_size > 0);
185
186 ASSERT_SUCCESS(aws_byte_buf_init(buffer, allocator, buffer_size));
187
188 srand(0);
189
190 for (size_t i = 0; i < buffer_size; ++i) {
191 const char single_char = (char)(rand() % (int)('z' - 'a') + (int)'a');
192
193 struct aws_byte_cursor single_char_cursor = {
194 .ptr = (uint8_t *)&single_char,
195 .len = 1,
196 };
197
198 ASSERT_SUCCESS(aws_byte_buf_append(buffer, &single_char_cursor));
199 }
200
201 return AWS_OP_SUCCESS;
202 }
203
s_test_http_headers_match(struct aws_allocator * allocator,struct aws_http_message * message0,struct aws_http_message * message1,const struct aws_byte_cursor * excluded_message0_headers,size_t excluded_message0_headers_count,const struct aws_byte_cursor * message1_header_exceptions,size_t message1_header_exceptions_count)204 static int s_test_http_headers_match(
205 struct aws_allocator *allocator,
206 struct aws_http_message *message0,
207 struct aws_http_message *message1,
208
209 /* Headers that we know are in message0, but should NOT be in message1 */
210 const struct aws_byte_cursor *excluded_message0_headers,
211 size_t excluded_message0_headers_count,
212
213 /* Headers in message1 that are okay to be in message1 even if they are in the excluded list or are not in
214 message0.*/
215 const struct aws_byte_cursor *message1_header_exceptions,
216 size_t message1_header_exceptions_count) {
217 ASSERT_TRUE(message0 != NULL);
218 ASSERT_TRUE(message1 != NULL);
219 ASSERT_TRUE(excluded_message0_headers != NULL || excluded_message0_headers_count == 0);
220 ASSERT_TRUE(message1_header_exceptions != NULL || message1_header_exceptions_count == 0);
221
222 struct aws_http_headers *message0_headers = aws_http_message_get_headers(message0);
223 ASSERT_TRUE(message0_headers != NULL);
224
225 struct aws_http_headers *message1_headers = aws_http_message_get_headers(message1);
226 ASSERT_TRUE(message1_headers != NULL);
227
228 struct aws_http_headers *expected_message0_headers = aws_http_headers_new(allocator);
229
230 /* Copy message1 headers to expected_message0_headers. With upcoming adds/removes, it should transform back into
231 * message0.
232 */
233 for (size_t i = 0; i < aws_http_headers_count(message1_headers); ++i) {
234 struct aws_http_header message1_header;
235 AWS_ZERO_STRUCT(message1_header);
236 ASSERT_SUCCESS(aws_http_headers_get_index(message1_headers, i, &message1_header));
237 ASSERT_SUCCESS(aws_http_headers_add(expected_message0_headers, message1_header.name, message1_header.value));
238 }
239
240 /* Go through all of the headers that were originally removed from message1 after it was copied from message0. */
241 for (size_t i = 0; i < excluded_message0_headers_count; ++i) {
242 const struct aws_byte_cursor *excluded_header_name = &excluded_message0_headers[i];
243
244 bool header_existance_is_valid = false;
245
246 /* If the heaer is in the exception list, it's okay for message1 to have. (It may have been re-added.) */
247 for (size_t j = 0; j < message1_header_exceptions_count; ++j) {
248 if (aws_byte_cursor_eq(excluded_header_name, &message1_header_exceptions[j])) {
249 header_existance_is_valid = true;
250 break;
251 }
252 }
253
254 /* Try to get the header from message1. */
255 struct aws_byte_cursor message1_header_value;
256 AWS_ZERO_STRUCT(message1_header_value);
257 int result = aws_http_headers_get(message1_headers, *excluded_header_name, &message1_header_value);
258
259 if (header_existance_is_valid) {
260
261 /* If this header is allowed to exist in message1, then we don't need to assert on its existance or
262 * non-existance. But we do want to erase it from the expected_message0_headers, since its value may be
263 * different from that in message0. */
264 if (result == AWS_OP_SUCCESS) {
265 ASSERT_SUCCESS(aws_http_headers_erase(expected_message0_headers, *excluded_header_name));
266 }
267
268 } else {
269 /* In this case, message1 should not have the header. */
270 ASSERT_TRUE(result == AWS_OP_ERR && aws_last_error() == AWS_ERROR_HTTP_HEADER_NOT_FOUND);
271 }
272
273 /* At this point, expected_message0_headers should not have the excluded header in it. Add a copy of the header
274 * from message0 to expected_message0_headers to further transform it toward being a copy of message0 headers.
275 */
276 struct aws_byte_cursor message0_header_value;
277 AWS_ZERO_STRUCT(message0_header_value);
278 if (aws_http_headers_get(message0_headers, *excluded_header_name, &message0_header_value) == AWS_OP_SUCCESS) {
279 ASSERT_SUCCESS(
280 aws_http_headers_add(expected_message0_headers, *excluded_header_name, message0_header_value));
281 }
282 }
283
284 /* message0_headers should now match expected_message0_headers */
285 {
286 ASSERT_TRUE(aws_http_headers_count(message0_headers) == aws_http_headers_count(expected_message0_headers));
287
288 for (size_t i = 0; i < aws_http_headers_count(message0_headers); ++i) {
289 struct aws_http_header message0_header;
290 AWS_ZERO_STRUCT(message0_header);
291 ASSERT_SUCCESS(aws_http_headers_get_index(message0_headers, i, &message0_header));
292
293 struct aws_byte_cursor expected_message0_header_value;
294 AWS_ZERO_STRUCT(expected_message0_header_value);
295 ASSERT_SUCCESS(
296 aws_http_headers_get(expected_message0_headers, message0_header.name, &expected_message0_header_value));
297
298 ASSERT_TRUE(aws_byte_cursor_eq(&message0_header.value, &expected_message0_header_value));
299 }
300 }
301
302 aws_http_headers_release(expected_message0_headers);
303
304 return AWS_OP_SUCCESS;
305 }
306
s_test_http_messages_match(struct aws_allocator * allocator,struct aws_http_message * message0,struct aws_http_message * message1,const struct aws_byte_cursor * excluded_headers,size_t excluded_headers_count)307 static int s_test_http_messages_match(
308 struct aws_allocator *allocator,
309 struct aws_http_message *message0,
310 struct aws_http_message *message1,
311 const struct aws_byte_cursor *excluded_headers,
312 size_t excluded_headers_count) {
313 ASSERT_TRUE(message0 != NULL);
314 ASSERT_TRUE(message1 != NULL);
315 ASSERT_TRUE(excluded_headers != NULL || excluded_headers_count == 0);
316
317 struct aws_byte_cursor request_path;
318 AWS_ZERO_STRUCT(request_path);
319 ASSERT_SUCCESS(aws_http_message_get_request_path(message0, &request_path));
320
321 struct aws_byte_cursor copied_request_path;
322 AWS_ZERO_STRUCT(copied_request_path);
323 ASSERT_SUCCESS(aws_http_message_get_request_path(message1, &copied_request_path));
324
325 ASSERT_TRUE(aws_byte_cursor_eq(&request_path, &copied_request_path));
326
327 struct aws_byte_cursor request_method;
328 AWS_ZERO_STRUCT(request_method);
329 ASSERT_SUCCESS(aws_http_message_get_request_method(message0, &request_method));
330
331 struct aws_byte_cursor copied_request_method;
332 AWS_ZERO_STRUCT(copied_request_method);
333 ASSERT_SUCCESS(aws_http_message_get_request_method(message1, &copied_request_method));
334
335 ASSERT_TRUE(aws_byte_cursor_eq(&request_method, &copied_request_method));
336
337 ASSERT_SUCCESS(
338 s_test_http_headers_match(allocator, message0, message1, excluded_headers, excluded_headers_count, NULL, 0));
339
340 return AWS_OP_SUCCESS;
341 }
342
s_test_http_message_request_path(struct aws_http_message * message,const struct aws_byte_cursor * request_path)343 static int s_test_http_message_request_path(
344 struct aws_http_message *message,
345 const struct aws_byte_cursor *request_path) {
346
347 struct aws_byte_cursor message_request_path;
348 AWS_ZERO_STRUCT(message_request_path);
349 ASSERT_SUCCESS(aws_http_message_get_request_path(message, &message_request_path));
350
351 ASSERT_TRUE(aws_byte_cursor_eq(&message_request_path, request_path));
352
353 return AWS_OP_SUCCESS;
354 }
355
s_test_http_message_request_method(struct aws_http_message * message,const char * method)356 static int s_test_http_message_request_method(struct aws_http_message *message, const char *method) {
357
358 struct aws_byte_cursor message_request_method;
359 AWS_ZERO_STRUCT(message_request_method);
360 ASSERT_SUCCESS(aws_http_message_get_request_method(message, &message_request_method));
361
362 struct aws_byte_cursor method_cursor = aws_byte_cursor_from_c_str(method);
363
364 ASSERT_TRUE(aws_byte_cursor_eq(&message_request_method, &method_cursor));
365
366 return AWS_OP_SUCCESS;
367 }
368
s_test_http_message_body_stream(struct aws_allocator * allocator,struct aws_http_message * derived_message,struct aws_byte_buf * expected_stream_contents)369 static int s_test_http_message_body_stream(
370 struct aws_allocator *allocator,
371 struct aws_http_message *derived_message,
372 struct aws_byte_buf *expected_stream_contents) {
373 ASSERT_TRUE(derived_message != NULL);
374 ASSERT_TRUE(expected_stream_contents != NULL);
375
376 struct aws_http_headers *headers = aws_http_message_get_headers(derived_message);
377 ASSERT_TRUE(headers != NULL);
378
379 struct aws_input_stream *body_stream = aws_http_message_get_body_stream(derived_message);
380 ASSERT_TRUE(body_stream != NULL);
381
382 /* Check for the content length header. */
383 struct aws_byte_cursor content_length_header_value;
384 AWS_ZERO_STRUCT(content_length_header_value);
385 ASSERT_SUCCESS(aws_http_headers_get(headers, g_content_length_header_name, &content_length_header_value));
386
387 struct aws_string *content_length_header_str = aws_string_new_from_cursor(allocator, &content_length_header_value);
388 uint32_t content_length = (uint32_t)atoi((const char *)content_length_header_str->bytes);
389 ASSERT_TRUE(content_length == (uint32_t)expected_stream_contents->len);
390 aws_string_destroy(content_length_header_str);
391
392 /* Check that the stream data is equal to the original buffer data. */
393 struct aws_byte_buf stream_read_buffer;
394 ASSERT_SUCCESS(aws_byte_buf_init(&stream_read_buffer, allocator, expected_stream_contents->len));
395 ASSERT_SUCCESS(aws_input_stream_read(body_stream, &stream_read_buffer));
396 ASSERT_TRUE(aws_byte_buf_eq(expected_stream_contents, &stream_read_buffer));
397 aws_byte_buf_clean_up(&stream_read_buffer);
398
399 /* There should be no data left in the stream. */
400 struct aws_byte_buf stream_overread_buffer;
401 ASSERT_SUCCESS(aws_byte_buf_init(&stream_overread_buffer, allocator, expected_stream_contents->len));
402 ASSERT_SUCCESS(aws_input_stream_read(body_stream, &stream_overread_buffer));
403 ASSERT_TRUE(stream_overread_buffer.len == 0);
404 aws_byte_buf_clean_up(&stream_overread_buffer);
405
406 return AWS_OP_SUCCESS;
407 }
408
s_create_get_object_message(struct aws_allocator * allocator,const struct aws_byte_cursor * path,struct aws_http_message ** out_message)409 int s_create_get_object_message(
410 struct aws_allocator *allocator,
411 const struct aws_byte_cursor *path,
412 struct aws_http_message **out_message) {
413 ASSERT_TRUE(out_message != NULL);
414 ASSERT_TRUE(*out_message == NULL);
415
416 struct aws_http_message *message = aws_http_message_new_request(allocator);
417 ASSERT_TRUE(message != NULL);
418
419 ASSERT_SUCCESS(aws_http_message_set_request_path(message, *path));
420 ASSERT_SUCCESS(aws_http_message_set_request_method(message, aws_byte_cursor_from_c_str("GET")));
421
422 for (size_t i = 0; i < AWS_ARRAY_SIZE(get_object_test_headers); ++i) {
423 ASSERT_SUCCESS(aws_http_message_add_header(message, get_object_test_headers[i]));
424 }
425
426 *out_message = message;
427
428 return AWS_OP_SUCCESS;
429 }
430
s_create_put_object_message(struct aws_allocator * allocator,const struct aws_byte_cursor * path,struct aws_http_message ** out_message)431 int s_create_put_object_message(
432 struct aws_allocator *allocator,
433 const struct aws_byte_cursor *path,
434 struct aws_http_message **out_message) {
435 ASSERT_TRUE(out_message != NULL);
436 ASSERT_TRUE(*out_message == NULL);
437
438 struct aws_http_message *message = aws_http_message_new_request(allocator);
439 ASSERT_TRUE(message != NULL);
440
441 ASSERT_SUCCESS(aws_http_message_set_request_path(message, *path));
442 ASSERT_SUCCESS(aws_http_message_set_request_method(message, aws_byte_cursor_from_c_str("PUT")));
443
444 for (size_t i = 0; i < AWS_ARRAY_SIZE(s_put_object_test_headers); ++i) {
445 ASSERT_SUCCESS(aws_http_message_add_header(message, s_put_object_test_headers[i]));
446 }
447
448 *out_message = message;
449
450 return AWS_OP_SUCCESS;
451 ;
452 }
453
AWS_TEST_CASE(test_s3_copy_http_message,s_test_s3_copy_http_message)454 AWS_TEST_CASE(test_s3_copy_http_message, s_test_s3_copy_http_message)
455 static int s_test_s3_copy_http_message(struct aws_allocator *allocator, void *ctx) {
456 (void)ctx;
457
458 const struct aws_byte_cursor request_method = AWS_BYTE_CUR_INIT_FROM_STRING_LITERAL("RequestMethod");
459 const struct aws_byte_cursor request_path = AWS_BYTE_CUR_INIT_FROM_STRING_LITERAL("RequestPath");
460
461 const struct aws_http_header included_header = {
462 .name = AWS_BYTE_CUR_INIT_FROM_STRING_LITERAL("IncludedHeader"),
463 .value = AWS_BYTE_CUR_INIT_FROM_STRING_LITERAL("IncludedHeaderValue"),
464 };
465
466 const struct aws_http_header excluded_header = {
467 .name = AWS_BYTE_CUR_INIT_FROM_STRING_LITERAL("ExcludedHeader"),
468 .value = AWS_BYTE_CUR_INIT_FROM_STRING_LITERAL("ExcludedHeaderValue"),
469 };
470
471 struct aws_http_message *message = aws_http_message_new_request(allocator);
472 ASSERT_TRUE(message != NULL);
473 ASSERT_SUCCESS(aws_http_message_set_request_method(message, request_method));
474 ASSERT_SUCCESS(aws_http_message_set_request_path(message, request_path));
475
476 struct aws_http_headers *message_headers = aws_http_message_get_headers(message);
477 ASSERT_TRUE(message != NULL);
478 ASSERT_SUCCESS(aws_http_headers_add(message_headers, included_header.name, included_header.value));
479 ASSERT_SUCCESS(aws_http_headers_add(message_headers, excluded_header.name, excluded_header.value));
480
481 struct aws_http_message *copied_message =
482 aws_s3_message_util_copy_http_message(allocator, message, &excluded_header.name, 1);
483 ASSERT_TRUE(copied_message != NULL);
484
485 ASSERT_SUCCESS(s_test_http_messages_match(allocator, message, copied_message, &excluded_header.name, 1));
486
487 aws_http_message_release(copied_message);
488 aws_http_message_release(message);
489
490 return 0;
491 }
492
AWS_TEST_CASE(test_s3_message_util_assign_body,s_test_s3_message_util_assign_body)493 AWS_TEST_CASE(test_s3_message_util_assign_body, s_test_s3_message_util_assign_body)
494 static int s_test_s3_message_util_assign_body(struct aws_allocator *allocator, void *ctx) {
495 (void)ctx;
496
497 struct aws_http_message *message = aws_http_message_new_request(allocator);
498
499 const size_t test_buffer_size = 42;
500 struct aws_byte_buf test_buffer;
501 ASSERT_SUCCESS(s_fill_byte_buf(&test_buffer, allocator, test_buffer_size));
502
503 struct aws_input_stream *input_stream = aws_s3_message_util_assign_body(allocator, &test_buffer, message);
504 ASSERT_TRUE(input_stream != NULL);
505
506 ASSERT_TRUE(aws_http_message_get_body_stream(message) == input_stream);
507 ASSERT_SUCCESS(s_test_http_message_body_stream(allocator, message, &test_buffer));
508
509 aws_input_stream_destroy(input_stream);
510 aws_byte_buf_clean_up(&test_buffer);
511 aws_http_message_release(message);
512
513 return 0;
514 }
515
AWS_TEST_CASE(test_s3_ranged_get_object_message_new,s_test_s3_ranged_get_object_message_new)516 AWS_TEST_CASE(test_s3_ranged_get_object_message_new, s_test_s3_ranged_get_object_message_new)
517 static int s_test_s3_ranged_get_object_message_new(struct aws_allocator *allocator, void *ctx) {
518 (void)ctx;
519
520 const struct aws_byte_cursor test_path = AWS_BYTE_CUR_INIT_FROM_STRING_LITERAL("/TestPath");
521
522 struct aws_http_message *original_message = NULL;
523 ASSERT_SUCCESS(s_create_get_object_message(allocator, &test_path, &original_message));
524 ASSERT_TRUE(original_message != NULL);
525
526 {
527 char expected_range_value_buffer[128] = "bytes=42-83";
528 struct aws_byte_cursor expected_range_value_cursor = aws_byte_cursor_from_c_str(expected_range_value_buffer);
529
530 struct aws_http_message *get_object_message =
531 aws_s3_ranged_get_object_message_new(allocator, original_message, 42, 83);
532 ASSERT_TRUE(get_object_message != NULL);
533
534 struct aws_http_headers *headers = aws_http_message_get_headers(get_object_message);
535 ASSERT_TRUE(headers != NULL);
536
537 struct aws_byte_cursor range_header_value;
538 AWS_ZERO_STRUCT(range_header_value);
539 ASSERT_SUCCESS(aws_http_headers_get(headers, g_range_header_name, &range_header_value));
540
541 ASSERT_TRUE(aws_byte_cursor_eq(&range_header_value, &expected_range_value_cursor));
542
543 s_test_http_message_request_method(get_object_message, "GET");
544
545 aws_http_message_release(get_object_message);
546 }
547
548 aws_http_message_release(original_message);
549
550 return 0;
551 }
552
AWS_TEST_CASE(test_s3_set_multipart_request_path,s_test_s3_set_multipart_request_path)553 AWS_TEST_CASE(test_s3_set_multipart_request_path, s_test_s3_set_multipart_request_path)
554 static int s_test_s3_set_multipart_request_path(struct aws_allocator *allocator, void *ctx) {
555 (void)ctx;
556
557 #define TEST_PATH "/TestPath"
558 #define TEST_PATH_WITH_PARAMS "/TestPath?arg=value"
559 #define UPLOAD_ID "test_upload_id"
560 #define UPLOAD_ID_PARAM "uploadId=test_upload_id"
561 #define PART_NUMBER 4
562 #define UPLOADS_PARAM "uploads"
563
564 const struct aws_byte_cursor test_path = AWS_BYTE_CUR_INIT_FROM_STRING_LITERAL(TEST_PATH);
565 const struct aws_byte_cursor test_path_with_params = AWS_BYTE_CUR_INIT_FROM_STRING_LITERAL(TEST_PATH_WITH_PARAMS);
566
567 struct aws_byte_cursor test_path_permutations[] = {
568 AWS_BYTE_CUR_INIT_FROM_STRING_LITERAL("/TestPath"),
569 AWS_BYTE_CUR_INIT_FROM_STRING_LITERAL("/TestPath?uploads"),
570 AWS_BYTE_CUR_INIT_FROM_STRING_LITERAL("/TestPath?partNumber=4"),
571 AWS_BYTE_CUR_INIT_FROM_STRING_LITERAL("/TestPath?partNumber=4&uploads"),
572 AWS_BYTE_CUR_INIT_FROM_STRING_LITERAL("/TestPath?uploadId=test_upload_id"),
573 AWS_BYTE_CUR_INIT_FROM_STRING_LITERAL("/TestPath?uploadId=test_upload_id&uploads"),
574 AWS_BYTE_CUR_INIT_FROM_STRING_LITERAL("/TestPath?partNumber=4&uploadId=test_upload_id"),
575 AWS_BYTE_CUR_INIT_FROM_STRING_LITERAL("/TestPath?partNumber=4&uploadId=test_upload_id&uploads"),
576 };
577
578 struct aws_byte_cursor test_path_with_params_permutations[] = {
579 AWS_BYTE_CUR_INIT_FROM_STRING_LITERAL("/TestPath?arg=value"),
580 AWS_BYTE_CUR_INIT_FROM_STRING_LITERAL("/TestPath?arg=value&uploads"),
581 AWS_BYTE_CUR_INIT_FROM_STRING_LITERAL("/TestPath?arg=value&partNumber=4"),
582 AWS_BYTE_CUR_INIT_FROM_STRING_LITERAL("/TestPath?arg=value&partNumber=4&uploads"),
583 AWS_BYTE_CUR_INIT_FROM_STRING_LITERAL("/TestPath?arg=value&uploadId=test_upload_id"),
584 AWS_BYTE_CUR_INIT_FROM_STRING_LITERAL("/TestPath?arg=value&uploadId=test_upload_id&uploads"),
585 AWS_BYTE_CUR_INIT_FROM_STRING_LITERAL("/TestPath?arg=value&partNumber=4&uploadId=test_upload_id"),
586 AWS_BYTE_CUR_INIT_FROM_STRING_LITERAL("/TestPath?arg=value&partNumber=4&uploadId=test_upload_id&uploads"),
587 };
588
589 const uint32_t num_permutations = 8;
590
591 for (uint32_t i = 0; i < num_permutations; ++i) {
592 struct aws_string *upload_id = NULL;
593 uint32_t part_number = 0;
594 bool uploads_param = false;
595
596 if (i & 0x4) {
597 upload_id = aws_string_new_from_c_str(allocator, UPLOAD_ID);
598 }
599
600 if (i & 0x2) {
601 part_number = PART_NUMBER;
602 }
603
604 if (i & 0x1) {
605 uploads_param = true;
606 }
607
608 {
609 struct aws_http_message *message = NULL;
610 ASSERT_SUCCESS(s_create_put_object_message(allocator, &test_path, &message));
611
612 ASSERT_SUCCESS(aws_s3_message_util_set_multipart_request_path(
613 allocator, upload_id, part_number, uploads_param, message));
614
615 ASSERT_SUCCESS(s_test_http_message_request_path(message, &test_path_permutations[i]));
616
617 aws_http_message_release(message);
618 }
619
620 {
621 struct aws_http_message *message_with_params = NULL;
622 ASSERT_SUCCESS(s_create_put_object_message(allocator, &test_path_with_params, &message_with_params));
623
624 ASSERT_SUCCESS(aws_s3_message_util_set_multipart_request_path(
625 allocator, upload_id, part_number, uploads_param, message_with_params));
626
627 ASSERT_SUCCESS(
628 s_test_http_message_request_path(message_with_params, &test_path_with_params_permutations[i]));
629
630 aws_http_message_release(message_with_params);
631 }
632
633 aws_string_destroy(upload_id);
634 }
635
636 #undef TEST_PATH
637 #undef TEST_PATH_WITH_PARAMS
638 #undef UPLOAD_ID
639 #undef UPLOAD_ID_PARAM
640 #undef PART_NUMBER
641 #undef UPLOADS_PARAM
642
643 return 0;
644 }
645
AWS_TEST_CASE(test_s3_create_multipart_upload_message_new,s_test_s3_create_multipart_upload_message_new)646 AWS_TEST_CASE(test_s3_create_multipart_upload_message_new, s_test_s3_create_multipart_upload_message_new)
647 static int s_test_s3_create_multipart_upload_message_new(struct aws_allocator *allocator, void *ctx) {
648 (void)ctx;
649
650 struct aws_byte_cursor path = AWS_BYTE_CUR_INIT_FROM_STRING_LITERAL("/TestPath");
651 struct aws_byte_cursor expected_create_path = AWS_BYTE_CUR_INIT_FROM_STRING_LITERAL("/TestPath?uploads");
652
653 struct aws_http_message *original_message = NULL;
654 ASSERT_SUCCESS(s_create_put_object_message(allocator, &path, &original_message));
655 ASSERT_TRUE(original_message != NULL);
656
657 struct aws_http_message *create_multipart_upload_message =
658 aws_s3_create_multipart_upload_message_new(allocator, original_message);
659 ASSERT_TRUE(create_multipart_upload_message != NULL);
660
661 ASSERT_SUCCESS(s_test_http_message_request_method(create_multipart_upload_message, "POST"));
662 ASSERT_SUCCESS(s_test_http_message_request_path(create_multipart_upload_message, &expected_create_path));
663 ASSERT_SUCCESS(s_test_http_headers_match(
664 allocator,
665 original_message,
666 create_multipart_upload_message,
667 g_s3_create_multipart_upload_excluded_headers,
668 g_s3_create_multipart_upload_excluded_headers_count,
669 NULL,
670 0));
671
672 aws_http_message_release(create_multipart_upload_message);
673 aws_http_message_release(original_message);
674
675 return 0;
676 }
677
AWS_TEST_CASE(test_s3_upload_part_message_new,s_test_s3_upload_part_message_new)678 AWS_TEST_CASE(test_s3_upload_part_message_new, s_test_s3_upload_part_message_new)
679 static int s_test_s3_upload_part_message_new(struct aws_allocator *allocator, void *ctx) {
680 (void)ctx;
681
682 #define STRINGIFY_HELPER(x) #x
683 #define STRINGIFY(x) STRINGIFY_HELPER(x)
684 #define TEST_PATH "/TestPath"
685 #define UPLOAD_ID "test_upload_id"
686 #define PART_NUMBER 4
687 #define PART_NUMBER_STR "?partNumber=" STRINGIFY(PART_NUMBER)
688 #define EXPECTED_UPLOAD_PART_PATH TEST_PATH PART_NUMBER_STR "&uploadId=" UPLOAD_ID
689
690 const struct aws_byte_cursor header_exclude_exceptions[] = {
691 AWS_BYTE_CUR_INIT_FROM_STRING_LITERAL("Content-Length"),
692 };
693
694 struct aws_byte_cursor path = AWS_BYTE_CUR_INIT_FROM_STRING_LITERAL(TEST_PATH);
695 struct aws_byte_cursor expected_create_path = aws_byte_cursor_from_c_str(EXPECTED_UPLOAD_PART_PATH);
696
697 struct aws_http_message *original_message = NULL;
698 ASSERT_SUCCESS(s_create_put_object_message(allocator, &path, &original_message));
699 ASSERT_TRUE(original_message != NULL);
700
701 const size_t part_buffer_size = 42;
702 struct aws_byte_buf part_buffer;
703 AWS_ZERO_STRUCT(part_buffer);
704 s_fill_byte_buf(&part_buffer, allocator, part_buffer_size);
705
706 struct aws_string *upload_id = aws_string_new_from_c_str(allocator, UPLOAD_ID);
707
708 struct aws_http_message *upload_part_message =
709 aws_s3_upload_part_message_new(allocator, original_message, &part_buffer, PART_NUMBER, upload_id, false);
710 ASSERT_TRUE(upload_part_message != NULL);
711
712 ASSERT_SUCCESS(s_test_http_message_request_method(upload_part_message, "PUT"));
713 ASSERT_SUCCESS(s_test_http_message_request_path(upload_part_message, &expected_create_path));
714 ASSERT_SUCCESS(s_test_http_headers_match(
715 allocator,
716 original_message,
717 upload_part_message,
718 g_s3_upload_part_excluded_headers,
719 g_s3_upload_part_excluded_headers_count,
720 header_exclude_exceptions,
721 AWS_ARRAY_SIZE(header_exclude_exceptions)));
722
723 ASSERT_SUCCESS(s_test_http_message_body_stream(allocator, upload_part_message, &part_buffer));
724
725 aws_string_destroy(upload_id);
726 aws_byte_buf_clean_up(&part_buffer);
727
728 aws_input_stream_destroy(aws_http_message_get_body_stream(upload_part_message));
729 aws_http_message_release(upload_part_message);
730 aws_http_message_release(original_message);
731
732 #undef STRINGIFY_HELPER
733 #undef STRINGIFY
734 #undef TEST_PATH
735 #undef UPLOAD_ID
736 #undef PART_NUMBER
737 #undef PART_NUMBER_STR
738 #undef EXPECTED_UPLOAD_PART_PATH
739
740 return 0;
741 }
742
743 struct complete_multipart_upload_xml_test_data {
744 struct aws_byte_cursor etag_value;
745 struct aws_byte_cursor part_number_value;
746 bool found_etag;
747 bool found_part_number;
748 };
749
s_complete_multipart_upload_traverse_xml_node(struct aws_xml_parser * parser,struct aws_xml_node * node,void * user_data)750 static bool s_complete_multipart_upload_traverse_xml_node(
751 struct aws_xml_parser *parser,
752 struct aws_xml_node *node,
753 void *user_data) {
754
755 const struct aws_byte_cursor complete_multipar_upload_tag_name =
756 AWS_BYTE_CUR_INIT_FROM_STRING_LITERAL("CompleteMultipartUpload");
757 const struct aws_byte_cursor part_tag_name = AWS_BYTE_CUR_INIT_FROM_STRING_LITERAL("Part");
758 const struct aws_byte_cursor etag_tag_name = AWS_BYTE_CUR_INIT_FROM_STRING_LITERAL("ETag");
759 const struct aws_byte_cursor part_number_tag_name = AWS_BYTE_CUR_INIT_FROM_STRING_LITERAL("PartNumber");
760
761 struct aws_byte_cursor node_name;
762 AWS_ZERO_STRUCT(node_name);
763
764 bool keep_traversing = false;
765 struct complete_multipart_upload_xml_test_data *test_data = user_data;
766
767 /* If we can't get the name of the node, stop traversing. */
768 if (aws_xml_node_get_name(node, &node_name)) {
769 /* Couldn't get the tag name, so nothing to do but stop traversing. */
770 } else if (aws_byte_cursor_eq(&node_name, &complete_multipar_upload_tag_name)) {
771 aws_xml_node_traverse(parser, node, s_complete_multipart_upload_traverse_xml_node, user_data);
772 } else if (aws_byte_cursor_eq(&node_name, &part_tag_name)) {
773 aws_xml_node_traverse(parser, node, s_complete_multipart_upload_traverse_xml_node, user_data);
774 } else if (aws_byte_cursor_eq(&node_name, &etag_tag_name)) {
775
776 struct aws_byte_cursor node_body;
777 AWS_ZERO_STRUCT(node_body);
778 if (aws_xml_node_as_body(parser, node, &node_body)) {
779 goto finish;
780 }
781
782 test_data->found_etag = aws_byte_cursor_eq(&node_body, &test_data->etag_value);
783 keep_traversing = true;
784 } else if (aws_byte_cursor_eq(&node_name, &part_number_tag_name)) {
785
786 struct aws_byte_cursor node_body;
787 AWS_ZERO_STRUCT(node_body);
788 aws_xml_node_as_body(parser, node, &node_body);
789
790 test_data->found_part_number = aws_byte_cursor_eq(&node_body, &test_data->part_number_value);
791 keep_traversing = true;
792 }
793
794 finish:
795 return keep_traversing;
796 }
797
AWS_TEST_CASE(test_s3_complete_multipart_message_new,s_test_s3_complete_multipart_message_new)798 AWS_TEST_CASE(test_s3_complete_multipart_message_new, s_test_s3_complete_multipart_message_new)
799 static int s_test_s3_complete_multipart_message_new(struct aws_allocator *allocator, void *ctx) {
800 (void)ctx;
801
802 #define TEST_PATH "/TestPath"
803 #define UPLOAD_ID "test_upload_id"
804 #define EXPECTED_UPLOAD_PART_PATH TEST_PATH "?uploadId=" UPLOAD_ID
805 #define ETAG_VALUE "etag_value"
806
807 struct aws_array_list etags;
808 ASSERT_SUCCESS(aws_array_list_init_dynamic(&etags, allocator, 1, sizeof(struct aws_string *)));
809 struct aws_string *etag = aws_string_new_from_c_str(allocator, ETAG_VALUE);
810 ASSERT_SUCCESS(aws_array_list_push_back(&etags, &etag));
811
812 const struct aws_byte_cursor header_exclude_exceptions[] = {
813 AWS_BYTE_CUR_INIT_FROM_STRING_LITERAL("Content-Length"),
814 };
815
816 struct aws_byte_cursor path = AWS_BYTE_CUR_INIT_FROM_STRING_LITERAL(TEST_PATH);
817 struct aws_byte_cursor expected_create_path = aws_byte_cursor_from_c_str(EXPECTED_UPLOAD_PART_PATH);
818
819 struct aws_http_message *original_message = NULL;
820 ASSERT_SUCCESS(s_create_put_object_message(allocator, &path, &original_message));
821 ASSERT_TRUE(original_message != NULL);
822
823 struct aws_string *upload_id = aws_string_new_from_c_str(allocator, UPLOAD_ID);
824
825 struct aws_byte_buf body_buffer;
826 aws_byte_buf_init(&body_buffer, allocator, 64);
827
828 struct aws_http_message *complete_multipart_message =
829 aws_s3_complete_multipart_message_new(allocator, original_message, &body_buffer, upload_id, &etags);
830
831 ASSERT_SUCCESS(s_test_http_message_request_method(complete_multipart_message, "POST"));
832 ASSERT_SUCCESS(s_test_http_message_request_path(complete_multipart_message, &expected_create_path));
833 ASSERT_SUCCESS(s_test_http_headers_match(
834 allocator,
835 original_message,
836 complete_multipart_message,
837 g_s3_complete_multipart_upload_excluded_headers,
838 g_s3_complete_multipart_upload_excluded_headers_count,
839 header_exclude_exceptions,
840 AWS_ARRAY_SIZE(header_exclude_exceptions)));
841
842 {
843 struct aws_xml_parser_options parser_options = {
844 .doc = aws_byte_cursor_from_buf(&body_buffer),
845 };
846
847 struct aws_xml_parser *parser = aws_xml_parser_new(allocator, &parser_options);
848
849 struct complete_multipart_upload_xml_test_data xml_user_data = {
850 .etag_value = AWS_BYTE_CUR_INIT_FROM_STRING_LITERAL(ETAG_VALUE),
851 .part_number_value = AWS_BYTE_CUR_INIT_FROM_STRING_LITERAL("1"),
852 .found_etag = false,
853 .found_part_number = false,
854 };
855
856 ASSERT_SUCCESS(
857 aws_xml_parser_parse(parser, s_complete_multipart_upload_traverse_xml_node, (void *)&xml_user_data));
858 aws_xml_parser_destroy(parser);
859
860 ASSERT_TRUE(xml_user_data.found_etag);
861 ASSERT_TRUE(xml_user_data.found_part_number);
862 }
863
864 aws_byte_buf_clean_up(&body_buffer);
865 aws_string_destroy(upload_id);
866
867 aws_input_stream_destroy(aws_http_message_get_body_stream(complete_multipart_message));
868 aws_http_message_release(complete_multipart_message);
869 aws_http_message_release(original_message);
870
871 aws_string_destroy(etag);
872 aws_array_list_clean_up(&etags);
873
874 #undef TEST_PATH
875 #undef UPLOAD_ID
876 #undef EXPECTED_UPLOAD_PART_PATH
877 #undef ETAG_VALUE
878
879 return 0;
880 }
881
AWS_TEST_CASE(test_s3_abort_multipart_upload_message_new,s_test_s3_abort_multipart_upload_message_newt)882 AWS_TEST_CASE(test_s3_abort_multipart_upload_message_new, s_test_s3_abort_multipart_upload_message_newt)
883 static int s_test_s3_abort_multipart_upload_message_newt(struct aws_allocator *allocator, void *ctx) {
884 (void)ctx;
885
886 #define TEST_PATH "/TestPath"
887 #define UPLOAD_ID "test_upload_id"
888 #define EXPECTED_UPLOAD_PART_PATH TEST_PATH "?uploadId=" UPLOAD_ID
889
890 struct aws_byte_cursor path = AWS_BYTE_CUR_INIT_FROM_STRING_LITERAL(TEST_PATH);
891 struct aws_byte_cursor expected_create_path = aws_byte_cursor_from_c_str(EXPECTED_UPLOAD_PART_PATH);
892
893 struct aws_http_message *original_message = NULL;
894 ASSERT_SUCCESS(s_create_put_object_message(allocator, &path, &original_message));
895 ASSERT_TRUE(original_message != NULL);
896
897 struct aws_string *upload_id = aws_string_new_from_c_str(allocator, UPLOAD_ID);
898
899 struct aws_http_message *abort_upload_message =
900 aws_s3_abort_multipart_upload_message_new(allocator, original_message, upload_id);
901 ASSERT_TRUE(abort_upload_message != NULL);
902
903 ASSERT_SUCCESS(s_test_http_message_request_method(abort_upload_message, "DELETE"));
904 ASSERT_SUCCESS(s_test_http_message_request_path(abort_upload_message, &expected_create_path));
905 ASSERT_SUCCESS(s_test_http_headers_match(
906 allocator,
907 original_message,
908 abort_upload_message,
909 g_s3_abort_multipart_upload_excluded_headers,
910 g_s3_abort_multipart_upload_excluded_headers_count,
911 NULL,
912 0));
913
914 aws_string_destroy(upload_id);
915
916 aws_http_message_release(abort_upload_message);
917 aws_http_message_release(original_message);
918
919 #undef TEST_PATH
920 #undef UPLOAD_ID
921 #undef EXPECTED_UPLOAD_PART_PATH
922
923 return 0;
924 }
925