Update http-parser subtree:

Source: https://github.com/nodejs/http-parser/commits/master
Commit: fd65b0fbbdb405425a14d0e49f5366667550b1c2
Merge commit '404d58d77c3ecbea68e0bd4fa1e7ff4b7c000fc5' into parser
This commit is contained in:
Vinnie Falco
2016-03-04 12:27:24 -05:00
parent e3414bf042
commit c4e9a464e7
13 changed files with 1505 additions and 395 deletions

View File

@@ -39,6 +39,7 @@
#define MAX_HEADERS 13
#define MAX_ELEMENT_SIZE 2048
#define MAX_CHUNKS 16
#define MIN(a,b) ((a) < (b) ? (a) : (b))
@@ -65,6 +66,10 @@ struct message {
char headers [MAX_HEADERS][2][MAX_ELEMENT_SIZE];
int should_keep_alive;
int num_chunks;
int num_chunks_complete;
int chunk_lengths[MAX_CHUNKS];
const char *upgrade; // upgraded body
unsigned short http_major;
@@ -301,6 +306,8 @@ const struct message requests[] =
{ { "Transfer-Encoding" , "chunked" }
}
,.body= "all your base are belong to us"
,.num_chunks_complete= 2
,.chunk_lengths= { 0x1e }
}
#define TWO_CHUNKS_MULT_ZERO_END 9
@@ -327,6 +334,8 @@ const struct message requests[] =
{ { "Transfer-Encoding", "chunked" }
}
,.body= "hello world"
,.num_chunks_complete= 3
,.chunk_lengths= { 5, 6 }
}
#define CHUNKED_W_TRAILING_HEADERS 10
@@ -357,6 +366,8 @@ const struct message requests[] =
, { "Content-Type", "text/plain" }
}
,.body= "hello world"
,.num_chunks_complete= 3
,.chunk_lengths= { 5, 6 }
}
#define CHUNKED_W_BULLSHIT_AFTER_LENGTH 11
@@ -383,6 +394,8 @@ const struct message requests[] =
{ { "Transfer-Encoding", "chunked" }
}
,.body= "hello world"
,.num_chunks_complete= 3
,.chunk_lengths= { 5, 6 }
}
#define WITH_QUOTES 12
@@ -608,8 +621,14 @@ const struct message requests[] =
" mno \r\n"
"\t \tqrs\r\n"
"Line2: \t line2\t\r\n"
"Line3:\r\n"
" line3\r\n"
"Line4: \r\n"
" \r\n"
"Connection:\r\n"
" close\r\n"
"\r\n"
,.should_keep_alive= TRUE
,.should_keep_alive= FALSE
,.message_complete_on_eof= FALSE
,.http_major= 1
,.http_minor= 1
@@ -618,9 +637,12 @@ const struct message requests[] =
,.fragment= ""
,.request_path= "/"
,.request_url= "/"
,.num_headers= 2
,.headers= { { "Line1", "abcdefghijklmno qrs" }
,.num_headers= 5
,.headers= { { "Line1", "abc\tdef ghi\t\tjkl mno \t \tqrs" }
, { "Line2", "line2\t" }
, { "Line3", "line3" }
, { "Line4", "" }
, { "Connection", "close" },
}
,.body= ""
}
@@ -904,6 +926,232 @@ const struct message requests[] =
,.body= ""
}
#define LINE_FOLDING_IN_HEADER_WITH_LF 34
, {.name= "line folding in header value"
,.type= HTTP_REQUEST
,.raw= "GET / HTTP/1.1\n"
"Line1: abc\n"
"\tdef\n"
" ghi\n"
"\t\tjkl\n"
" mno \n"
"\t \tqrs\n"
"Line2: \t line2\t\n"
"Line3:\n"
" line3\n"
"Line4: \n"
" \n"
"Connection:\n"
" close\n"
"\n"
,.should_keep_alive= FALSE
,.message_complete_on_eof= FALSE
,.http_major= 1
,.http_minor= 1
,.method= HTTP_GET
,.query_string= ""
,.fragment= ""
,.request_path= "/"
,.request_url= "/"
,.num_headers= 5
,.headers= { { "Line1", "abc\tdef ghi\t\tjkl mno \t \tqrs" }
, { "Line2", "line2\t" }
, { "Line3", "line3" }
, { "Line4", "" }
, { "Connection", "close" },
}
,.body= ""
}
#define CONNECTION_MULTI 35
, {.name = "multiple connection header values with folding"
,.type= HTTP_REQUEST
,.raw= "GET /demo HTTP/1.1\r\n"
"Host: example.com\r\n"
"Connection: Something,\r\n"
" Upgrade, ,Keep-Alive\r\n"
"Sec-WebSocket-Key2: 12998 5 Y3 1 .P00\r\n"
"Sec-WebSocket-Protocol: sample\r\n"
"Upgrade: WebSocket\r\n"
"Sec-WebSocket-Key1: 4 @1 46546xW%0l 1 5\r\n"
"Origin: http://example.com\r\n"
"\r\n"
"Hot diggity dogg"
,.should_keep_alive= TRUE
,.message_complete_on_eof= FALSE
,.http_major= 1
,.http_minor= 1
,.method= HTTP_GET
,.query_string= ""
,.fragment= ""
,.request_path= "/demo"
,.request_url= "/demo"
,.num_headers= 7
,.upgrade="Hot diggity dogg"
,.headers= { { "Host", "example.com" }
, { "Connection", "Something, Upgrade, ,Keep-Alive" }
, { "Sec-WebSocket-Key2", "12998 5 Y3 1 .P00" }
, { "Sec-WebSocket-Protocol", "sample" }
, { "Upgrade", "WebSocket" }
, { "Sec-WebSocket-Key1", "4 @1 46546xW%0l 1 5" }
, { "Origin", "http://example.com" }
}
,.body= ""
}
#define CONNECTION_MULTI_LWS 36
, {.name = "multiple connection header values with folding and lws"
,.type= HTTP_REQUEST
,.raw= "GET /demo HTTP/1.1\r\n"
"Connection: keep-alive, upgrade\r\n"
"Upgrade: WebSocket\r\n"
"\r\n"
"Hot diggity dogg"
,.should_keep_alive= TRUE
,.message_complete_on_eof= FALSE
,.http_major= 1
,.http_minor= 1
,.method= HTTP_GET
,.query_string= ""
,.fragment= ""
,.request_path= "/demo"
,.request_url= "/demo"
,.num_headers= 2
,.upgrade="Hot diggity dogg"
,.headers= { { "Connection", "keep-alive, upgrade" }
, { "Upgrade", "WebSocket" }
}
,.body= ""
}
#define CONNECTION_MULTI_LWS_CRLF 37
, {.name = "multiple connection header values with folding and lws"
,.type= HTTP_REQUEST
,.raw= "GET /demo HTTP/1.1\r\n"
"Connection: keep-alive, \r\n upgrade\r\n"
"Upgrade: WebSocket\r\n"
"\r\n"
"Hot diggity dogg"
,.should_keep_alive= TRUE
,.message_complete_on_eof= FALSE
,.http_major= 1
,.http_minor= 1
,.method= HTTP_GET
,.query_string= ""
,.fragment= ""
,.request_path= "/demo"
,.request_url= "/demo"
,.num_headers= 2
,.upgrade="Hot diggity dogg"
,.headers= { { "Connection", "keep-alive, upgrade" }
, { "Upgrade", "WebSocket" }
}
,.body= ""
}
#define UPGRADE_POST_REQUEST 38
, {.name = "upgrade post request"
,.type= HTTP_REQUEST
,.raw= "POST /demo HTTP/1.1\r\n"
"Host: example.com\r\n"
"Connection: Upgrade\r\n"
"Upgrade: HTTP/2.0\r\n"
"Content-Length: 15\r\n"
"\r\n"
"sweet post body"
"Hot diggity dogg"
,.should_keep_alive= TRUE
,.message_complete_on_eof= FALSE
,.http_major= 1
,.http_minor= 1
,.method= HTTP_POST
,.request_path= "/demo"
,.request_url= "/demo"
,.num_headers= 4
,.upgrade="Hot diggity dogg"
,.headers= { { "Host", "example.com" }
, { "Connection", "Upgrade" }
, { "Upgrade", "HTTP/2.0" }
, { "Content-Length", "15" }
}
,.body= "sweet post body"
}
#define CONNECT_WITH_BODY_REQUEST 39
, {.name = "connect with body request"
,.type= HTTP_REQUEST
,.raw= "CONNECT foo.bar.com:443 HTTP/1.0\r\n"
"User-agent: Mozilla/1.1N\r\n"
"Proxy-authorization: basic aGVsbG86d29ybGQ=\r\n"
"Content-Length: 10\r\n"
"\r\n"
"blarfcicle"
,.should_keep_alive= FALSE
,.message_complete_on_eof= FALSE
,.http_major= 1
,.http_minor= 0
,.method= HTTP_CONNECT
,.request_url= "foo.bar.com:443"
,.num_headers= 3
,.upgrade="blarfcicle"
,.headers= { { "User-agent", "Mozilla/1.1N" }
, { "Proxy-authorization", "basic aGVsbG86d29ybGQ=" }
, { "Content-Length", "10" }
}
,.body= ""
}
/* Examples from the Internet draft for LINK/UNLINK methods:
* https://tools.ietf.org/id/draft-snell-link-method-01.html#rfc.section.5
*/
#define LINK_REQUEST 40
, {.name = "link request"
,.type= HTTP_REQUEST
,.raw= "LINK /images/my_dog.jpg HTTP/1.1\r\n"
"Host: example.com\r\n"
"Link: <http://example.com/profiles/joe>; rel=\"tag\"\r\n"
"Link: <http://example.com/profiles/sally>; rel=\"tag\"\r\n"
"\r\n"
,.should_keep_alive= TRUE
,.message_complete_on_eof= FALSE
,.http_major= 1
,.http_minor= 1
,.method= HTTP_LINK
,.request_path= "/images/my_dog.jpg"
,.request_url= "/images/my_dog.jpg"
,.query_string= ""
,.fragment= ""
,.num_headers= 3
,.headers= { { "Host", "example.com" }
, { "Link", "<http://example.com/profiles/joe>; rel=\"tag\"" }
, { "Link", "<http://example.com/profiles/sally>; rel=\"tag\"" }
}
,.body= ""
}
#define UNLINK_REQUEST 41
, {.name = "link request"
,.type= HTTP_REQUEST
,.raw= "UNLINK /images/my_dog.jpg HTTP/1.1\r\n"
"Host: example.com\r\n"
"Link: <http://example.com/profiles/sally>; rel=\"tag\"\r\n"
"\r\n"
,.should_keep_alive= TRUE
,.message_complete_on_eof= FALSE
,.http_major= 1
,.http_minor= 1
,.method= HTTP_UNLINK
,.request_path= "/images/my_dog.jpg"
,.request_url= "/images/my_dog.jpg"
,.query_string= ""
,.fragment= ""
,.num_headers= 2
,.headers= { { "Host", "example.com" }
, { "Link", "<http://example.com/profiles/sally>; rel=\"tag\"" }
}
,.body= ""
}
, {.name= NULL } /* sentinel */
};
@@ -1064,7 +1312,8 @@ const struct message responses[] =
,.body =
"This is the data in the first chunk\r\n"
"and this is the second one\r\n"
,.num_chunks_complete= 3
,.chunk_lengths= { 0x25, 0x1c }
}
#define NO_CARRIAGE_RET 5
@@ -1218,6 +1467,8 @@ const struct message responses[] =
, { "Connection", "close" }
}
,.body= ""
,.num_chunks_complete= 1
,.chunk_lengths= {}
}
#define NON_ASCII_IN_STATUS_LINE 10
@@ -1400,6 +1651,7 @@ const struct message responses[] =
}
,.body_size= 0
,.body= ""
,.num_chunks_complete= 1
}
#if !HTTP_PARSER_STRICT
@@ -1473,6 +1725,8 @@ const struct message responses[] =
, { "Transfer-Encoding", "chunked" }
}
,.body= "\n"
,.num_chunks_complete= 2
,.chunk_lengths= { 1 }
}
#define EMPTY_REASON_PHRASE_AFTER_SPACE 20
@@ -1708,6 +1962,35 @@ response_status_cb (http_parser *p, const char *buf, size_t len)
return 0;
}
int
chunk_header_cb (http_parser *p)
{
assert(p == parser);
int chunk_idx = messages[num_messages].num_chunks;
messages[num_messages].num_chunks++;
if (chunk_idx < MAX_CHUNKS) {
messages[num_messages].chunk_lengths[chunk_idx] = p->content_length;
}
return 0;
}
int
chunk_complete_cb (http_parser *p)
{
assert(p == parser);
/* Here we want to verify that each chunk_header_cb is matched by a
* chunk_complete_cb, so not only should the total number of calls to
* both callbacks be the same, but they also should be interleaved
* properly */
assert(messages[num_messages].num_chunks ==
messages[num_messages].num_chunks_complete + 1);
messages[num_messages].num_chunks_complete++;
return 0;
}
/* These dontcall_* callbacks exist so that we can verify that when we're
* paused, no additional callbacks are invoked */
int
@@ -1776,6 +2059,23 @@ dontcall_response_status_cb (http_parser *p, const char *buf, size_t len)
abort();
}
int
dontcall_chunk_header_cb (http_parser *p)
{
if (p) { } // gcc
fprintf(stderr, "\n\n*** on_chunk_header() called on paused parser ***\n\n");
exit(1);
}
int
dontcall_chunk_complete_cb (http_parser *p)
{
if (p) { } // gcc
fprintf(stderr, "\n\n*** on_chunk_complete() "
"called on paused parser ***\n\n");
exit(1);
}
static http_parser_settings settings_dontcall =
{.on_message_begin = dontcall_message_begin_cb
,.on_header_field = dontcall_header_field_cb
@@ -1785,6 +2085,8 @@ static http_parser_settings settings_dontcall =
,.on_body = dontcall_body_cb
,.on_headers_complete = dontcall_headers_complete_cb
,.on_message_complete = dontcall_message_complete_cb
,.on_chunk_header = dontcall_chunk_header_cb
,.on_chunk_complete = dontcall_chunk_complete_cb
};
/* These pause_* callbacks always pause the parser and just invoke the regular
@@ -1855,6 +2157,22 @@ pause_response_status_cb (http_parser *p, const char *buf, size_t len)
return response_status_cb(p, buf, len);
}
int
pause_chunk_header_cb (http_parser *p)
{
http_parser_pause(p, 1);
*current_pause_parser = settings_dontcall;
return chunk_header_cb(p);
}
int
pause_chunk_complete_cb (http_parser *p)
{
http_parser_pause(p, 1);
*current_pause_parser = settings_dontcall;
return chunk_complete_cb(p);
}
static http_parser_settings settings_pause =
{.on_message_begin = pause_message_begin_cb
,.on_header_field = pause_header_field_cb
@@ -1864,6 +2182,8 @@ static http_parser_settings settings_pause =
,.on_body = pause_body_cb
,.on_headers_complete = pause_headers_complete_cb
,.on_message_complete = pause_message_complete_cb
,.on_chunk_header = pause_chunk_header_cb
,.on_chunk_complete = pause_chunk_complete_cb
};
static http_parser_settings settings =
@@ -1875,6 +2195,8 @@ static http_parser_settings settings =
,.on_body = body_cb
,.on_headers_complete = headers_complete_cb
,.on_message_complete = message_complete_cb
,.on_chunk_header = chunk_header_cb
,.on_chunk_complete = chunk_complete_cb
};
static http_parser_settings settings_count_body =
@@ -1886,6 +2208,8 @@ static http_parser_settings settings_count_body =
,.on_body = count_body_cb
,.on_headers_complete = headers_complete_cb
,.on_message_complete = message_complete_cb
,.on_chunk_header = chunk_header_cb
,.on_chunk_complete = chunk_complete_cb
};
static http_parser_settings settings_null =
@@ -1897,6 +2221,8 @@ static http_parser_settings settings_null =
,.on_body = 0
,.on_headers_complete = 0
,.on_message_complete = 0
,.on_chunk_header = 0
,.on_chunk_complete = 0
};
void
@@ -2065,6 +2391,12 @@ message_eq (int index, const struct message *expected)
MESSAGE_CHECK_STR_EQ(expected, m, body);
}
assert(m->num_chunks == m->num_chunks_complete);
MESSAGE_CHECK_NUM_EQ(expected, m, num_chunks_complete);
for (i = 0; i < m->num_chunks && i < MAX_CHUNKS; i++) {
MESSAGE_CHECK_NUM_EQ(expected, m, chunk_lengths[i]);
}
MESSAGE_CHECK_NUM_EQ(expected, m, num_headers);
int r;
@@ -2112,7 +2444,7 @@ upgrade_message_fix(char *body, const size_t nread, const size_t nmsgs, ...) {
va_list ap;
size_t i;
size_t off = 0;
va_start(ap, nmsgs);
for (i = 0; i < nmsgs; i++) {
@@ -2161,7 +2493,6 @@ print_error (const char *raw, size_t error_location)
break;
case '\n':
char_len = 2;
fprintf(stderr, "\\n\n");
if (this_line) goto print;
@@ -2639,6 +2970,59 @@ const struct url_test url_tests[] =
,.rv=1 /* s_dead */
}
, {.name="ipv6 address with Zone ID"
,.url="http://[fe80::a%25eth0]/"
,.is_connect=0
,.u=
{.field_set= (1<<UF_SCHEMA) | (1<<UF_HOST) | (1<<UF_PATH)
,.port=0
,.field_data=
{{ 0, 4 } /* UF_SCHEMA */
,{ 8, 14 } /* UF_HOST */
,{ 0, 0 } /* UF_PORT */
,{ 23, 1 } /* UF_PATH */
,{ 0, 0 } /* UF_QUERY */
,{ 0, 0 } /* UF_FRAGMENT */
,{ 0, 0 } /* UF_USERINFO */
}
}
,.rv=0
}
, {.name="ipv6 address with Zone ID, but '%' is not percent-encoded"
,.url="http://[fe80::a%eth0]/"
,.is_connect=0
,.u=
{.field_set= (1<<UF_SCHEMA) | (1<<UF_HOST) | (1<<UF_PATH)
,.port=0
,.field_data=
{{ 0, 4 } /* UF_SCHEMA */
,{ 8, 12 } /* UF_HOST */
,{ 0, 0 } /* UF_PORT */
,{ 21, 1 } /* UF_PATH */
,{ 0, 0 } /* UF_QUERY */
,{ 0, 0 } /* UF_FRAGMENT */
,{ 0, 0 } /* UF_USERINFO */
}
}
,.rv=0
}
, {.name="ipv6 address ending with '%'"
,.url="http://[fe80::a%]/"
,.rv=1 /* s_dead */
}
, {.name="ipv6 address with Zone ID including bad character"
,.url="http://[fe80::a%$HOME]/"
,.rv=1 /* s_dead */
}
, {.name="just ipv6 Zone ID"
,.url="http://[%eth0]/"
,.rv=1 /* s_dead */
}
#if HTTP_PARSER_STRICT
, {.name="tab in URL"
@@ -2779,7 +3163,7 @@ test_message (const struct message *message)
if (msg1len) {
read = parse(msg1, msg1len);
if (message->upgrade && parser->upgrade) {
if (message->upgrade && parser->upgrade && num_messages > 0) {
messages[num_messages - 1].upgrade = msg1 + read;
goto test;
}
@@ -2864,15 +3248,11 @@ test_simple (const char *buf, enum http_errno err_expected)
{
parser_init(HTTP_REQUEST);
size_t parsed;
int pass;
enum http_errno err;
parsed = parse(buf, strlen(buf));
pass = (parsed == strlen(buf));
parse(buf, strlen(buf));
err = HTTP_PARSER_ERRNO(parser);
parsed = parse(NULL, 0);
pass &= (parsed == 0);
parse(NULL, 0);
parser_free();
@@ -2890,6 +3270,155 @@ test_simple (const char *buf, enum http_errno err_expected)
}
}
void
test_invalid_header_content (int req, const char* str)
{
http_parser parser;
http_parser_init(&parser, req ? HTTP_REQUEST : HTTP_RESPONSE);
size_t parsed;
const char *buf;
buf = req ?
"GET / HTTP/1.1\r\n" :
"HTTP/1.1 200 OK\r\n";
parsed = http_parser_execute(&parser, &settings_null, buf, strlen(buf));
assert(parsed == strlen(buf));
buf = str;
size_t buflen = strlen(buf);
parsed = http_parser_execute(&parser, &settings_null, buf, buflen);
if (parsed != buflen) {
assert(HTTP_PARSER_ERRNO(&parser) == HPE_INVALID_HEADER_TOKEN);
return;
}
fprintf(stderr,
"\n*** Error expected but none in invalid header content test ***\n");
abort();
}
void
test_invalid_header_field_content_error (int req)
{
test_invalid_header_content(req, "Foo: F\01ailure");
test_invalid_header_content(req, "Foo: B\02ar");
}
void
test_invalid_header_field (int req, const char* str)
{
http_parser parser;
http_parser_init(&parser, req ? HTTP_REQUEST : HTTP_RESPONSE);
size_t parsed;
const char *buf;
buf = req ?
"GET / HTTP/1.1\r\n" :
"HTTP/1.1 200 OK\r\n";
parsed = http_parser_execute(&parser, &settings_null, buf, strlen(buf));
assert(parsed == strlen(buf));
buf = str;
size_t buflen = strlen(buf);
parsed = http_parser_execute(&parser, &settings_null, buf, buflen);
if (parsed != buflen) {
assert(HTTP_PARSER_ERRNO(&parser) == HPE_INVALID_HEADER_TOKEN);
return;
}
fprintf(stderr,
"\n*** Error expected but none in invalid header token test ***\n");
abort();
}
void
test_invalid_header_field_token_error (int req)
{
test_invalid_header_field(req, "Fo@: Failure");
test_invalid_header_field(req, "Foo\01\test: Bar");
}
void
test_double_content_length_error (int req)
{
http_parser parser;
http_parser_init(&parser, req ? HTTP_REQUEST : HTTP_RESPONSE);
size_t parsed;
const char *buf;
buf = req ?
"GET / HTTP/1.1\r\n" :
"HTTP/1.1 200 OK\r\n";
parsed = http_parser_execute(&parser, &settings_null, buf, strlen(buf));
assert(parsed == strlen(buf));
buf = "Content-Length: 0\r\nContent-Length: 1\r\n\r\n";
size_t buflen = strlen(buf);
parsed = http_parser_execute(&parser, &settings_null, buf, buflen);
if (parsed != buflen) {
assert(HTTP_PARSER_ERRNO(&parser) == HPE_UNEXPECTED_CONTENT_LENGTH);
return;
}
fprintf(stderr,
"\n*** Error expected but none in double content-length test ***\n");
abort();
}
void
test_chunked_content_length_error (int req)
{
http_parser parser;
http_parser_init(&parser, req ? HTTP_REQUEST : HTTP_RESPONSE);
size_t parsed;
const char *buf;
buf = req ?
"GET / HTTP/1.1\r\n" :
"HTTP/1.1 200 OK\r\n";
parsed = http_parser_execute(&parser, &settings_null, buf, strlen(buf));
assert(parsed == strlen(buf));
buf = "Transfer-Encoding: chunked\r\nContent-Length: 1\r\n\r\n";
size_t buflen = strlen(buf);
parsed = http_parser_execute(&parser, &settings_null, buf, buflen);
if (parsed != buflen) {
assert(HTTP_PARSER_ERRNO(&parser) == HPE_UNEXPECTED_CONTENT_LENGTH);
return;
}
fprintf(stderr,
"\n*** Error expected but none in chunked content-length test ***\n");
abort();
}
void
test_header_cr_no_lf_error (int req)
{
http_parser parser;
http_parser_init(&parser, req ? HTTP_REQUEST : HTTP_RESPONSE);
size_t parsed;
const char *buf;
buf = req ?
"GET / HTTP/1.1\r\n" :
"HTTP/1.1 200 OK\r\n";
parsed = http_parser_execute(&parser, &settings_null, buf, strlen(buf));
assert(parsed == strlen(buf));
buf = "Foo: 1\rBar: 1\r\n\r\n";
size_t buflen = strlen(buf);
parsed = http_parser_execute(&parser, &settings_null, buf, buflen);
if (parsed != buflen) {
assert(HTTP_PARSER_ERRNO(&parser) == HPE_LF_EXPECTED);
return;
}
fprintf(stderr,
"\n*** Error expected but none in header whitespace test ***\n");
abort();
}
void
test_header_overflow_error (int req)
{
@@ -2918,6 +3447,22 @@ test_header_overflow_error (int req)
abort();
}
void
test_header_nread_value ()
{
http_parser parser;
http_parser_init(&parser, HTTP_REQUEST);
size_t parsed;
const char *buf;
buf = "GET / HTTP/1.1\r\nheader: value\nhdr: value\r\n";
parsed = http_parser_execute(&parser, &settings_null, buf, strlen(buf));
assert(parsed == strlen(buf));
assert(parser.nread == strlen(buf));
}
static void
test_content_length_overflow (const char *buf, size_t buflen, int expect_ok)
{
@@ -3284,6 +3829,9 @@ main (void)
test_parse_url();
test_method_str();
//// NREAD
test_header_nread_value();
//// OVERFLOW CONDITIONS
test_header_overflow_error(HTTP_REQUEST);
@@ -3297,6 +3845,18 @@ main (void)
test_header_content_length_overflow_error();
test_chunk_content_length_overflow_error();
//// HEADER FIELD CONDITIONS
test_double_content_length_error(HTTP_REQUEST);
test_chunked_content_length_error(HTTP_REQUEST);
test_header_cr_no_lf_error(HTTP_REQUEST);
test_invalid_header_field_token_error(HTTP_REQUEST);
test_invalid_header_field_content_error(HTTP_REQUEST);
test_double_content_length_error(HTTP_RESPONSE);
test_chunked_content_length_error(HTTP_RESPONSE);
test_header_cr_no_lf_error(HTTP_RESPONSE);
test_invalid_header_field_token_error(HTTP_RESPONSE);
test_invalid_header_field_content_error(HTTP_RESPONSE);
//// RESPONSES
for (i = 0; i < response_count; i++) {
@@ -3343,7 +3903,11 @@ main (void)
, { "Content-Type", "text/plain" }
}
,.body_size= 31337*1024
,.num_chunks_complete= 31338
};
for (i = 0; i < MAX_CHUNKS; i++) {
large_chunked.chunk_lengths[i] = 1024;
}
test_message_count_body(&large_chunked);
free(msg);
}
@@ -3392,7 +3956,12 @@ main (void)
"MOVE",
"PROPFIND",
"PROPPATCH",
"SEARCH",
"UNLOCK",
"BIND",
"REBIND",
"UNBIND",
"ACL",
"REPORT",
"MKACTIVITY",
"CHECKOUT",
@@ -3402,6 +3971,10 @@ main (void)
"SUBSCRIBE",
"UNSUBSCRIBE",
"PATCH",
"PURGE",
"MKCALENDAR",
"LINK",
"UNLINK",
0 };
const char **this_method;
for (this_method = all_methods; *this_method; this_method++) {
@@ -3430,6 +4003,13 @@ main (void)
test_simple(buf, HPE_INVALID_METHOD);
}
// illegal header field name line folding
test_simple("GET / HTTP/1.1\r\n"
"name\r\n"
" : value\r\n"
"\r\n",
HPE_INVALID_HEADER_TOKEN);
const char *dumbfuck2 =
"GET / HTTP/1.1\r\n"
"X-SSL-Bullshit: -----BEGIN CERTIFICATE-----\r\n"
@@ -3467,6 +4047,22 @@ main (void)
"\r\n";
test_simple(dumbfuck2, HPE_OK);
const char *corrupted_connection =
"GET / HTTP/1.1\r\n"
"Host: www.example.com\r\n"
"Connection\r\033\065\325eep-Alive\r\n"
"Accept-Encoding: gzip\r\n"
"\r\n";
test_simple(corrupted_connection, HPE_INVALID_HEADER_TOKEN);
const char *corrupted_header_name =
"GET / HTTP/1.1\r\n"
"Host: www.example.com\r\n"
"X-Some-Header\r\033\065\325eep-Alive\r\n"
"Accept-Encoding: gzip\r\n"
"\r\n";
test_simple(corrupted_header_name, HPE_INVALID_HEADER_TOKEN);
#if 0
// NOTE(Wed Nov 18 11:57:27 CET 2009) this seems okay. we just read body
// until EOF.