|
16 | 16 | #include <aws/http/request_response.h>
|
17 | 17 |
|
18 | 18 | #include <aws/common/string.h>
|
19 |
| -#include <aws/testing/aws_test_harness.h> |
| 19 | +#include <aws/testing/aws_test_allocators.h> |
20 | 20 |
|
21 | 21 | #define TEST_CASE(NAME) \
|
22 | 22 | AWS_TEST_CASE(NAME, s_test_##NAME); \
|
@@ -132,6 +132,11 @@ TEST_CASE(request_add_headers) {
|
132 | 132 | ASSERT_SUCCESS(aws_http_request_get_header(request, &get, 0));
|
133 | 133 | ASSERT_SUCCESS(s_check_header_eq(get, "Host", "example.com"));
|
134 | 134 |
|
| 135 | + /* Overwrite header and check values */ |
| 136 | + ASSERT_SUCCESS(aws_http_request_set_header(request, s_make_header("Connection", "Upgrade"), 0)); |
| 137 | + ASSERT_SUCCESS(aws_http_request_get_header(request, &get, 0)); |
| 138 | + ASSERT_SUCCESS(s_check_header_eq(get, "Connection", "Upgrade")); |
| 139 | + |
135 | 140 | aws_http_request_destroy(request);
|
136 | 141 | return AWS_OP_SUCCESS;
|
137 | 142 | }
|
@@ -194,3 +199,78 @@ TEST_CASE(request_erase_headers) {
|
194 | 199 | aws_http_request_destroy(request);
|
195 | 200 | return AWS_OP_SUCCESS;
|
196 | 201 | }
|
| 202 | + |
| 203 | +/* Do every operation that involves allocating some memory */ |
| 204 | +int s_request_handles_oom_attempt(struct aws_http_request *request) { |
| 205 | + ASSERT_NOT_NULL(request); |
| 206 | + |
| 207 | + /* Set, and then overwrite, method and path */ |
| 208 | + ASSERT_SUCCESS(aws_http_request_set_method(request, aws_byte_cursor_from_c_str("POST"))); |
| 209 | + ASSERT_SUCCESS(aws_http_request_set_path(request, aws_byte_cursor_from_c_str("/"))); |
| 210 | + ASSERT_SUCCESS(aws_http_request_set_method(request, aws_byte_cursor_from_c_str("GET"))); |
| 211 | + ASSERT_SUCCESS(aws_http_request_set_path(request, aws_byte_cursor_from_c_str("/chat"))); |
| 212 | + |
| 213 | + /* Add a lot of headers, enough to force the underlying array-list to expand. |
| 214 | + * (just loop through the list above again and again) */ |
| 215 | + char name_buf[16]; |
| 216 | + char value_buf[16]; |
| 217 | + for (size_t i = 0; i < 128; ++i) { |
| 218 | + snprintf(name_buf, sizeof(name_buf), "Name-%zu", i); |
| 219 | + snprintf(name_buf, sizeof(name_buf), "Value-%zu", i); |
| 220 | + struct aws_http_header header = {.name = aws_byte_cursor_from_c_str(name_buf), |
| 221 | + .value = aws_byte_cursor_from_c_str(value_buf)}; |
| 222 | + ASSERT_SUCCESS(aws_http_request_add_header(request, header)); |
| 223 | + } |
| 224 | + |
| 225 | + /* Overwrite all the headers */ |
| 226 | + for (size_t i = 0; i < 128; ++i) { |
| 227 | + snprintf(name_buf, sizeof(name_buf), "New-Name-%zu", i); |
| 228 | + snprintf(name_buf, sizeof(name_buf), "New-Value-%zu", i); |
| 229 | + struct aws_http_header header = {.name = aws_byte_cursor_from_c_str(name_buf), |
| 230 | + .value = aws_byte_cursor_from_c_str(value_buf)}; |
| 231 | + ASSERT_SUCCESS(aws_http_request_set_header(request, header, i)); |
| 232 | + } |
| 233 | + |
| 234 | + return AWS_OP_SUCCESS; |
| 235 | +} |
| 236 | + |
| 237 | +TEST_CASE(request_handles_oom) { |
| 238 | + (void)ctx; |
| 239 | + struct aws_allocator timebomb_alloc; |
| 240 | + ASSERT_SUCCESS(aws_timebomb_allocator_init(&timebomb_alloc, allocator, SIZE_MAX)); |
| 241 | + |
| 242 | + bool test_succeeded = false; |
| 243 | + size_t allocations_until_failure; |
| 244 | + for (allocations_until_failure = 0; allocations_until_failure < 10000; ++allocations_until_failure) { |
| 245 | + /* Allow one more allocation each time we loop. */ |
| 246 | + aws_timebomb_allocator_reset_countdown(&timebomb_alloc, allocations_until_failure); |
| 247 | + |
| 248 | + /* Create a request, then do a bunch of stuff with it. */ |
| 249 | + struct aws_http_request *request = aws_http_request_new(&timebomb_alloc); |
| 250 | + int err = 0; |
| 251 | + if (request) { |
| 252 | + err = s_request_handles_oom_attempt(request); |
| 253 | + if (err) { |
| 254 | + /* Ensure failure was due to OOM */ |
| 255 | + ASSERT_INT_EQUALS(AWS_ERROR_OOM, aws_last_error()); |
| 256 | + } else { |
| 257 | + test_succeeded = true; |
| 258 | + } |
| 259 | + |
| 260 | + aws_http_request_destroy(request); |
| 261 | + } else { |
| 262 | + /* Ensure failure was due to OOM */ |
| 263 | + ASSERT_INT_EQUALS(AWS_ERROR_OOM, aws_last_error()); |
| 264 | + } |
| 265 | + |
| 266 | + if (test_succeeded) { |
| 267 | + break; |
| 268 | + } |
| 269 | + } |
| 270 | + |
| 271 | + ASSERT_TRUE(test_succeeded); |
| 272 | + ASSERT_TRUE(allocations_until_failure > 2); /* Assert that this did fail a few times */ |
| 273 | + |
| 274 | + aws_timebomb_allocator_clean_up(&timebomb_alloc); |
| 275 | + return AWS_OP_SUCCESS; |
| 276 | +} |
0 commit comments