Skip to content

Commit 9797b1d

Browse files
authored
test aws_http_request OOM errors (#93)
1 parent f541d13 commit 9797b1d

File tree

2 files changed

+82
-1
lines changed

2 files changed

+82
-1
lines changed

tests/CMakeLists.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ add_test_case(request_method)
1111
add_test_case(request_path)
1212
add_test_case(request_add_headers)
1313
add_test_case(request_erase_headers)
14+
add_test_case(request_handles_oom)
1415

1516
add_test_case(h1_test_get_request)
1617
add_test_case(h1_test_request_bad_version)

tests/test_request.c

Lines changed: 81 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@
1616
#include <aws/http/request_response.h>
1717

1818
#include <aws/common/string.h>
19-
#include <aws/testing/aws_test_harness.h>
19+
#include <aws/testing/aws_test_allocators.h>
2020

2121
#define TEST_CASE(NAME) \
2222
AWS_TEST_CASE(NAME, s_test_##NAME); \
@@ -132,6 +132,11 @@ TEST_CASE(request_add_headers) {
132132
ASSERT_SUCCESS(aws_http_request_get_header(request, &get, 0));
133133
ASSERT_SUCCESS(s_check_header_eq(get, "Host", "example.com"));
134134

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+
135140
aws_http_request_destroy(request);
136141
return AWS_OP_SUCCESS;
137142
}
@@ -194,3 +199,78 @@ TEST_CASE(request_erase_headers) {
194199
aws_http_request_destroy(request);
195200
return AWS_OP_SUCCESS;
196201
}
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

Comments
 (0)