|
|
@ -71,6 +71,7 @@ static int currently_parsing_eof;
|
|
|
|
|
|
|
|
|
|
|
|
static struct message messages[5];
|
|
|
|
static struct message messages[5];
|
|
|
|
static int num_messages;
|
|
|
|
static int num_messages;
|
|
|
|
|
|
|
|
static http_parser_settings *current_pause_parser;
|
|
|
|
|
|
|
|
|
|
|
|
/* * R E Q U E S T S * */
|
|
|
|
/* * R E Q U E S T S * */
|
|
|
|
const struct message requests[] =
|
|
|
|
const struct message requests[] =
|
|
|
@ -1290,6 +1291,146 @@ message_complete_cb (http_parser *p)
|
|
|
|
return 0;
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/* These dontcall_* callbacks exist so that we can verify that when we're
|
|
|
|
|
|
|
|
* paused, no additional callbacks are invoked */
|
|
|
|
|
|
|
|
int
|
|
|
|
|
|
|
|
dontcall_message_begin_cb (http_parser *p)
|
|
|
|
|
|
|
|
{
|
|
|
|
|
|
|
|
if (p) { } // gcc
|
|
|
|
|
|
|
|
fprintf(stderr, "\n\n*** on_message_begin() called on paused parser ***\n\n");
|
|
|
|
|
|
|
|
exit(1);
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
int
|
|
|
|
|
|
|
|
dontcall_header_field_cb (http_parser *p, const char *buf, size_t len)
|
|
|
|
|
|
|
|
{
|
|
|
|
|
|
|
|
if (p || buf || len) { } // gcc
|
|
|
|
|
|
|
|
fprintf(stderr, "\n\n*** on_header_field() called on paused parser ***\n\n");
|
|
|
|
|
|
|
|
exit(1);
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
int
|
|
|
|
|
|
|
|
dontcall_header_value_cb (http_parser *p, const char *buf, size_t len)
|
|
|
|
|
|
|
|
{
|
|
|
|
|
|
|
|
if (p || buf || len) { } // gcc
|
|
|
|
|
|
|
|
fprintf(stderr, "\n\n*** on_header_value() called on paused parser ***\n\n");
|
|
|
|
|
|
|
|
exit(1);
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
int
|
|
|
|
|
|
|
|
dontcall_request_url_cb (http_parser *p, const char *buf, size_t len)
|
|
|
|
|
|
|
|
{
|
|
|
|
|
|
|
|
if (p || buf || len) { } // gcc
|
|
|
|
|
|
|
|
fprintf(stderr, "\n\n*** on_request_url() called on paused parser ***\n\n");
|
|
|
|
|
|
|
|
exit(1);
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
int
|
|
|
|
|
|
|
|
dontcall_body_cb (http_parser *p, const char *buf, size_t len)
|
|
|
|
|
|
|
|
{
|
|
|
|
|
|
|
|
if (p || buf || len) { } // gcc
|
|
|
|
|
|
|
|
fprintf(stderr, "\n\n*** on_body_cb() called on paused parser ***\n\n");
|
|
|
|
|
|
|
|
exit(1);
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
int
|
|
|
|
|
|
|
|
dontcall_headers_complete_cb (http_parser *p)
|
|
|
|
|
|
|
|
{
|
|
|
|
|
|
|
|
if (p) { } // gcc
|
|
|
|
|
|
|
|
fprintf(stderr, "\n\n*** on_headers_complete() called on paused "
|
|
|
|
|
|
|
|
"parser ***\n\n");
|
|
|
|
|
|
|
|
exit(1);
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
int
|
|
|
|
|
|
|
|
dontcall_message_complete_cb (http_parser *p)
|
|
|
|
|
|
|
|
{
|
|
|
|
|
|
|
|
if (p) { } // gcc
|
|
|
|
|
|
|
|
fprintf(stderr, "\n\n*** on_message_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
|
|
|
|
|
|
|
|
,.on_header_value = dontcall_header_value_cb
|
|
|
|
|
|
|
|
,.on_url = dontcall_request_url_cb
|
|
|
|
|
|
|
|
,.on_body = dontcall_body_cb
|
|
|
|
|
|
|
|
,.on_headers_complete = dontcall_headers_complete_cb
|
|
|
|
|
|
|
|
,.on_message_complete = dontcall_message_complete_cb
|
|
|
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/* These pause_* callbacks always pause the parser and just invoke the regular
|
|
|
|
|
|
|
|
* callback that tracks content. Before returning, we overwrite the parser
|
|
|
|
|
|
|
|
* settings to point to the _dontcall variety so that we can verify that
|
|
|
|
|
|
|
|
* the pause actually did, you know, pause. */
|
|
|
|
|
|
|
|
int
|
|
|
|
|
|
|
|
pause_message_begin_cb (http_parser *p)
|
|
|
|
|
|
|
|
{
|
|
|
|
|
|
|
|
http_parser_pause(p, 1);
|
|
|
|
|
|
|
|
*current_pause_parser = settings_dontcall;
|
|
|
|
|
|
|
|
return message_begin_cb(p);
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
int
|
|
|
|
|
|
|
|
pause_header_field_cb (http_parser *p, const char *buf, size_t len)
|
|
|
|
|
|
|
|
{
|
|
|
|
|
|
|
|
http_parser_pause(p, 1);
|
|
|
|
|
|
|
|
*current_pause_parser = settings_dontcall;
|
|
|
|
|
|
|
|
return header_field_cb(p, buf, len);
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
int
|
|
|
|
|
|
|
|
pause_header_value_cb (http_parser *p, const char *buf, size_t len)
|
|
|
|
|
|
|
|
{
|
|
|
|
|
|
|
|
http_parser_pause(p, 1);
|
|
|
|
|
|
|
|
*current_pause_parser = settings_dontcall;
|
|
|
|
|
|
|
|
return header_value_cb(p, buf, len);
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
int
|
|
|
|
|
|
|
|
pause_request_url_cb (http_parser *p, const char *buf, size_t len)
|
|
|
|
|
|
|
|
{
|
|
|
|
|
|
|
|
http_parser_pause(p, 1);
|
|
|
|
|
|
|
|
*current_pause_parser = settings_dontcall;
|
|
|
|
|
|
|
|
return request_url_cb(p, buf, len);
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
int
|
|
|
|
|
|
|
|
pause_body_cb (http_parser *p, const char *buf, size_t len)
|
|
|
|
|
|
|
|
{
|
|
|
|
|
|
|
|
http_parser_pause(p, 1);
|
|
|
|
|
|
|
|
*current_pause_parser = settings_dontcall;
|
|
|
|
|
|
|
|
return body_cb(p, buf, len);
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
int
|
|
|
|
|
|
|
|
pause_headers_complete_cb (http_parser *p)
|
|
|
|
|
|
|
|
{
|
|
|
|
|
|
|
|
http_parser_pause(p, 1);
|
|
|
|
|
|
|
|
*current_pause_parser = settings_dontcall;
|
|
|
|
|
|
|
|
return headers_complete_cb(p);
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
int
|
|
|
|
|
|
|
|
pause_message_complete_cb (http_parser *p)
|
|
|
|
|
|
|
|
{
|
|
|
|
|
|
|
|
http_parser_pause(p, 1);
|
|
|
|
|
|
|
|
*current_pause_parser = settings_dontcall;
|
|
|
|
|
|
|
|
return message_complete_cb(p);
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
static http_parser_settings settings_pause =
|
|
|
|
|
|
|
|
{.on_message_begin = pause_message_begin_cb
|
|
|
|
|
|
|
|
,.on_header_field = pause_header_field_cb
|
|
|
|
|
|
|
|
,.on_header_value = pause_header_value_cb
|
|
|
|
|
|
|
|
,.on_url = pause_request_url_cb
|
|
|
|
|
|
|
|
,.on_body = pause_body_cb
|
|
|
|
|
|
|
|
,.on_headers_complete = pause_headers_complete_cb
|
|
|
|
|
|
|
|
,.on_message_complete = pause_message_complete_cb
|
|
|
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
static http_parser_settings settings =
|
|
|
|
static http_parser_settings settings =
|
|
|
|
{.on_message_begin = message_begin_cb
|
|
|
|
{.on_message_begin = message_begin_cb
|
|
|
|
,.on_header_field = header_field_cb
|
|
|
|
,.on_header_field = header_field_cb
|
|
|
@ -1359,6 +1500,17 @@ size_t parse_count_body (const char *buf, size_t len)
|
|
|
|
return nparsed;
|
|
|
|
return nparsed;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
size_t parse_pause (const char *buf, size_t len)
|
|
|
|
|
|
|
|
{
|
|
|
|
|
|
|
|
size_t nparsed;
|
|
|
|
|
|
|
|
http_parser_settings s = settings_pause;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
currently_parsing_eof = (len == 0);
|
|
|
|
|
|
|
|
current_pause_parser = &s;
|
|
|
|
|
|
|
|
nparsed = http_parser_execute(parser, current_pause_parser, buf, len);
|
|
|
|
|
|
|
|
return nparsed;
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
static inline int
|
|
|
|
static inline int
|
|
|
|
check_str_eq (const struct message *m,
|
|
|
|
check_str_eq (const struct message *m,
|
|
|
|
const char *prop,
|
|
|
|
const char *prop,
|
|
|
@ -1982,6 +2134,58 @@ create_large_chunked_message (int body_size_in_kb, const char* headers)
|
|
|
|
return buf;
|
|
|
|
return buf;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/* Verify that we can pause parsing at any of the bytes in the
|
|
|
|
|
|
|
|
* message and still get the result that we're expecting. */
|
|
|
|
|
|
|
|
void
|
|
|
|
|
|
|
|
test_message_pause (const struct message *msg)
|
|
|
|
|
|
|
|
{
|
|
|
|
|
|
|
|
char *buf = (char*) msg->raw;
|
|
|
|
|
|
|
|
size_t buflen = strlen(msg->raw);
|
|
|
|
|
|
|
|
size_t nread;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
parser_init(msg->type);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
do {
|
|
|
|
|
|
|
|
nread = parse_pause(buf, buflen);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// We can only set the upgrade buffer once we've gotten our message
|
|
|
|
|
|
|
|
// completion callback.
|
|
|
|
|
|
|
|
if (messages[0].message_complete_cb_called &&
|
|
|
|
|
|
|
|
msg->upgrade &&
|
|
|
|
|
|
|
|
parser->upgrade) {
|
|
|
|
|
|
|
|
messages[0].upgrade = buf + nread;
|
|
|
|
|
|
|
|
goto test;
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
if (nread < buflen) {
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// Not much do to if we failed a strict-mode check
|
|
|
|
|
|
|
|
if (HTTP_PARSER_ERRNO(parser) == HPE_STRICT) {
|
|
|
|
|
|
|
|
parser_free();
|
|
|
|
|
|
|
|
return;
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
assert (HTTP_PARSER_ERRNO(parser) == HPE_PAUSED);
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
buf += nread;
|
|
|
|
|
|
|
|
buflen -= nread;
|
|
|
|
|
|
|
|
http_parser_pause(parser, 0);
|
|
|
|
|
|
|
|
} while (buflen > 0);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
nread = parse_pause(NULL, 0);
|
|
|
|
|
|
|
|
assert (nread == 0);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
test:
|
|
|
|
|
|
|
|
if (num_messages != 1) {
|
|
|
|
|
|
|
|
printf("\n*** num_messages != 1 after testing '%s' ***\n\n", msg->name);
|
|
|
|
|
|
|
|
exit(1);
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
if(!message_eq(0, msg)) exit(1);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
parser_free();
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
int
|
|
|
|
int
|
|
|
|
main (void)
|
|
|
|
main (void)
|
|
|
@ -2012,6 +2216,10 @@ main (void)
|
|
|
|
test_message(&responses[i]);
|
|
|
|
test_message(&responses[i]);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
for (i = 0; i < response_count; i++) {
|
|
|
|
|
|
|
|
test_message_pause(&responses[i]);
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
for (i = 0; i < response_count; i++) {
|
|
|
|
for (i = 0; i < response_count; i++) {
|
|
|
|
if (!responses[i].should_keep_alive) continue;
|
|
|
|
if (!responses[i].should_keep_alive) continue;
|
|
|
|
for (j = 0; j < response_count; j++) {
|
|
|
|
for (j = 0; j < response_count; j++) {
|
|
|
@ -2187,7 +2395,9 @@ main (void)
|
|
|
|
test_message(&requests[i]);
|
|
|
|
test_message(&requests[i]);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
for (i = 0; i < request_count; i++) {
|
|
|
|
|
|
|
|
test_message_pause(&requests[i]);
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
for (i = 0; i < request_count; i++) {
|
|
|
|
for (i = 0; i < request_count; i++) {
|
|
|
|
if (!requests[i].should_keep_alive) continue;
|
|
|
|
if (!requests[i].should_keep_alive) continue;
|
|
|
|