|
|
|
@ -27,7 +27,11 @@
|
|
|
|
|
#include <ctype.h>
|
|
|
|
|
#include <stdlib.h>
|
|
|
|
|
#include <string.h>
|
|
|
|
|
#include <limits.h>
|
|
|
|
|
|
|
|
|
|
#ifndef ULLONG_MAX
|
|
|
|
|
# define ULLONG_MAX ((uint64_t) -1) /* 2^64-1 */
|
|
|
|
|
#endif
|
|
|
|
|
|
|
|
|
|
#ifndef MIN
|
|
|
|
|
# define MIN(a,b) ((a) < (b) ? (a) : (b))
|
|
|
|
@ -648,7 +652,7 @@ size_t http_parser_execute (http_parser *parser,
|
|
|
|
|
if (ch == CR || ch == LF)
|
|
|
|
|
break;
|
|
|
|
|
parser->flags = 0;
|
|
|
|
|
parser->content_length = -1;
|
|
|
|
|
parser->content_length = ULLONG_MAX;
|
|
|
|
|
|
|
|
|
|
if (ch == 'H') {
|
|
|
|
|
parser->state = s_res_or_resp_H;
|
|
|
|
@ -683,7 +687,7 @@ size_t http_parser_execute (http_parser *parser,
|
|
|
|
|
case s_start_res:
|
|
|
|
|
{
|
|
|
|
|
parser->flags = 0;
|
|
|
|
|
parser->content_length = -1;
|
|
|
|
|
parser->content_length = ULLONG_MAX;
|
|
|
|
|
|
|
|
|
|
switch (ch) {
|
|
|
|
|
case 'H':
|
|
|
|
@ -862,7 +866,7 @@ size_t http_parser_execute (http_parser *parser,
|
|
|
|
|
if (ch == CR || ch == LF)
|
|
|
|
|
break;
|
|
|
|
|
parser->flags = 0;
|
|
|
|
|
parser->content_length = -1;
|
|
|
|
|
parser->content_length = ULLONG_MAX;
|
|
|
|
|
|
|
|
|
|
if (!IS_ALPHA(ch)) {
|
|
|
|
|
SET_ERRNO(HPE_INVALID_METHOD);
|
|
|
|
@ -1427,15 +1431,29 @@ size_t http_parser_execute (http_parser *parser,
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case h_content_length:
|
|
|
|
|
{
|
|
|
|
|
uint64_t t;
|
|
|
|
|
|
|
|
|
|
if (ch == ' ') break;
|
|
|
|
|
|
|
|
|
|
if (!IS_NUM(ch)) {
|
|
|
|
|
SET_ERRNO(HPE_INVALID_CONTENT_LENGTH);
|
|
|
|
|
goto error;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
parser->content_length *= 10;
|
|
|
|
|
parser->content_length += ch - '0';
|
|
|
|
|
t = parser->content_length;
|
|
|
|
|
t *= 10;
|
|
|
|
|
t += ch - '0';
|
|
|
|
|
|
|
|
|
|
/* Overflow? */
|
|
|
|
|
if (t < parser->content_length || t == ULLONG_MAX) {
|
|
|
|
|
SET_ERRNO(HPE_INVALID_CONTENT_LENGTH);
|
|
|
|
|
goto error;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
parser->content_length = t;
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Transfer-Encoding: chunked */
|
|
|
|
|
case h_matching_transfer_encoding_chunked:
|
|
|
|
@ -1590,7 +1608,7 @@ size_t http_parser_execute (http_parser *parser,
|
|
|
|
|
/* Content-Length header given but zero: Content-Length: 0\r\n */
|
|
|
|
|
parser->state = NEW_MESSAGE();
|
|
|
|
|
CALLBACK_NOTIFY(message_complete);
|
|
|
|
|
} else if (parser->content_length > 0) {
|
|
|
|
|
} else if (parser->content_length != ULLONG_MAX) {
|
|
|
|
|
/* Content-Length header given and non-zero */
|
|
|
|
|
parser->state = s_body_identity;
|
|
|
|
|
} else {
|
|
|
|
@ -1611,9 +1629,11 @@ size_t http_parser_execute (http_parser *parser,
|
|
|
|
|
|
|
|
|
|
case s_body_identity:
|
|
|
|
|
{
|
|
|
|
|
uint64_t to_read = MIN(parser->content_length, (data + len) - p);
|
|
|
|
|
uint64_t to_read = MIN(parser->content_length,
|
|
|
|
|
(uint64_t) ((data + len) - p));
|
|
|
|
|
|
|
|
|
|
assert(parser->content_length > 0);
|
|
|
|
|
assert(parser->content_length != 0
|
|
|
|
|
&& parser->content_length != ULLONG_MAX);
|
|
|
|
|
|
|
|
|
|
/* The difference between advancing content_length and p is because
|
|
|
|
|
* the latter will automaticaly advance on the next loop iteration.
|
|
|
|
@ -1673,6 +1693,8 @@ size_t http_parser_execute (http_parser *parser,
|
|
|
|
|
|
|
|
|
|
case s_chunk_size:
|
|
|
|
|
{
|
|
|
|
|
uint64_t t;
|
|
|
|
|
|
|
|
|
|
assert(parser->flags & F_CHUNKED);
|
|
|
|
|
|
|
|
|
|
if (ch == CR) {
|
|
|
|
@ -1692,8 +1714,17 @@ size_t http_parser_execute (http_parser *parser,
|
|
|
|
|
goto error;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
parser->content_length *= 16;
|
|
|
|
|
parser->content_length += unhex_val;
|
|
|
|
|
t = parser->content_length;
|
|
|
|
|
t *= 16;
|
|
|
|
|
t += unhex_val;
|
|
|
|
|
|
|
|
|
|
/* Overflow? */
|
|
|
|
|
if (t < parser->content_length || t == ULLONG_MAX) {
|
|
|
|
|
SET_ERRNO(HPE_INVALID_CONTENT_LENGTH);
|
|
|
|
|
goto error;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
parser->content_length = t;
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
@ -1726,10 +1757,12 @@ size_t http_parser_execute (http_parser *parser,
|
|
|
|
|
|
|
|
|
|
case s_chunk_data:
|
|
|
|
|
{
|
|
|
|
|
uint64_t to_read = MIN(parser->content_length, (data + len) - p);
|
|
|
|
|
uint64_t to_read = MIN(parser->content_length,
|
|
|
|
|
(uint64_t) ((data + len) - p));
|
|
|
|
|
|
|
|
|
|
assert(parser->flags & F_CHUNKED);
|
|
|
|
|
assert(parser->content_length > 0);
|
|
|
|
|
assert(parser->content_length != 0
|
|
|
|
|
&& parser->content_length != ULLONG_MAX);
|
|
|
|
|
|
|
|
|
|
/* See the explanation in s_body_identity for why the content
|
|
|
|
|
* length and data pointers are managed this way.
|
|
|
|
@ -1814,7 +1847,7 @@ http_message_needs_eof (http_parser *parser)
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if ((parser->flags & F_CHUNKED) || parser->content_length >= 0) {
|
|
|
|
|
if ((parser->flags & F_CHUNKED) || parser->content_length != ULLONG_MAX) {
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|