diff options
Diffstat (limited to 'src/third_party/kms-message/src/kms_response_parser.c')
-rw-r--r-- | src/third_party/kms-message/src/kms_response_parser.c | 373 |
1 files changed, 0 insertions, 373 deletions
diff --git a/src/third_party/kms-message/src/kms_response_parser.c b/src/third_party/kms-message/src/kms_response_parser.c deleted file mode 100644 index 6f0c0487864..00000000000 --- a/src/third_party/kms-message/src/kms_response_parser.c +++ /dev/null @@ -1,373 +0,0 @@ -#include "kms_message/kms_response_parser.h" -#include "kms_message_private.h" - -#include <errno.h> -#include <limits.h> -#include <stdio.h> -#include <stdlib.h> - -#include "hexlify.h" - -/* destroys the members of parser, but not the parser itself. */ -static void -_parser_destroy (kms_response_parser_t *parser) -{ - kms_request_str_destroy (parser->raw_response); - parser->raw_response = NULL; - parser->content_length = -1; - kms_response_destroy (parser->response); - parser->response = NULL; -} - -/* initializes the members of parser. */ -static void -_parser_init (kms_response_parser_t *parser) -{ - parser->raw_response = kms_request_str_new (); - parser->content_length = -1; - parser->response = calloc (1, sizeof (kms_response_t)); - KMS_ASSERT (parser->response); - parser->response->headers = kms_kv_list_new (); - parser->state = PARSING_STATUS_LINE; - parser->start = 0; - parser->failed = false; - parser->chunk_size = 0; - parser->transfer_encoding_chunked = false; -} - -kms_response_parser_t * -kms_response_parser_new (void) -{ - kms_response_parser_t *parser = malloc (sizeof (kms_response_parser_t)); - KMS_ASSERT (parser); - - _parser_init (parser); - return parser; -} - -int -kms_response_parser_wants_bytes (kms_response_parser_t *parser, int32_t max) -{ - switch (parser->state) { - case PARSING_DONE: - return 0; - case PARSING_STATUS_LINE: - case PARSING_HEADER: - return max; - case PARSING_CHUNK_LENGTH: - return max; - case PARSING_CHUNK: - /* add 2 for trailing \r\n */ - return (parser->chunk_size + 2) - - ((int) parser->raw_response->len - parser->start); - case PARSING_BODY: - KMS_ASSERT (parser->content_length != -1); - return parser->content_length - - ((int) parser->raw_response->len - parser->start); - } - return -1; -} - -static bool -_parse_int (const char *str, int *result) -{ - char *endptr = NULL; - int64_t long_result; - - errno = 0; - long_result = strtol (str, &endptr, 10); - if (endptr == str) { - /* No digits were parsed. Consider this an error */ - return false; - } - if (endptr != NULL && *endptr != '\0') { - /* endptr points to the first invalid character. */ - return false; - } - if (errno == EINVAL || errno == ERANGE) { - return false; - } - if (long_result > INT32_MAX || long_result < INT32_MIN) { - return false; - } - *result = (int) long_result; - - return true; -} - -/* parse an int from a substring inside of a string. */ -static bool -_parse_int_from_view (const char *str, int start, int end, int *result) -{ - char *num_str = malloc (end - start + 1); - KMS_ASSERT (num_str); - - bool ret; - - strncpy (num_str, str + start, end - start); - num_str[end - start] = '\0'; - ret = _parse_int (num_str, result); - free (num_str); - return ret; -} - -static bool -_parse_hex_from_view (const char *str, int len, int *result) -{ - *result = unhexlify (str, len); - if (*result < 0) { - return false; - } - return true; -} - -/* returns true if char is "linear white space". This *ignores* the folding case - * of CRLF followed by WSP. See https://stackoverflow.com/a/21072806/774658 */ -static bool -_is_lwsp (char c) -{ - return c == ' ' || c == 0x09 /* HTAB */; -} - -/* parse a header line or status line. */ -static kms_response_parser_state_t -_parse_line (kms_response_parser_t *parser, int end) -{ - int i = parser->start; - const char *raw = parser->raw_response->str; - kms_response_t *response = parser->response; - - if (parser->state == PARSING_STATUS_LINE) { - /* Status-Line = HTTP-Version SP Status-Code SP Reason-Phrase CRLF */ - int j; - int status; - - if (strncmp (raw + i, "HTTP/1.1 ", 9) != 0) { - KMS_ERROR (parser, "Could not parse HTTP-Version."); - return PARSING_DONE; - } - i += 9; - - for (j = i; j < end; j++) { - if (raw[j] == ' ') - break; - } - - if (!_parse_int_from_view (raw, i, j, &status)) { - KMS_ERROR (parser, "Could not parse Status-Code."); - return PARSING_DONE; - } - - response->status = status; - - /* ignore the Reason-Phrase. */ - return PARSING_HEADER; - } else if (parser->state == PARSING_HEADER) { - /* Treating a header as: - * message-header = field-name ":" [ field-value ] CRLF - * This is not completely correct, and does not take folding into acct. - * See https://tools.ietf.org/html/rfc822#section-3.1 - */ - int j; - kms_request_str_t *key; - kms_request_str_t *val; - - if (i == end) { - /* empty line, this signals the start of the body. */ - if (parser->transfer_encoding_chunked) { - return PARSING_CHUNK_LENGTH; - } - return PARSING_BODY; - } - - for (j = i; j < end; j++) { - if (raw[j] == ':') - break; - } - - if (j == end) { - KMS_ERROR (parser, "Could not parse header, no colon found."); - return PARSING_DONE; - } - - key = kms_request_str_new_from_chars (raw + i, j - i); - - i = j + 1; - /* remove leading and trailing whitespace from the value. */ - for (j = i; j < end; j++) { - if (!_is_lwsp (raw[j])) - break; - } - i = j; - - /* find the end of the header by backtracking. */ - for (j = end; j > i; j--) { - if (!_is_lwsp (raw[j])) - break; - } - - if (i == j) { - val = kms_request_str_new (); - } else { - val = kms_request_str_new_from_chars (raw + i, j - i); - } - - kms_kv_list_add (response->headers, key, val); - - /* if we have *not* read the Content-Length yet, check. */ - if (parser->content_length == -1 && - strcmp (key->str, "Content-Length") == 0) { - if (!_parse_int (val->str, &parser->content_length)) { - KMS_ERROR (parser, "Could not parse Content-Length header."); - kms_request_str_destroy (key); - kms_request_str_destroy (val); - return PARSING_DONE; - } - } - - if (0 == strcmp (key->str, "Transfer-Encoding")) { - if (0 == strcmp (val->str, "chunked")) { - parser->transfer_encoding_chunked = true; - } else { - KMS_ERROR (parser, "Unsupported Transfer-Encoding: %s", val->str); - kms_request_str_destroy (key); - kms_request_str_destroy (val); - return PARSING_DONE; - } - } - kms_request_str_destroy (key); - kms_request_str_destroy (val); - return PARSING_HEADER; - } else if (parser->state == PARSING_CHUNK_LENGTH) { - int result = 0; - - if (!_parse_hex_from_view (raw + i, end - i, &result)) { - KMS_ERROR (parser, "Failed to parse hex chunk length."); - return PARSING_DONE; - } - parser->chunk_size = result; - return PARSING_CHUNK; - } - return PARSING_DONE; -} - -bool -kms_response_parser_feed (kms_response_parser_t *parser, - uint8_t *buf, - uint32_t len) -{ - kms_request_str_t *raw = parser->raw_response; - int curr, body_read, chunk_read; - - curr = (int) raw->len; - kms_request_str_append_chars (raw, (char *) buf, len); - /* process the new data appended. */ - while (curr < (int) raw->len) { - switch (parser->state) { - case PARSING_STATUS_LINE: - case PARSING_HEADER: - case PARSING_CHUNK_LENGTH: - /* find the next \r\n. */ - if (curr && strncmp (raw->str + (curr - 1), "\r\n", 2) == 0) { - parser->state = _parse_line (parser, curr - 1); - parser->start = curr + 1; - } - curr++; - - if (parser->state == PARSING_BODY && parser->content_length <= 0) { - /* Ok, no Content-Length header, or explicitly 0, so empty body */ - parser->response->body = kms_request_str_new (); - parser->state = PARSING_DONE; - } - break; - case PARSING_BODY: - body_read = (int) raw->len - parser->start; - - if (parser->content_length == -1 || - body_read > parser->content_length) { - KMS_ERROR (parser, "Unexpected: exceeded content length"); - return false; - } - - /* check if we have the entire body. */ - if (body_read == parser->content_length) { - parser->response->body = kms_request_str_new_from_chars ( - raw->str + parser->start, parser->content_length); - parser->state = PARSING_DONE; - } - - curr = (int) raw->len; - break; - case PARSING_CHUNK: - chunk_read = (int) raw->len - parser->start; - /* check if we've read the full chunk and the trailing \r\n */ - if (chunk_read >= parser->chunk_size + 2) { - if (!parser->response->body) { - parser->response->body = kms_request_str_new (); - } - kms_request_str_append_chars (parser->response->body, - raw->str + parser->start, - parser->chunk_size); - curr = parser->start + parser->chunk_size + 2; - parser->start = curr; - if (parser->chunk_size == 0) { - /* last chunk. */ - parser->state = PARSING_DONE; - } else { - parser->state = PARSING_CHUNK_LENGTH; - } - } else { - curr = (int) raw->len; - } - break; - case PARSING_DONE: - KMS_ERROR (parser, "Unexpected extra HTTP content"); - return false; - } - } - - if (parser->failed) { - return false; - } - return true; -} - -/* steals the response from the parser. */ -kms_response_t * -kms_response_parser_get_response (kms_response_parser_t *parser) -{ - kms_response_t *response = parser->response; - - parser->response = NULL; - /* reset the parser. */ - _parser_destroy (parser); - _parser_init (parser); - return response; -} - -int -kms_response_parser_status (kms_response_parser_t *parser) -{ - if (!parser || !(parser->response)) { - return 0; - } - - return parser->response->status; -} - -const char * -kms_response_parser_error (kms_response_parser_t *parser) -{ - if (!parser) { - return NULL; - } - - return parser->error; -} - -void -kms_response_parser_destroy (kms_response_parser_t *parser) -{ - _parser_destroy (parser); - free (parser); -} |