Update http-parser

This commit is contained in:
Tatsuhiro Tsujikawa 2015-02-20 19:51:41 +09:00
parent 4424cf5b65
commit 83d9ee1fd1
4 changed files with 106 additions and 12 deletions

View File

@ -39,12 +39,25 @@ BogDan Vatra <bogdan@kde.org>
Peter Faiman <peter@thepicard.org> Peter Faiman <peter@thepicard.org>
Corey Richardson <corey@octayn.net> Corey Richardson <corey@octayn.net>
Tóth Tamás <tomika_nospam@freemail.hu> Tóth Tamás <tomika_nospam@freemail.hu>
Patrik Stutz <patrik.stutz@gmail.com>
Cam Swords <cam.swords@gmail.com> Cam Swords <cam.swords@gmail.com>
Chris Dickinson <christopher.s.dickinson@gmail.com> Chris Dickinson <christopher.s.dickinson@gmail.com>
Uli Köhler <ukoehler@btronik.de> Uli Köhler <ukoehler@btronik.de>
Charlie Somerville <charlie@charliesomerville.com> Charlie Somerville <charlie@charliesomerville.com>
Patrik Stutz <patrik.stutz@gmail.com>
Fedor Indutny <fedor.indutny@gmail.com> Fedor Indutny <fedor.indutny@gmail.com>
runner <runner.mei@gmail.com> runner <runner.mei@gmail.com>
Alexis Campailla <alexis@janeasystems.com> Alexis Campailla <alexis@janeasystems.com>
David Wragg <david@wragg.org> David Wragg <david@wragg.org>
Vinnie Falco <vinnie.falco@gmail.com>
Alex Butum <alexbutum@linux.com>
Rex Feng <rexfeng@gmail.com>
Alex Kocharin <alex@kocharin.ru>
Mark Koopman <markmontymark@yahoo.com>
Helge Heß <me@helgehess.eu>
Alexis La Goutte <alexis.lagoutte@gmail.com>
George Miroshnykov <george.miroshnykov@gmail.com>
Maciej Małecki <me@mmalecki.com>
Marc O'Morain <github.com@marcomorain.com>
Jeff Pinner <jpinner@twitter.com>
Timothy J Fontaine <tjfontaine@gmail.com>
Akagi201 <akagi201@gmail.com>

View File

