Skip to content

Commit

Permalink
respect response length when looking for error message (#324)
Browse files Browse the repository at this point in the history
  • Loading branch information
Jamiras authored Mar 23, 2024
1 parent 58ec567 commit 28bf311
Show file tree
Hide file tree
Showing 3 changed files with 88 additions and 22 deletions.
67 changes: 45 additions & 22 deletions src/rapi/rc_api_common.c
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,24 @@ static void rc_json_skip_whitespace(rc_json_iterator_t* iterator)
++iterator->json;
}

static int rc_json_find_substring(rc_json_iterator_t* iterator, const char* substring)
{
const char first = *substring;
const size_t substring_len = strlen(substring);
const char* end = iterator->end - substring_len;

while (iterator->json <= end) {
if (*iterator->json == first) {
if (memcmp(iterator->json, substring, substring_len) == 0)
return 1;
}

++iterator->json;
}

return 0;
}

static int rc_json_find_closing_quote(rc_json_iterator_t* iterator)
{
while (iterator->json < iterator->end) {
Expand Down Expand Up @@ -237,43 +255,48 @@ int rc_json_get_next_object_field(rc_json_iterator_t* iterator, rc_json_field_t*
}

int rc_json_get_object_string_length(const char* json) {
const char* json_start = json;

rc_json_iterator_t iterator;
memset(&iterator, 0, sizeof(iterator));
iterator.json = json;
iterator.end = json + (1024 * 1024 * 1024); /* arbitrary 1GB limit on JSON response */

rc_json_parse_object(&iterator, NULL, 0, NULL);

return (int)(iterator.json - json_start);
if (iterator.json == json) /* not JSON */
return (int)strlen(json);

return (int)(iterator.json - json);
}

static int rc_json_extract_html_error(rc_api_response_t* response, const rc_api_server_response_t* server_response) {
const char* json = server_response->body;
const char* end = json;

const char* title_start = strstr(json, "<title>");
if (title_start) {
title_start += 7;
if (isdigit((int)*title_start)) {
const char* title_end = strstr(title_start + 7, "</title>");
if (title_end) {
response->error_message = rc_buffer_strncpy(&response->buffer, title_start, title_end - title_start);
response->succeeded = 0;
return RC_INVALID_JSON;
}
rc_json_iterator_t iterator;
memset(&iterator, 0, sizeof(iterator));
iterator.json = server_response->body;
iterator.end = server_response->body + server_response->body_length;

/* if the title contains an HTTP status code(i.e "404 Not Found"), return the title */
if (rc_json_find_substring(&iterator, "<title>")) {
const char* title_start = iterator.json + 7;
if (isdigit((int)*title_start) && rc_json_find_substring(&iterator, "</title>")) {
response->error_message = rc_buffer_strncpy(&response->buffer, title_start, iterator.json - title_start);
response->succeeded = 0;
return RC_INVALID_JSON;
}
}

while (*end && *end != '\n' && end - json < 200)
++end;
/* title not found, or did not start with an error code, return the first line of the response */
iterator.json = server_response->body;

while (iterator.json < iterator.end && *iterator.json != '\n' &&
iterator.json - server_response->body < 200) {
++iterator.json;
}

if (end > json && end[-1] == '\r')
--end;
if (iterator.json > server_response->body && iterator.json[-1] == '\r')
--iterator.json;

if (end > json)
response->error_message = rc_buffer_strncpy(&response->buffer, json, end - json);
if (iterator.json > server_response->body)
response->error_message = rc_buffer_strncpy(&response->buffer, server_response->body, iterator.json - server_response->body);

response->succeeded = 0;
return RC_INVALID_JSON;
Expand Down
25 changes: 25 additions & 0 deletions test/rapi/test_rc_api_common.c
Original file line number Diff line number Diff line change
Expand Up @@ -90,6 +90,30 @@ static void test_json_parse_response_non_json() {
ASSERT_NUM_EQUALS(response.succeeded, 0);
}

static void test_json_parse_response_non_json_bounded() {
int result;
rc_api_server_response_t server_response;
rc_api_response_t response;
const char* error_message = "This is an error.\r\n<title>Should not be seen</title>";
rc_json_field_t fields[] = {
RC_JSON_NEW_FIELD("Success"),
RC_JSON_NEW_FIELD("Error"),
RC_JSON_NEW_FIELD("Test")
};
rc_buffer_init(&response.buffer);

memset(&server_response, 0, sizeof(server_response));
server_response.body = error_message;
server_response.body_length = 16; /* "This is an error" (no period, newline, etc) */

result = rc_json_parse_server_response(&response, &server_response, fields, sizeof(fields) / sizeof(fields[0]));
ASSERT_NUM_EQUALS(result, RC_INVALID_JSON);

ASSERT_PTR_NOT_NULL(response.error_message);
ASSERT_STR_EQUALS(response.error_message, "This is an error");
ASSERT_NUM_EQUALS(response.succeeded, 0);
}

static void test_json_parse_response_error_from_server() {
int result;
rc_api_server_response_t server_response;
Expand Down Expand Up @@ -766,6 +790,7 @@ void test_rapi_common(void) {
TEST_PARAMS2(test_json_parse_response_field, "{ \"Other\" : 1, \"Test\" : 2 }", "2"); /* preceding field */
TEST_PARAMS2(test_json_parse_response_field, "{ \"Test\" : 1, \"Other\" : 2 }", "1"); /* trailing field */
TEST(test_json_parse_response_non_json);
TEST(test_json_parse_response_non_json_bounded);
TEST(test_json_parse_response_error_from_server);
TEST(test_json_parse_response_incorrect_size);

Expand Down
18 changes: 18 additions & 0 deletions test/rapi/test_rc_api_runtime.c
Original file line number Diff line number Diff line change
Expand Up @@ -951,6 +951,23 @@ static void test_process_award_achievement_response_503_fancy() {
rc_api_destroy_award_achievement_response(&award_achievement_response);
}

static void test_process_award_achievement_response_522_simple() {
rc_api_award_achievement_response_t award_achievement_response;
const char* server_response = "error code: 522";

memset(&award_achievement_response, 0, sizeof(award_achievement_response));

ASSERT_NUM_EQUALS(rc_api_process_award_achievement_response(&award_achievement_response, server_response), RC_INVALID_JSON);
ASSERT_NUM_EQUALS(award_achievement_response.response.succeeded, 0);
ASSERT_STR_EQUALS(award_achievement_response.response.error_message, "error code: 522");
ASSERT_UNUM_EQUALS(award_achievement_response.new_player_score, 0);
ASSERT_UNUM_EQUALS(award_achievement_response.new_player_score_softcore, 0);
ASSERT_UNUM_EQUALS(award_achievement_response.awarded_achievement_id, 0);
ASSERT_UNUM_EQUALS(award_achievement_response.achievements_remaining, 0);

rc_api_destroy_award_achievement_response(&award_achievement_response);
}

static void test_init_submit_lboard_entry_request() {
rc_api_submit_lboard_entry_request_t submit_lboard_entry_request;
rc_api_request_t request;
Expand Down Expand Up @@ -1164,6 +1181,7 @@ void test_rapi_runtime(void) {
TEST(test_process_award_achievement_response_429);
TEST(test_process_award_achievement_response_429_json);
TEST(test_process_award_achievement_response_503_fancy);
TEST(test_process_award_achievement_response_522_simple);

/* submitlbentry */
TEST(test_init_submit_lboard_entry_request);
Expand Down

0 comments on commit 28bf311

Please sign in to comment.