diff --git a/third-party/http-parser/AUTHORS b/third-party/http-parser/AUTHORS index 8e2df1d0..5323b685 100644 --- a/third-party/http-parser/AUTHORS +++ b/third-party/http-parser/AUTHORS @@ -65,3 +65,4 @@ Romain Giraud Jay Satiro Arne Steen Kjell Schubert +Olivier Mengué diff --git a/third-party/http-parser/README.md b/third-party/http-parser/README.md index c0b83d2b..eedd7f8c 100644 --- a/third-party/http-parser/README.md +++ b/third-party/http-parser/README.md @@ -1,7 +1,7 @@ HTTP Parser =========== -[![Build Status](https://travis-ci.org/joyent/http-parser.png?branch=master)](https://travis-ci.org/joyent/http-parser) +[![Build Status](https://api.travis-ci.org/nodejs/http-parser.svg?branch=master)](https://travis-ci.org/nodejs/http-parser) This is a parser for HTTP messages written in C. It parses both requests and responses. The parser is designed to be used in performance HTTP @@ -137,6 +137,69 @@ There are two types of callbacks: Callbacks must return 0 on success. Returning a non-zero value indicates error to the parser, making it exit immediately. +For cases where it is necessary to pass local information to/from a callback, +the `http_parser` object's `data` field can be used. +An example of such a case is when using threads to handle a socket connection, +parse a request, and then give a response over that socket. By instantiation +of a thread-local struct containing relevant data (e.g. accepted socket, +allocated memory for callbacks to write into, etc), a parser's callbacks are +able to communicate data between the scope of the thread and the scope of the +callback in a threadsafe manner. This allows http-parser to be used in +multi-threaded contexts. + +Example: +``` + typedef struct { + socket_t sock; + void* buffer; + int buf_len; + } custom_data_t; + + +int my_url_callback(http_parser* parser, const char *at, size_t length) { + /* access to thread local custom_data_t struct. + Use this access save parsed data for later use into thread local + buffer, or communicate over socket + */ + parser->data; + ... + return 0; +} + +... + +void http_parser_thread(socket_t sock) { + int nparsed = 0; + /* allocate memory for user data */ + custom_data_t *my_data = malloc(sizeof(custom_data_t)); + + /* some information for use by callbacks. + * achieves thread -> callback information flow */ + my_data->sock = sock; + + /* instantiate a thread-local parser */ + http_parser *parser = malloc(sizeof(http_parser)); + http_parser_init(parser, HTTP_REQUEST); /* initialise parser */ + /* this custom data reference is accessible through the reference to the + parser supplied to callback functions */ + parser->data = my_data; + + http_parser_settings settings; / * set up callbacks */ + settings.on_url = my_url_callback; + + /* execute parser */ + nparsed = http_parser_execute(parser, &settings, buf, recved); + + ... + /* parsed information copied from callback. + can now perform action on data copied into thread-local memory from callbacks. + achieves callback -> thread information flow */ + my_data->buffer; + ... +} + +``` + In case you parse HTTP message in chunks (i.e. `read()` request line from socket, parse, read half headers, parse, etc) your data callbacks may be called more than once. Http-parser guarantees that data pointer is only diff --git a/third-party/http-parser/contrib/url_parser.c b/third-party/http-parser/contrib/url_parser.c index 6650b414..f235bed9 100644 --- a/third-party/http-parser/contrib/url_parser.c +++ b/third-party/http-parser/contrib/url_parser.c @@ -35,6 +35,7 @@ int main(int argc, char ** argv) { connect = strcmp("connect", argv[1]) == 0 ? 1 : 0; printf("Parsing %s, connect %d\n", argv[2], connect); + http_parser_url_init(&u); result = http_parser_parse_url(argv[2], len, connect, &u); if (result != 0) { printf("Parse error : %d\n", result); @@ -43,4 +44,4 @@ int main(int argc, char ** argv) { printf("Parse ok, result : \n"); dump_url(argv[2], &u); return 0; -} \ No newline at end of file +} diff --git a/third-party/http-parser/http_parser.c b/third-party/http-parser/http_parser.c index 99f5a23a..b3037d7e 100644 --- a/third-party/http-parser/http_parser.c +++ b/third-party/http-parser/http_parser.c @@ -965,7 +965,7 @@ reexecute: case 'D': parser->method = HTTP_DELETE; break; case 'G': parser->method = HTTP_GET; break; case 'H': parser->method = HTTP_HEAD; break; - case 'L': parser->method = HTTP_LOCK; break; + case 'L': parser->method = HTTP_LOCK; /* or LINK */ break; case 'M': parser->method = HTTP_MKCOL; /* or MOVE, MKACTIVITY, MERGE, M-SEARCH, MKCALENDAR */ break; case 'N': parser->method = HTTP_NOTIFY; break; case 'O': parser->method = HTTP_OPTIONS; break; @@ -975,7 +975,7 @@ reexecute: case 'R': parser->method = HTTP_REPORT; /* or REBIND */ break; case 'S': parser->method = HTTP_SUBSCRIBE; /* or SEARCH */ break; case 'T': parser->method = HTTP_TRACE; break; - case 'U': parser->method = HTTP_UNLOCK; /* or UNSUBSCRIBE, UNBIND */ break; + case 'U': parser->method = HTTP_UNLOCK; /* or UNSUBSCRIBE, UNBIND, UNLINK */ break; default: SET_ERRNO(HPE_INVALID_METHOD); goto error; @@ -1038,16 +1038,25 @@ reexecute: SET_ERRNO(HPE_INVALID_METHOD); goto error; } - } else if (parser->index == 1 && parser->method == HTTP_POST) { - if (ch == 'R') { - parser->method = HTTP_PROPFIND; /* or HTTP_PROPPATCH */ - } else if (ch == 'U') { - parser->method = HTTP_PUT; /* or HTTP_PURGE */ - } else if (ch == 'A') { - parser->method = HTTP_PATCH; - } else { - SET_ERRNO(HPE_INVALID_METHOD); - goto error; + } else if (parser->index == 1) { + if (parser->method == HTTP_POST) { + if (ch == 'R') { + parser->method = HTTP_PROPFIND; /* or HTTP_PROPPATCH */ + } else if (ch == 'U') { + parser->method = HTTP_PUT; /* or HTTP_PURGE */ + } else if (ch == 'A') { + parser->method = HTTP_PATCH; + } else { + SET_ERRNO(HPE_INVALID_METHOD); + goto error; + } + } else if (parser->method == HTTP_LOCK) { + if (ch == 'I') { + parser->method = HTTP_LINK; + } else { + SET_ERRNO(HPE_INVALID_METHOD); + goto error; + } } } else if (parser->index == 2) { if (parser->method == HTTP_PUT) { @@ -1072,6 +1081,8 @@ reexecute: } } else if (parser->index == 4 && parser->method == HTTP_PROPFIND && ch == 'P') { parser->method = HTTP_PROPPATCH; + } else if (parser->index == 3 && parser->method == HTTP_UNLOCK && ch == 'I') { + parser->method = HTTP_UNLINK; } else { SET_ERRNO(HPE_INVALID_METHOD); goto error; @@ -2339,6 +2350,11 @@ http_parse_host(const char * buf, struct http_parser_url *u, int found_at) { return 0; } +void +http_parser_url_init(struct http_parser_url *u) { + memset(u, 0, sizeof(*u)); +} + int http_parser_parse_url(const char *buf, size_t buflen, int is_connect, struct http_parser_url *u) diff --git a/third-party/http-parser/http_parser.h b/third-party/http-parser/http_parser.h index a7bb9b9c..34bebf3d 100644 --- a/third-party/http-parser/http_parser.h +++ b/third-party/http-parser/http_parser.h @@ -26,7 +26,7 @@ extern "C" { /* Also update SONAME in the Makefile whenever you change these. */ #define HTTP_PARSER_VERSION_MAJOR 2 -#define HTTP_PARSER_VERSION_MINOR 5 +#define HTTP_PARSER_VERSION_MINOR 6 #define HTTP_PARSER_VERSION_PATCH 0 #include @@ -124,6 +124,9 @@ typedef int (*http_cb) (http_parser*); XX(29, PURGE, PURGE) \ /* CalDAV */ \ XX(30, MKCALENDAR, MKCALENDAR) \ + /* RFC-2068, section 19.6.1.2 */ \ + XX(31, LINK, LINK) \ + XX(32, UNLINK, UNLINK) \ enum http_method { @@ -149,7 +152,7 @@ enum flags /* Map for errno-related constants - * + * * The provided argument should be a macro that takes 2 arguments. */ #define HTTP_ERRNO_MAP(XX) \ @@ -330,6 +333,9 @@ const char *http_errno_name(enum http_errno err); /* Return a string description of the given error */ const char *http_errno_description(enum http_errno err); +/* Initialize all http_parser_url members to 0 */ +void http_parser_url_init(struct http_parser_url *u); + /* Parse a URL; return nonzero on failure */ int http_parser_parse_url(const char *buf, size_t buflen, int is_connect, diff --git a/third-party/http-parser/test.c b/third-party/http-parser/test.c index 72f0f4bf..c63b8f0b 100644 --- a/third-party/http-parser/test.c +++ b/third-party/http-parser/test.c @@ -1101,6 +1101,58 @@ const struct message requests[] = ,.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: ; rel=\"tag\"\r\n" + "Link: ; 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", "; rel=\"tag\"" } + , { "Link", "; 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: ; 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", "; rel=\"tag\"" } + } + ,.body= "" + } + , {.name= NULL } /* sentinel */ }; @@ -3760,6 +3812,8 @@ main (void) "PATCH", "PURGE", "MKCALENDAR", + "LINK", + "UNLINK", 0 }; const char **this_method; for (this_method = all_methods; *this_method; this_method++) {