Update http-parser to 4e382f96e6d3321538a78f2c7f9506d4e79b08d6
This commit is contained in:
parent
1cfdf386ff
commit
c5f3eee3be
|
@ -65,3 +65,4 @@ Romain Giraud <giraud.romain@gmail.com>
|
|||
Jay Satiro <raysatiro@yahoo.com>
|
||||
Arne Steen <Arne.Steen@gmx.de>
|
||||
Kjell Schubert <kjell.schubert@gmail.com>
|
||||
Olivier Mengué <dolmen@cpan.org>
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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 <sys/types.h>
|
||||
|
@ -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
|
||||
{
|
||||
|
@ -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,
|
||||
|
|
|
@ -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: <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 */
|
||||
};
|
||||
|
||||
|
@ -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++) {
|
||||
|
|
Loading…
Reference in New Issue