mirror of
https://gitlab.com/openconnect/ocserv.git
synced 2026-02-10 00:37:00 +08:00
Updated the included http-parser
This commit is contained in:
@@ -249,6 +249,7 @@ enum state
|
||||
, s_res_http_minor
|
||||
, s_res_first_status_code
|
||||
, s_res_status_code
|
||||
, s_res_status_start
|
||||
, s_res_status
|
||||
, s_res_line_almost_done
|
||||
|
||||
@@ -582,6 +583,7 @@ size_t http_parser_execute (http_parser *parser,
|
||||
const char *header_value_mark = 0;
|
||||
const char *url_mark = 0;
|
||||
const char *body_mark = 0;
|
||||
const char *status_mark = 0;
|
||||
|
||||
/* We're in an error state. Don't bother doing anything. */
|
||||
if (HTTP_PARSER_ERRNO(parser) != HPE_OK) {
|
||||
@@ -628,6 +630,9 @@ size_t http_parser_execute (http_parser *parser,
|
||||
case s_req_fragment:
|
||||
url_mark = data;
|
||||
break;
|
||||
case s_res_status:
|
||||
status_mark = data;
|
||||
break;
|
||||
}
|
||||
|
||||
for (p=data; p != data + len; p++) {
|
||||
@@ -635,7 +640,17 @@ size_t http_parser_execute (http_parser *parser,
|
||||
|
||||
if (PARSING_HEADER(parser->state)) {
|
||||
++parser->nread;
|
||||
/* Buffer overflow attack */
|
||||
/* Don't allow the total size of the HTTP headers (including the status
|
||||
* line) to exceed HTTP_MAX_HEADER_SIZE. This check is here to protect
|
||||
* embedders against denial-of-service attacks where the attacker feeds
|
||||
* us a never-ending header that the embedder keeps buffering.
|
||||
*
|
||||
* This check is arguably the responsibility of embedders but we're doing
|
||||
* it on the embedder's behalf because most won't bother and this way we
|
||||
* make the web a little safer. HTTP_MAX_HEADER_SIZE is still far bigger
|
||||
* than any reasonable request or response so this should never affect
|
||||
* day-to-day operation.
|
||||
*/
|
||||
if (parser->nread > HTTP_MAX_HEADER_SIZE) {
|
||||
SET_ERRNO(HPE_HEADER_OVERFLOW);
|
||||
goto error;
|
||||
@@ -824,7 +839,7 @@ size_t http_parser_execute (http_parser *parser,
|
||||
if (!IS_NUM(ch)) {
|
||||
switch (ch) {
|
||||
case ' ':
|
||||
parser->state = s_res_status;
|
||||
parser->state = s_res_status_start;
|
||||
break;
|
||||
case CR:
|
||||
parser->state = s_res_line_almost_done;
|
||||
@@ -850,9 +865,8 @@ size_t http_parser_execute (http_parser *parser,
|
||||
break;
|
||||
}
|
||||
|
||||
case s_res_status:
|
||||
/* the human readable status. e.g. "NOT FOUND"
|
||||
* we are not humans so just ignore this */
|
||||
case s_res_status_start:
|
||||
{
|
||||
if (ch == CR) {
|
||||
parser->state = s_res_line_almost_done;
|
||||
break;
|
||||
@@ -862,12 +876,31 @@ size_t http_parser_execute (http_parser *parser,
|
||||
parser->state = s_header_field_start;
|
||||
break;
|
||||
}
|
||||
|
||||
MARK(status);
|
||||
parser->state = s_res_status;
|
||||
parser->index = 0;
|
||||
break;
|
||||
}
|
||||
|
||||
case s_res_status:
|
||||
if (ch == CR) {
|
||||
parser->state = s_res_line_almost_done;
|
||||
CALLBACK_DATA(status);
|
||||
break;
|
||||
}
|
||||
|
||||
if (ch == LF) {
|
||||
parser->state = s_header_field_start;
|
||||
CALLBACK_DATA(status);
|
||||
break;
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
case s_res_line_almost_done:
|
||||
STRICT_CHECK(ch != LF);
|
||||
parser->state = s_header_field_start;
|
||||
CALLBACK_NOTIFY(status_complete);
|
||||
break;
|
||||
|
||||
case s_start_req:
|
||||
@@ -930,6 +963,7 @@ size_t http_parser_execute (http_parser *parser,
|
||||
} else if (parser->index == 2 && ch == 'P') {
|
||||
parser->method = HTTP_COPY;
|
||||
} else {
|
||||
SET_ERRNO(HPE_INVALID_METHOD);
|
||||
goto error;
|
||||
}
|
||||
} else if (parser->method == HTTP_MKCOL) {
|
||||
@@ -942,12 +976,14 @@ size_t http_parser_execute (http_parser *parser,
|
||||
} else if (parser->index == 2 && ch == 'A') {
|
||||
parser->method = HTTP_MKACTIVITY;
|
||||
} else {
|
||||
SET_ERRNO(HPE_INVALID_METHOD);
|
||||
goto error;
|
||||
}
|
||||
} else if (parser->method == HTTP_SUBSCRIBE) {
|
||||
if (parser->index == 1 && ch == 'E') {
|
||||
parser->method = HTTP_SEARCH;
|
||||
} else {
|
||||
SET_ERRNO(HPE_INVALID_METHOD);
|
||||
goto error;
|
||||
}
|
||||
} else if (parser->index == 1 && parser->method == HTTP_POST) {
|
||||
@@ -958,13 +994,27 @@ size_t http_parser_execute (http_parser *parser,
|
||||
} else if (ch == 'A') {
|
||||
parser->method = HTTP_PATCH;
|
||||
} else {
|
||||
SET_ERRNO(HPE_INVALID_METHOD);
|
||||
goto error;
|
||||
}
|
||||
} else if (parser->index == 2) {
|
||||
if (parser->method == HTTP_PUT) {
|
||||
if (ch == 'R') parser->method = HTTP_PURGE;
|
||||
if (ch == 'R') {
|
||||
parser->method = HTTP_PURGE;
|
||||
} else {
|
||||
SET_ERRNO(HPE_INVALID_METHOD);
|
||||
goto error;
|
||||
}
|
||||
} else if (parser->method == HTTP_UNLOCK) {
|
||||
if (ch == 'S') parser->method = HTTP_UNSUBSCRIBE;
|
||||
if (ch == 'S') {
|
||||
parser->method = HTTP_UNSUBSCRIBE;
|
||||
} else {
|
||||
SET_ERRNO(HPE_INVALID_METHOD);
|
||||
goto error;
|
||||
}
|
||||
} else {
|
||||
SET_ERRNO(HPE_INVALID_METHOD);
|
||||
goto error;
|
||||
}
|
||||
} else if (parser->index == 4 && parser->method == HTTP_PROPFIND && ch == 'P') {
|
||||
parser->method = HTTP_PROPPATCH;
|
||||
@@ -1460,8 +1510,8 @@ size_t http_parser_execute (http_parser *parser,
|
||||
t *= 10;
|
||||
t += ch - '0';
|
||||
|
||||
/* Overflow? */
|
||||
if (t < parser->content_length || t == ULLONG_MAX) {
|
||||
/* Overflow? Test against a conservative limit for simplicity. */
|
||||
if ((ULLONG_MAX - 10) / 10 < parser->content_length) {
|
||||
SET_ERRNO(HPE_INVALID_CONTENT_LENGTH);
|
||||
goto error;
|
||||
}
|
||||
@@ -1733,8 +1783,8 @@ size_t http_parser_execute (http_parser *parser,
|
||||
t *= 16;
|
||||
t += unhex_val;
|
||||
|
||||
/* Overflow? */
|
||||
if (t < parser->content_length || t == ULLONG_MAX) {
|
||||
/* Overflow? Test against a conservative limit for simplicity. */
|
||||
if ((ULLONG_MAX - 16) / 16 < parser->content_length) {
|
||||
SET_ERRNO(HPE_INVALID_CONTENT_LENGTH);
|
||||
goto error;
|
||||
}
|
||||
@@ -1828,12 +1878,14 @@ size_t http_parser_execute (http_parser *parser,
|
||||
assert(((header_field_mark ? 1 : 0) +
|
||||
(header_value_mark ? 1 : 0) +
|
||||
(url_mark ? 1 : 0) +
|
||||
(body_mark ? 1 : 0)) <= 1);
|
||||
(body_mark ? 1 : 0) +
|
||||
(status_mark ? 1 : 0)) <= 1);
|
||||
|
||||
CALLBACK_DATA_NOADVANCE(header_field);
|
||||
CALLBACK_DATA_NOADVANCE(header_value);
|
||||
CALLBACK_DATA_NOADVANCE(url);
|
||||
CALLBACK_DATA_NOADVANCE(body);
|
||||
CALLBACK_DATA_NOADVANCE(status);
|
||||
|
||||
return len;
|
||||
|
||||
@@ -2174,3 +2226,10 @@ int
|
||||
http_body_is_final(const struct http_parser *parser) {
|
||||
return parser->state == s_message_done;
|
||||
}
|
||||
|
||||
unsigned long
|
||||
http_parser_version(void) {
|
||||
return HTTP_PARSER_VERSION_MAJOR * 0x10000 |
|
||||
HTTP_PARSER_VERSION_MINOR * 0x00100 |
|
||||
HTTP_PARSER_VERSION_PATCH * 0x00001;
|
||||
}
|
||||
|
||||
@@ -24,8 +24,10 @@
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/* Also update SONAME in the Makefile whenever you change these. */
|
||||
#define HTTP_PARSER_VERSION_MAJOR 2
|
||||
#define HTTP_PARSER_VERSION_MINOR 0
|
||||
#define HTTP_PARSER_VERSION_MINOR 2
|
||||
#define HTTP_PARSER_VERSION_PATCH 1
|
||||
|
||||
#include <sys/types.h>
|
||||
#if defined(_WIN32) && !defined(__MINGW32__) && (!defined(_MSC_VER) || _MSC_VER<1600)
|
||||
@@ -141,13 +143,13 @@ enum flags
|
||||
\
|
||||
/* Callback-related errors */ \
|
||||
XX(CB_message_begin, "the on_message_begin callback failed") \
|
||||
XX(CB_status_complete, "the on_status_complete callback failed") \
|
||||
XX(CB_url, "the on_url callback failed") \
|
||||
XX(CB_header_field, "the on_header_field callback failed") \
|
||||
XX(CB_header_value, "the on_header_value callback failed") \
|
||||
XX(CB_headers_complete, "the on_headers_complete callback failed") \
|
||||
XX(CB_body, "the on_body callback failed") \
|
||||
XX(CB_message_complete, "the on_message_complete callback failed") \
|
||||
XX(CB_status, "the on_status callback failed") \
|
||||
\
|
||||
/* Parsing-related errors */ \
|
||||
XX(INVALID_EOF_STATE, "stream ended at an unexpected time") \
|
||||
@@ -191,11 +193,11 @@ enum http_errno {
|
||||
|
||||
struct http_parser {
|
||||
/** PRIVATE **/
|
||||
unsigned char type : 2; /* enum http_parser_type */
|
||||
unsigned char flags : 6; /* F_* values from 'flags' enum; semi-public */
|
||||
unsigned char state; /* enum state from http_parser.c */
|
||||
unsigned char header_state; /* enum header_state from http_parser.c */
|
||||
unsigned char index; /* index into current matcher */
|
||||
unsigned int type : 2; /* enum http_parser_type */
|
||||
unsigned int flags : 6; /* F_* values from 'flags' enum; semi-public */
|
||||
unsigned int state : 8; /* enum state from http_parser.c */
|
||||
unsigned int header_state : 8; /* enum header_state from http_parser.c */
|
||||
unsigned int index : 8; /* index into current matcher */
|
||||
|
||||
uint32_t nread; /* # bytes read in various scenarios */
|
||||
uint64_t content_length; /* # bytes in body (0 if no Content-Length header) */
|
||||
@@ -203,16 +205,16 @@ struct http_parser {
|
||||
/** READ-ONLY **/
|
||||
unsigned short http_major;
|
||||
unsigned short http_minor;
|
||||
unsigned short status_code; /* responses only */
|
||||
unsigned char method; /* requests only */
|
||||
unsigned char http_errno : 7;
|
||||
unsigned int status_code : 16; /* responses only */
|
||||
unsigned int method : 8; /* requests only */
|
||||
unsigned int http_errno : 7;
|
||||
|
||||
/* 1 = Upgrade header was present and the parser has exited because of that.
|
||||
* 0 = No upgrade header present.
|
||||
* Should be checked when http_parser_execute() returns in addition to
|
||||
* error checking.
|
||||
*/
|
||||
unsigned char upgrade : 1;
|
||||
unsigned int upgrade : 1;
|
||||
|
||||
/** PUBLIC **/
|
||||
void *data; /* A pointer to get hook to the "connection" or "socket" object */
|
||||
@@ -222,7 +224,7 @@ struct http_parser {
|
||||
struct http_parser_settings {
|
||||
http_cb on_message_begin;
|
||||
http_data_cb on_url;
|
||||
http_cb on_status_complete;
|
||||
http_data_cb on_status;
|
||||
http_data_cb on_header_field;
|
||||
http_data_cb on_header_value;
|
||||
http_cb on_headers_complete;
|
||||
@@ -261,6 +263,18 @@ struct http_parser_url {
|
||||
};
|
||||
|
||||
|
||||
/* Returns the library version. Bits 16-23 contain the major version number,
|
||||
* bits 8-15 the minor version number and bits 0-7 the patch level.
|
||||
* Usage example:
|
||||
*
|
||||
* unsigned long version = http_parser_version();
|
||||
* unsigned major = (version >> 16) & 255;
|
||||
* unsigned minor = (version >> 8) & 255;
|
||||
* unsigned patch = version & 255;
|
||||
* printf("http_parser v%u.%u.%u\n", major, minor, version);
|
||||
*/
|
||||
unsigned long http_parser_version(void);
|
||||
|
||||
void http_parser_init(http_parser *parser, enum http_parser_type type);
|
||||
|
||||
|
||||
|
||||
Reference in New Issue
Block a user