@ -57,15 +57,14 @@ do { \
} while(0) } while(0)
#define CURRENT_STATE() p_state #define CURRENT_STATE() p_state
#define UPDATE_STATE(V) p_state = (V); #define UPDATE_STATE(V) p_state = (enum state) (V);
#define RETURN(V) \ #define RETURN(V) \
do { \ do { \
parser->state = CURRENT_STATE(); \ parser->state = CURRENT_STATE(); \
return (V); \ return (V); \
} while (0); } while (0);
#define REEXECUTE() \ #define REEXECUTE() \
--p; \ goto reexecute; \
break;
#ifdef __GNUC__ #ifdef __GNUC__
@ -637,7 +636,7 @@ size_t http_parser_execute (http_parser *parser,
const char *url_mark = 0; const char *url_mark = 0;
const char *body_mark = 0; const char *body_mark = 0;
const char *status_mark = 0; const char *status_mark = 0;
enum state p_state = parser->state; enum state p_state = (enum state) parser->state;
/* We're in an error state. Don't bother doing anything. */ /* We're in an error state. Don't bother doing anything. */
if (HTTP_PARSER_ERRNO(parser) != HPE_OK) { if (HTTP_PARSER_ERRNO(parser) != HPE_OK) {
@ -697,6 +696,7 @@ size_t http_parser_execute (http_parser *parser,
if (PARSING_HEADER(CURRENT_STATE())) if (PARSING_HEADER(CURRENT_STATE()))
COUNT_HEADER_SIZE(1); COUNT_HEADER_SIZE(1);
reexecute:
switch (CURRENT_STATE()) { switch (CURRENT_STATE()) {
case s_dead: case s_dead:
@ -1518,7 +1518,7 @@ size_t http_parser_execute (http_parser *parser,
case s_header_value: case s_header_value:
{ {
const char* start = p; const char* start = p;
enum header_states h_state = parser->header_state; enum header_states h_state = (enum header_states) parser->header_state;
for (; p != data + len; p++) { for (; p != data + len; p++) {
ch = *p; ch = *p;
if (ch == CR) { if (ch == CR) {
@ -1547,8 +1547,8 @@ size_t http_parser_execute (http_parser *parser,
limit = MIN(limit, HTTP_MAX_HEADER_SIZE); limit = MIN(limit, HTTP_MAX_HEADER_SIZE);
p_cr = memchr(p, CR, limit); p_cr = (const char*) memchr(p, CR, limit);
p_lf = memchr(p, LF, limit); p_lf = (const char*) memchr(p, LF, limit);
if (p_cr != NULL) { if (p_cr != NULL) {
if (p_lf != NULL && p_cr >= p_lf) if (p_lf != NULL && p_cr >= p_lf)
p = p_lf; p = p_lf;
@ -1618,6 +1618,8 @@ size_t http_parser_execute (http_parser *parser,
h_state = h_matching_connection_upgrade; h_state = h_matching_connection_upgrade;
} else if (STRICT_TOKEN(c)) { } else if (STRICT_TOKEN(c)) {
h_state = h_matching_connection_token; h_state = h_matching_connection_token;
} else if (c == ' ' || c == '\t') {
/* Skip lws */
} else { } else {
h_state = h_general; h_state = h_general;
} }
@ -2134,6 +2136,12 @@ http_parser_init (http_parser *parser, enum http_parser_type t)
parser->http_errno = HPE_OK; parser->http_errno = HPE_OK;
} }
void
http_parser_settings_init(http_parser_settings *settings)
{
memset(settings, 0, sizeof(*settings));
}
const char * const char *
http_errno_name(enum http_errno err) { http_errno_name(enum http_errno err) {
assert(err < (sizeof(http_strerror_tab)/sizeof(http_strerror_tab[0]))); assert(err < (sizeof(http_strerror_tab)/sizeof(http_strerror_tab[0])));

View File

@ -26,8 +26,8 @@ extern "C" {
/* Also update SONAME in the Makefile whenever you change these. */ /* Also update SONAME in the Makefile whenever you change these. */
#define HTTP_PARSER_VERSION_MAJOR 2 #define HTTP_PARSER_VERSION_MAJOR 2
#define HTTP_PARSER_VERSION_MINOR 3 #define HTTP_PARSER_VERSION_MINOR 4
#define HTTP_PARSER_VERSION_PATCH 0 #define HTTP_PARSER_VERSION_PATCH 2
#include <sys/types.h> #include <sys/types.h>
#if defined(_WIN32) && !defined(__MINGW32__) && (!defined(_MSC_VER) || _MSC_VER<1600) #if defined(_WIN32) && !defined(__MINGW32__) && (!defined(_MSC_VER) || _MSC_VER<1600)
@ -204,8 +204,8 @@ enum http_errno {
struct http_parser { struct http_parser {
/** PRIVATE **/ /** PRIVATE **/
unsigned int type : 2; /* enum http_parser_type */ unsigned int type : 2; /* enum http_parser_type */
unsigned int flags : 6; /* F_* values from 'flags' enum; semi-public */ unsigned int flags : 7; /* F_* values from 'flags' enum; semi-public */
unsigned int state : 8; /* enum state from http_parser.c */ unsigned int state : 7; /* enum state from http_parser.c */
unsigned int header_state : 8; /* enum header_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 */ unsigned int index : 8; /* index into current matcher */
@ -288,6 +288,11 @@ unsigned long http_parser_version(void);
void http_parser_init(http_parser *parser, enum http_parser_type type); void http_parser_init(http_parser *parser, enum http_parser_type type);
/* Initialize http_parser_settings members to 0
*/
void http_parser_settings_init(http_parser_settings *settings);
/* Executes the parser. Returns number of parsed bytes. Sets /* Executes the parser. Returns number of parsed bytes. Sets
* `parser->http_errno` on error. */ * `parser->http_errno` on error. */
size_t http_parser_execute(http_parser *parser, size_t http_parser_execute(http_parser *parser,

View File

@ -986,6 +986,55 @@ const struct message requests[] =
,.body= "" ,.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= ""
}
, {.name= NULL } /* sentinel */ , {.name= NULL } /* sentinel */
}; };
@ -2995,6 +3044,22 @@ test_header_overflow_error (int req)
abort(); 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 static void
test_content_length_overflow (const char *buf, size_t buflen, int expect_ok) test_content_length_overflow (const char *buf, size_t buflen, int expect_ok)
{ {
@ -3361,6 +3426,9 @@ main (void)
test_parse_url(); test_parse_url();
test_method_str(); test_method_str();
//// NREAD
test_header_nread_value();
//// OVERFLOW CONDITIONS //// OVERFLOW CONDITIONS
test_header_overflow_error(HTTP_REQUEST); test_header_overflow_error(HTTP_REQUEST);