Upgrade http-parser
Now at version 6f72c780f0a237a775150a9963bcdf5299685cde
This commit is contained in:
Родитель
765f0cdece
Коммит
54d4efd44b
|
@ -0,0 +1,3 @@
|
|||
tags
|
||||
*.o
|
||||
test
|
|
@ -4,8 +4,9 @@ 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
|
||||
applications. It does not make any allocations, it does not buffer data, and
|
||||
it can be interrupted at anytime. It only requires about 136 bytes of data
|
||||
per message stream (in a web server that is per connection).
|
||||
it can be interrupted at anytime. Depending on your architecture, it only
|
||||
requires between 100 and 200 bytes of data per message stream (in a web
|
||||
server that is per connection).
|
||||
|
||||
Features:
|
||||
|
||||
|
@ -31,12 +32,14 @@ One `http_parser` object is used per TCP connection. Initialize the struct
|
|||
using `http_parser_init()` and set the callbacks. That might look something
|
||||
like this for a request parser:
|
||||
|
||||
http_parser_settings settings;
|
||||
settings.on_path = my_path_callback;
|
||||
settings.on_header_field = my_header_field_callback;
|
||||
/* ... */
|
||||
settings.data = my_socket;
|
||||
|
||||
http_parser *parser = malloc(sizeof(http_parser));
|
||||
http_parser_init(parser, HTTP_REQUEST);
|
||||
parser->on_path = my_path_callback;
|
||||
parser->on_header_field = my_header_field_callback;
|
||||
/* ... */
|
||||
parser->data = my_socket;
|
||||
|
||||
When data is received on the socket execute the parser and check for errors.
|
||||
|
||||
|
@ -54,7 +57,7 @@ When data is received on the socket execute the parser and check for errors.
|
|||
* Note we pass the recved==0 to http_parse_requests to signal
|
||||
* that EOF has been recieved.
|
||||
*/
|
||||
nparsed = http_parser_execute(parser, buf, recved);
|
||||
nparsed = http_parser_execute(parser, settings, buf, recved);
|
||||
|
||||
if (nparsed != recved) {
|
||||
/* Handle error. Usually just close the connection. */
|
||||
|
@ -63,13 +66,13 @@ When data is received on the socket execute the parser and check for errors.
|
|||
HTTP needs to know where the end of the stream is. For example, sometimes
|
||||
servers send responses without Content-Length and expect the client to
|
||||
consume input (for the body) until EOF. To tell http_parser about EOF, give
|
||||
`0` as the third parameter to `http_parser_execute()`. Callbacks and errors
|
||||
`0` as the forth parameter to `http_parser_execute()`. Callbacks and errors
|
||||
can still be encountered during an EOF, so one must still be prepared
|
||||
to receive them.
|
||||
|
||||
Scalar valued message information such as `status_code`, `method`, and the
|
||||
HTTP version are stored in the parser structure. This data is only
|
||||
temporarlly stored in `http_parser` and gets reset on each new message. If
|
||||
temporally stored in `http_parser` and gets reset on each new message. If
|
||||
this information is needed later, copy it out of the structure during the
|
||||
`headers_complete` callback.
|
||||
|
||||
|
@ -85,10 +88,10 @@ parser, for example, would not want such a feature.
|
|||
Callbacks
|
||||
---------
|
||||
|
||||
During the `http_parser_execute()` call, the callbacks set in `http_parser`
|
||||
will be executed. The parser maintains state and never looks behind, so
|
||||
buffering the data is not necessary. If you need to save certain data for
|
||||
later usage, you can do that from the callbacks.
|
||||
During the `http_parser_execute()` call, the callbacks set in
|
||||
`http_parser_settings` will be executed. The parser maintains state and
|
||||
never looks behind, so buffering the data is not necessary. If you need to
|
||||
save certain data for later usage, you can do that from the callbacks.
|
||||
|
||||
There are two types of callbacks:
|
||||
|
||||
|
@ -98,6 +101,9 @@ There are two types of callbacks:
|
|||
Callbacks: (requests only) on_path, on_query_string, on_uri, on_fragment,
|
||||
(common) on_header_field, on_header_value, on_body;
|
||||
|
||||
Callbacks must return 0 on success. Returning a non-zero value indicates
|
||||
error to the parser, making it exit immediately.
|
||||
|
||||
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
|
||||
|
|
|
@ -24,88 +24,65 @@
|
|||
#include <http_parser.h>
|
||||
#include <stdint.h>
|
||||
#include <assert.h>
|
||||
#include <string.h> /* strncmp */
|
||||
#include <stddef.h>
|
||||
|
||||
#ifndef NULL
|
||||
# define NULL ((void*)0)
|
||||
#endif
|
||||
|
||||
#ifndef MIN
|
||||
# define MIN(a,b) ((a) < (b) ? (a) : (b))
|
||||
#endif
|
||||
|
||||
|
||||
#define MAX_FIELD_SIZE (80*1024)
|
||||
|
||||
|
||||
#define CALLBACK2(FOR) \
|
||||
do { \
|
||||
if (settings.on_##FOR) { \
|
||||
if (0 != settings.on_##FOR(parser)) return (p - data); \
|
||||
} \
|
||||
} while (0)
|
||||
|
||||
|
||||
#define MARK(FOR) \
|
||||
do { \
|
||||
parser->FOR##_mark = p; \
|
||||
parser->FOR##_size = 0; \
|
||||
} while (0)
|
||||
|
||||
#define CALLBACK(FOR) \
|
||||
do { \
|
||||
if (0 != FOR##_callback(parser, p)) return (p - data); \
|
||||
parser->FOR##_mark = NULL; \
|
||||
} while (0)
|
||||
|
||||
#define CALLBACK_NOCLEAR(FOR) \
|
||||
do { \
|
||||
if (0 != FOR##_callback(parser, p)) return (p - data); \
|
||||
if (parser->FOR##_mark) { \
|
||||
parser->FOR##_size += p - parser->FOR##_mark; \
|
||||
if (parser->FOR##_size > MAX_FIELD_SIZE) return (p - data); \
|
||||
if (settings.on_##FOR) { \
|
||||
if (0 != settings.on_##FOR(parser, \
|
||||
parser->FOR##_mark, \
|
||||
p - parser->FOR##_mark)) \
|
||||
{ \
|
||||
return (p - data); \
|
||||
} \
|
||||
} \
|
||||
} \
|
||||
} while (0)
|
||||
|
||||
#define CALLBACK2(FOR) \
|
||||
|
||||
#define CALLBACK(FOR) \
|
||||
do { \
|
||||
if (0 != FOR##_callback(parser)) return (p - data); \
|
||||
CALLBACK_NOCLEAR(FOR); \
|
||||
parser->FOR##_mark = NULL; \
|
||||
} while (0)
|
||||
|
||||
#define DEFINE_CALLBACK(FOR) \
|
||||
static inline int FOR##_callback (http_parser *parser, const char *p) \
|
||||
{ \
|
||||
if (!parser->FOR##_mark) return 0; \
|
||||
assert(parser->FOR##_mark); \
|
||||
const char *mark = parser->FOR##_mark; \
|
||||
parser->FOR##_size += p - mark; \
|
||||
if (parser->FOR##_size > MAX_FIELD_SIZE) return -1; \
|
||||
int r = 0; \
|
||||
if (parser->on_##FOR) r = parser->on_##FOR(parser, mark, p - mark); \
|
||||
return r; \
|
||||
}
|
||||
|
||||
DEFINE_CALLBACK(url)
|
||||
DEFINE_CALLBACK(path)
|
||||
DEFINE_CALLBACK(query_string)
|
||||
DEFINE_CALLBACK(fragment)
|
||||
DEFINE_CALLBACK(header_field)
|
||||
DEFINE_CALLBACK(header_value)
|
||||
|
||||
static inline int headers_complete_callback (http_parser *parser)
|
||||
{
|
||||
if (parser->on_headers_complete == NULL) return 0;
|
||||
return parser->on_headers_complete(parser);
|
||||
}
|
||||
|
||||
static inline int message_begin_callback (http_parser *parser)
|
||||
{
|
||||
if (parser->on_message_begin == NULL) return 0;
|
||||
return parser->on_message_begin(parser);
|
||||
}
|
||||
|
||||
static inline int message_complete_callback (http_parser *parser)
|
||||
{
|
||||
if (parser->on_message_complete == NULL) return 0;
|
||||
return parser->on_message_complete(parser);
|
||||
}
|
||||
|
||||
#define PROXY_CONNECTION "proxy-connection"
|
||||
#define CONNECTION "connection"
|
||||
#define CONTENT_LENGTH "content-length"
|
||||
#define TRANSFER_ENCODING "transfer-encoding"
|
||||
|
||||
#define CHUNKED "chunked"
|
||||
#define KEEP_ALIVE "keep-alive"
|
||||
#define CLOSE "close"
|
||||
|
||||
|
||||
static const unsigned char lowcase[] =
|
||||
"\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"
|
||||
"\0\0\0\0\0\0\0\0\0\0\0\0\0-\0\0" "0123456789\0\0\0\0\0\0"
|
||||
|
@ -116,6 +93,7 @@ static const unsigned char lowcase[] =
|
|||
"\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"
|
||||
"\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0";
|
||||
|
||||
|
||||
static const int unhex[] =
|
||||
{-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1
|
||||
,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1
|
||||
|
@ -128,6 +106,7 @@ static const int unhex[] =
|
|||
};
|
||||
|
||||
|
||||
|
||||
static const uint32_t usual[] = {
|
||||
0xffffdbfe, /* 1111 1111 1111 1111 1101 1011 1111 1110 */
|
||||
|
||||
|
@ -148,6 +127,7 @@ static const uint32_t usual[] = {
|
|||
|
||||
#define USUAL(c) (usual[c >> 5] & (1 << (c & 0x1f)))
|
||||
|
||||
|
||||
enum state
|
||||
{ s_dead = 1 /* important that this is > 0 */
|
||||
|
||||
|
@ -216,6 +196,7 @@ enum state
|
|||
|
||||
#define PARSING_HEADER(state) (state <= s_headers_almost_done)
|
||||
|
||||
|
||||
enum header_states
|
||||
{ h_general = 0
|
||||
, h_C
|
||||
|
@ -240,6 +221,7 @@ enum header_states
|
|||
, h_connection_close
|
||||
};
|
||||
|
||||
|
||||
enum flags
|
||||
{ F_CHUNKED = 1 << 0
|
||||
, F_CONNECTION_KEEP_ALIVE = 1 << 1
|
||||
|
@ -247,12 +229,15 @@ enum flags
|
|||
, F_TRAILING = 1 << 3
|
||||
};
|
||||
|
||||
|
||||
#define CR '\r'
|
||||
#define LF '\n'
|
||||
#define LOWER(c) (unsigned char)(c | 0x20)
|
||||
|
||||
|
||||
#define start_state (parser->type == HTTP_REQUEST ? s_start_req : s_start_res)
|
||||
|
||||
|
||||
#if HTTP_PARSER_STRICT
|
||||
# define STRICT_CHECK(cond) if (cond) goto error
|
||||
# define NEW_MESSAGE() (http_should_keep_alive(parser) ? start_state : s_dead)
|
||||
|
@ -261,7 +246,38 @@ enum flags
|
|||
# define NEW_MESSAGE() start_state
|
||||
#endif
|
||||
|
||||
|
||||
#define ngx_str3_cmp(m, c0, c1, c2) \
|
||||
m[0] == c0 && m[1] == c1 && m[2] == c2
|
||||
|
||||
#define ngx_str3Ocmp(m, c0, c1, c2, c3) \
|
||||
m[0] == c0 && m[2] == c2 && m[3] == c3
|
||||
|
||||
#define ngx_str4cmp(m, c0, c1, c2, c3) \
|
||||
m[0] == c0 && m[1] == c1 && m[2] == c2 && m[3] == c3
|
||||
|
||||
#define ngx_str5cmp(m, c0, c1, c2, c3, c4) \
|
||||
m[0] == c0 && m[1] == c1 && m[2] == c2 && m[3] == c3 && m[4] == c4
|
||||
|
||||
#define ngx_str6cmp(m, c0, c1, c2, c3, c4, c5) \
|
||||
m[0] == c0 && m[1] == c1 && m[2] == c2 && m[3] == c3 \
|
||||
&& m[4] == c4 && m[5] == c5
|
||||
|
||||
#define ngx_str7_cmp(m, c0, c1, c2, c3, c4, c5, c6, c7) \
|
||||
m[0] == c0 && m[1] == c1 && m[2] == c2 && m[3] == c3 \
|
||||
&& m[4] == c4 && m[5] == c5 && m[6] == c6
|
||||
|
||||
#define ngx_str8cmp(m, c0, c1, c2, c3, c4, c5, c6, c7) \
|
||||
m[0] == c0 && m[1] == c1 && m[2] == c2 && m[3] == c3 \
|
||||
&& m[4] == c4 && m[5] == c5 && m[6] == c6 && m[7] == c7
|
||||
|
||||
#define ngx_str9cmp(m, c0, c1, c2, c3, c4, c5, c6, c7, c8) \
|
||||
m[0] == c0 && m[1] == c1 && m[2] == c2 && m[3] == c3 \
|
||||
&& m[4] == c4 && m[5] == c5 && m[6] == c6 && m[7] == c7 && m[8] == c8
|
||||
|
||||
|
||||
size_t http_parser_execute (http_parser *parser,
|
||||
http_parser_settings settings,
|
||||
const char *data,
|
||||
size_t len)
|
||||
{
|
||||
|
@ -269,8 +285,8 @@ size_t http_parser_execute (http_parser *parser,
|
|||
const char *p = data, *pe;
|
||||
ssize_t to_read;
|
||||
|
||||
enum state state = parser->state;
|
||||
enum header_states header_state = parser->header_state;
|
||||
enum state state = (enum state) parser->state;
|
||||
enum header_states header_state = (enum header_states) parser->header_state;
|
||||
size_t index = parser->index;
|
||||
size_t nread = parser->nread;
|
||||
|
||||
|
@ -462,7 +478,7 @@ size_t http_parser_execute (http_parser *parser,
|
|||
|
||||
if (ch < 'A' || 'Z' < ch) goto error;
|
||||
|
||||
parser->method = 0;
|
||||
parser->method = (enum http_method) 0;
|
||||
index = 0;
|
||||
parser->buffer[0] = ch;
|
||||
state = s_req_method;
|
||||
|
@ -474,16 +490,14 @@ size_t http_parser_execute (http_parser *parser,
|
|||
assert(index+1 < HTTP_PARSER_MAX_METHOD_LEN);
|
||||
parser->buffer[index+1] = '\0';
|
||||
|
||||
/* TODO Instead of using strncmp() use NGINX's ngx_str3Ocmp() */
|
||||
|
||||
switch (index+1) {
|
||||
case 3:
|
||||
if (strncmp(parser->buffer, "GET", 3) == 0) {
|
||||
if (ngx_str3_cmp(parser->buffer, 'G', 'E', 'T')) {
|
||||
parser->method = HTTP_GET;
|
||||
break;
|
||||
}
|
||||
|
||||
if (strncmp(parser->buffer, "PUT", 3) == 0) {
|
||||
if (ngx_str3_cmp(parser->buffer, 'P', 'U', 'T')) {
|
||||
parser->method = HTTP_PUT;
|
||||
break;
|
||||
}
|
||||
|
@ -491,22 +505,22 @@ size_t http_parser_execute (http_parser *parser,
|
|||
break;
|
||||
|
||||
case 4:
|
||||
if (strncmp(parser->buffer, "POST", 4) == 0) {
|
||||
if (ngx_str4cmp(parser->buffer, 'P', 'O', 'S', 'T')) {
|
||||
parser->method = HTTP_POST;
|
||||
break;
|
||||
}
|
||||
|
||||
if (strncmp(parser->buffer, "HEAD", 4) == 0) {
|
||||
if (ngx_str4cmp(parser->buffer, 'H', 'E', 'A', 'D')) {
|
||||
parser->method = HTTP_HEAD;
|
||||
break;
|
||||
}
|
||||
|
||||
if (strncmp(parser->buffer, "COPY", 4) == 0) {
|
||||
if (ngx_str4cmp(parser->buffer, 'C', 'O', 'P', 'Y')) {
|
||||
parser->method = HTTP_COPY;
|
||||
break;
|
||||
}
|
||||
|
||||
if (strncmp(parser->buffer, "MOVE", 4) == 0) {
|
||||
if (ngx_str4cmp(parser->buffer, 'M', 'O', 'V', 'E')) {
|
||||
parser->method = HTTP_MOVE;
|
||||
break;
|
||||
}
|
||||
|
@ -514,12 +528,12 @@ size_t http_parser_execute (http_parser *parser,
|
|||
break;
|
||||
|
||||
case 5:
|
||||
if (strncmp(parser->buffer, "MKCOL", 5) == 0) {
|
||||
if (ngx_str5cmp(parser->buffer, 'M', 'K', 'C', 'O', 'L')) {
|
||||
parser->method = HTTP_MKCOL;
|
||||
break;
|
||||
}
|
||||
|
||||
if (strncmp(parser->buffer, "TRACE", 5) == 0) {
|
||||
if (ngx_str5cmp(parser->buffer, 'T', 'R', 'A', 'C', 'E')) {
|
||||
parser->method = HTTP_TRACE;
|
||||
break;
|
||||
}
|
||||
|
@ -527,12 +541,12 @@ size_t http_parser_execute (http_parser *parser,
|
|||
break;
|
||||
|
||||
case 6:
|
||||
if (strncmp(parser->buffer, "DELETE", 6) == 0) {
|
||||
if (ngx_str6cmp(parser->buffer, 'D', 'E', 'L', 'E', 'T', 'E')) {
|
||||
parser->method = HTTP_DELETE;
|
||||
break;
|
||||
}
|
||||
|
||||
if (strncmp(parser->buffer, "UNLOCK", 6) == 0) {
|
||||
if (ngx_str6cmp(parser->buffer, 'U', 'N', 'L', 'O', 'C', 'K')) {
|
||||
parser->method = HTTP_UNLOCK;
|
||||
break;
|
||||
}
|
||||
|
@ -540,12 +554,14 @@ size_t http_parser_execute (http_parser *parser,
|
|||
break;
|
||||
|
||||
case 7:
|
||||
if (strncmp(parser->buffer, "OPTIONS", 7) == 0) {
|
||||
if (ngx_str7_cmp(parser->buffer,
|
||||
'O', 'P', 'T', 'I', 'O', 'N', 'S', '\0')) {
|
||||
parser->method = HTTP_OPTIONS;
|
||||
break;
|
||||
}
|
||||
|
||||
if (strncmp(parser->buffer, "CONNECT", 7) == 0) {
|
||||
if (ngx_str7_cmp(parser->buffer,
|
||||
'C', 'O', 'N', 'N', 'E', 'C', 'T', '\0')) {
|
||||
parser->method = HTTP_CONNECT;
|
||||
break;
|
||||
}
|
||||
|
@ -553,7 +569,8 @@ size_t http_parser_execute (http_parser *parser,
|
|||
break;
|
||||
|
||||
case 8:
|
||||
if (strncmp(parser->buffer, "PROPFIND", 8) == 0) {
|
||||
if (ngx_str8cmp(parser->buffer,
|
||||
'P', 'R', 'O', 'P', 'F', 'I', 'N', 'D')) {
|
||||
parser->method = HTTP_PROPFIND;
|
||||
break;
|
||||
}
|
||||
|
@ -561,7 +578,8 @@ size_t http_parser_execute (http_parser *parser,
|
|||
break;
|
||||
|
||||
case 9:
|
||||
if (strncmp(parser->buffer, "PROPPATCH", 9) == 0) {
|
||||
if (ngx_str9cmp(parser->buffer,
|
||||
'P', 'R', 'O', 'P', 'P', 'A', 'T', 'C', 'H')) {
|
||||
parser->method = HTTP_PROPPATCH;
|
||||
break;
|
||||
}
|
||||
|
@ -1311,7 +1329,7 @@ size_t http_parser_execute (http_parser *parser,
|
|||
case s_body_identity:
|
||||
to_read = MIN(pe - p, (ssize_t)(parser->content_length - parser->body_read));
|
||||
if (to_read > 0) {
|
||||
if (parser->on_body) parser->on_body(parser, p, to_read);
|
||||
if (settings.on_body) settings.on_body(parser, p, to_read);
|
||||
p += to_read - 1;
|
||||
parser->body_read += to_read;
|
||||
if (parser->body_read == parser->content_length) {
|
||||
|
@ -1325,7 +1343,7 @@ size_t http_parser_execute (http_parser *parser,
|
|||
case s_body_identity_eof:
|
||||
to_read = pe - p;
|
||||
if (to_read > 0) {
|
||||
if (parser->on_body) parser->on_body(parser, p, to_read);
|
||||
if (settings.on_body) settings.on_body(parser, p, to_read);
|
||||
p += to_read - 1;
|
||||
parser->body_read += to_read;
|
||||
}
|
||||
|
@ -1398,7 +1416,7 @@ size_t http_parser_execute (http_parser *parser,
|
|||
to_read = MIN(pe - p, (ssize_t)(parser->content_length));
|
||||
|
||||
if (to_read > 0) {
|
||||
if (parser->on_body) parser->on_body(parser, p, to_read);
|
||||
if (settings.on_body) settings.on_body(parser, p, to_read);
|
||||
p += to_read - 1;
|
||||
}
|
||||
|
||||
|
@ -1475,17 +1493,6 @@ http_parser_init (http_parser *parser, enum http_parser_type t)
|
|||
parser->state = (t == HTTP_REQUEST ? s_start_req : s_start_res);
|
||||
parser->nread = 0;
|
||||
|
||||
parser->on_message_begin = NULL;
|
||||
parser->on_path = NULL;
|
||||
parser->on_query_string = NULL;
|
||||
parser->on_url = NULL;
|
||||
parser->on_fragment = NULL;
|
||||
parser->on_header_field = NULL;
|
||||
parser->on_header_value = NULL;
|
||||
parser->on_headers_complete = NULL;
|
||||
parser->on_body = NULL;
|
||||
parser->on_message_complete = NULL;
|
||||
|
||||
parser->header_field_mark = NULL;
|
||||
parser->header_value_mark = NULL;
|
||||
parser->query_string_mark = NULL;
|
||||
|
|
|
@ -24,11 +24,10 @@
|
|||
extern "C" {
|
||||
#endif
|
||||
|
||||
#ifdef _MSC_VER
|
||||
# include <stddef.h>
|
||||
#endif
|
||||
|
||||
#include <sys/types.h>
|
||||
|
||||
|
||||
/* Compile with -DHTTP_PARSER_STRICT=0 to make less checks, but run
|
||||
* faster
|
||||
*/
|
||||
|
@ -38,12 +37,16 @@ extern "C" {
|
|||
# define HTTP_PARSER_STRICT 0
|
||||
#endif
|
||||
|
||||
|
||||
/* Maximium header size allowed */
|
||||
#define HTTP_MAX_HEADER_SIZE (80*1024)
|
||||
|
||||
typedef struct http_parser http_parser;
|
||||
|
||||
/* Callbacks should return non-zero to indicate an error. The parse will
|
||||
typedef struct http_parser http_parser;
|
||||
typedef struct http_parser_settings http_parser_settings;
|
||||
|
||||
|
||||
/* Callbacks should return non-zero to indicate an error. The parser will
|
||||
* then halt execution.
|
||||
*
|
||||
* http_data_cb does not return data chunks. It will be call arbitrarally
|
||||
|
@ -53,9 +56,11 @@ typedef struct http_parser http_parser;
|
|||
typedef int (*http_data_cb) (http_parser*, const char *at, size_t length);
|
||||
typedef int (*http_cb) (http_parser*);
|
||||
|
||||
|
||||
/* Should be at least one longer than the longest request method */
|
||||
#define HTTP_PARSER_MAX_METHOD_LEN 10
|
||||
|
||||
|
||||
/* Request Methods */
|
||||
enum http_method
|
||||
{ HTTP_DELETE = 0x0001
|
||||
|
@ -77,8 +82,10 @@ enum http_method
|
|||
, HTTP_UNLOCK = 0x4000
|
||||
};
|
||||
|
||||
|
||||
enum http_parser_type { HTTP_REQUEST, HTTP_RESPONSE };
|
||||
|
||||
|
||||
struct http_parser {
|
||||
/** PRIVATE **/
|
||||
enum http_parser_type type;
|
||||
|
@ -114,17 +121,15 @@ struct http_parser {
|
|||
|
||||
/** PUBLIC **/
|
||||
void *data; /* A pointer to get hook to the "connection" or "socket" object */
|
||||
};
|
||||
|
||||
/* an ordered list of callbacks */
|
||||
|
||||
struct http_parser_settings {
|
||||
http_cb on_message_begin;
|
||||
|
||||
/* requests only */
|
||||
http_data_cb on_path;
|
||||
http_data_cb on_query_string;
|
||||
http_data_cb on_url;
|
||||
http_data_cb on_fragment;
|
||||
|
||||
http_data_cb on_header_field;
|
||||
http_data_cb on_header_value;
|
||||
http_cb on_headers_complete;
|
||||
|
@ -132,15 +137,25 @@ struct http_parser {
|
|||
http_cb on_message_complete;
|
||||
};
|
||||
|
||||
|
||||
void http_parser_init(http_parser *parser, enum http_parser_type type);
|
||||
size_t http_parser_execute(http_parser *parser, const char *data, size_t len);
|
||||
/* Call this in the on_headers_complete or on_message_complete callback to
|
||||
* determine if this will be the last message on the connection.
|
||||
* If you are the server, respond with the "Connection: close" header
|
||||
* if you are the client, close the connection.
|
||||
|
||||
|
||||
size_t http_parser_execute(http_parser *parser,
|
||||
http_parser_settings settings,
|
||||
const char *data,
|
||||
size_t len);
|
||||
|
||||
|
||||
/* If http_should_keep_alive() in the on_headers_complete or
|
||||
* on_message_complete callback returns true, then this will be should be
|
||||
* the last message on the connection.
|
||||
* If you are the server, respond with the "Connection: close" header.
|
||||
* If you are the client, close the connection.
|
||||
*/
|
||||
int http_should_keep_alive(http_parser *parser);
|
||||
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
|
|
@ -63,14 +63,6 @@ struct message {
|
|||
|
||||
static int currently_parsing_eof;
|
||||
|
||||
inline size_t parse (const char *buf, size_t len)
|
||||
{
|
||||
size_t nparsed;
|
||||
currently_parsing_eof = (len == 0);
|
||||
nparsed = http_parser_execute(parser, buf, len);
|
||||
return nparsed;
|
||||
}
|
||||
|
||||
static struct message messages[5];
|
||||
static int num_messages;
|
||||
|
||||
|
@ -802,6 +794,19 @@ message_complete_cb (http_parser *p)
|
|||
return 0;
|
||||
}
|
||||
|
||||
static http_parser_settings settings =
|
||||
{.on_message_begin = message_begin_cb
|
||||
,.on_header_field = header_field_cb
|
||||
,.on_header_value = header_value_cb
|
||||
,.on_path = request_path_cb
|
||||
,.on_url = request_url_cb
|
||||
,.on_fragment = fragment_cb
|
||||
,.on_query_string = query_string_cb
|
||||
,.on_body = body_cb
|
||||
,.on_headers_complete = headers_complete_cb
|
||||
,.on_message_complete = message_complete_cb
|
||||
};
|
||||
|
||||
void
|
||||
parser_init (enum http_parser_type type)
|
||||
{
|
||||
|
@ -815,16 +820,6 @@ parser_init (enum http_parser_type type)
|
|||
|
||||
memset(&messages, 0, sizeof messages);
|
||||
|
||||
parser->on_message_begin = message_begin_cb;
|
||||
parser->on_header_field = header_field_cb;
|
||||
parser->on_header_value = header_value_cb;
|
||||
parser->on_path = request_path_cb;
|
||||
parser->on_url = request_url_cb;
|
||||
parser->on_fragment = fragment_cb;
|
||||
parser->on_query_string = query_string_cb;
|
||||
parser->on_body = body_cb;
|
||||
parser->on_headers_complete = headers_complete_cb;
|
||||
parser->on_message_complete = message_complete_cb;
|
||||
}
|
||||
|
||||
void
|
||||
|
@ -835,6 +830,14 @@ parser_free ()
|
|||
parser = NULL;
|
||||
}
|
||||
|
||||
inline size_t parse (const char *buf, size_t len)
|
||||
{
|
||||
size_t nparsed;
|
||||
currently_parsing_eof = (len == 0);
|
||||
nparsed = http_parser_execute(parser, settings, buf, len);
|
||||
return nparsed;
|
||||
}
|
||||
|
||||
static inline int
|
||||
check_str_eq (const struct message *m,
|
||||
const char *prop,
|
||||
|
@ -950,7 +953,7 @@ print_error (const char *raw, size_t error_location)
|
|||
for (j = 0; j < error_location_line; j++) {
|
||||
fputc(' ', stderr);
|
||||
}
|
||||
fprintf(stderr, "^\n\nerror location: %d\n", error_location);
|
||||
fprintf(stderr, "^\n\nerror location: %u\n", (unsigned int)error_location);
|
||||
}
|
||||
|
||||
|
||||
|
@ -1142,9 +1145,9 @@ test_scan (const struct message *r1, const struct message *r2, const struct mess
|
|||
|
||||
error:
|
||||
fprintf(stderr, "i=%d j=%d\n", i, j);
|
||||
fprintf(stderr, "buf1 (%d) %s\n\n", buf1_len, buf1);
|
||||
fprintf(stderr, "buf2 (%d) %s\n\n", buf2_len , buf2);
|
||||
fprintf(stderr, "buf3 (%d) %s\n", buf3_len, buf3);
|
||||
fprintf(stderr, "buf1 (%u) %s\n\n", (unsigned int)buf1_len, buf1);
|
||||
fprintf(stderr, "buf2 (%u) %s\n\n", (unsigned int)buf2_len , buf2);
|
||||
fprintf(stderr, "buf3 (%u) %s\n", (unsigned int)buf3_len, buf3);
|
||||
exit(1);
|
||||
}
|
||||
|
||||
|
@ -1156,7 +1159,7 @@ main (void)
|
|||
int request_count;
|
||||
int response_count;
|
||||
|
||||
printf("sizeof(http_parser) = %d\n", sizeof(http_parser));
|
||||
printf("sizeof(http_parser) = %u\n", (unsigned int)sizeof(http_parser));
|
||||
|
||||
for (request_count = 0; requests[request_count].name; request_count++);
|
||||
for (response_count = 0; responses[response_count].name; response_count++);
|
||||
|
|
|
@ -46,6 +46,8 @@ static Persistent<String> proppatch_sym;
|
|||
static Persistent<String> unlock_sym;
|
||||
static Persistent<String> unknown_method_sym;
|
||||
|
||||
static struct http_parser_settings settings;
|
||||
|
||||
void
|
||||
HTTPConnection::Initialize (Handle<Object> target)
|
||||
{
|
||||
|
@ -68,6 +70,16 @@ HTTPConnection::Initialize (Handle<Object> target)
|
|||
|
||||
end_symbol = NODE_PSYMBOL("end");
|
||||
|
||||
settings.on_message_begin = on_message_begin;
|
||||
settings.on_path = on_path;
|
||||
settings.on_query_string = on_query_string;
|
||||
settings.on_url = on_url;
|
||||
settings.on_fragment = on_fragment;
|
||||
settings.on_header_field = on_header_field;
|
||||
settings.on_header_value = on_header_value;
|
||||
settings.on_headers_complete = on_headers_complete;
|
||||
settings.on_body = on_body;
|
||||
settings.on_message_complete = on_message_complete;
|
||||
}
|
||||
|
||||
Handle<Value>
|
||||
|
@ -109,7 +121,7 @@ HTTPConnection::OnReceive (const void *buf, size_t len)
|
|||
assert(refs_);
|
||||
size_t nparsed;
|
||||
|
||||
nparsed = http_parser_execute(&parser_, static_cast<const char*>(buf), len);
|
||||
nparsed = http_parser_execute(&parser_, settings, static_cast<const char*>(buf), len);
|
||||
|
||||
if (nparsed != len) {
|
||||
ForceClose();
|
||||
|
@ -122,7 +134,7 @@ HTTPConnection::OnEOF ()
|
|||
HandleScope scope;
|
||||
assert(refs_);
|
||||
size_t nparsed;
|
||||
nparsed = http_parser_execute(&parser_, NULL, 0);
|
||||
nparsed = http_parser_execute(&parser_, settings, NULL, 0);
|
||||
Emit(end_symbol, 0, NULL);
|
||||
}
|
||||
|
||||
|
|
|
@ -28,16 +28,6 @@ protected:
|
|||
|
||||
void ResetParser() {
|
||||
http_parser_init (&parser_, type_);
|
||||
parser_.on_message_begin = on_message_begin;
|
||||
parser_.on_url = on_url;
|
||||
parser_.on_path = on_path;
|
||||
parser_.on_fragment = on_fragment;
|
||||
parser_.on_query_string = on_query_string;
|
||||
parser_.on_header_field = on_header_field;
|
||||
parser_.on_header_value = on_header_value;
|
||||
parser_.on_headers_complete = on_headers_complete;
|
||||
parser_.on_body = on_body;
|
||||
parser_.on_message_complete = on_message_complete;
|
||||
parser_.data = this;
|
||||
}
|
||||
|
||||
|
|
|
@ -27,8 +27,6 @@ namespace node {
|
|||
|
||||
using namespace v8;
|
||||
|
||||
static int deep = 0;
|
||||
|
||||
static Persistent<String> on_message_begin_sym;
|
||||
static Persistent<String> on_path_sym;
|
||||
static Persistent<String> on_query_string_sym;
|
||||
|
@ -64,6 +62,8 @@ static Persistent<String> version_major_sym;
|
|||
static Persistent<String> version_minor_sym;
|
||||
static Persistent<String> should_keep_alive_sym;
|
||||
|
||||
static struct http_parser_settings settings;
|
||||
|
||||
// Callback prototype for http_cb
|
||||
#define DEFINE_HTTP_CB(name) \
|
||||
static int name(http_parser *p) { \
|
||||
|
@ -231,7 +231,7 @@ class Parser : public ObjectWrap {
|
|||
parser->buffer_ = buffer;
|
||||
|
||||
size_t nparsed =
|
||||
http_parser_execute(&parser->parser_, buffer->data()+off, len);
|
||||
http_parser_execute(&parser->parser_, settings, buffer->data()+off, len);
|
||||
|
||||
// Unassign the 'buffer_' variable
|
||||
assert(parser->buffer_);
|
||||
|
@ -261,7 +261,7 @@ class Parser : public ObjectWrap {
|
|||
|
||||
assert(!parser->buffer_);
|
||||
|
||||
http_parser_execute(&(parser->parser_), NULL, 0);
|
||||
http_parser_execute(&(parser->parser_), settings, NULL, 0);
|
||||
|
||||
return Undefined();
|
||||
}
|
||||
|
@ -290,17 +290,6 @@ class Parser : public ObjectWrap {
|
|||
assert(buffer_ == NULL); // don't call this during Execute()
|
||||
http_parser_init(&parser_, type);
|
||||
|
||||
parser_.on_message_begin = on_message_begin;
|
||||
parser_.on_path = on_path;
|
||||
parser_.on_query_string = on_query_string;
|
||||
parser_.on_url = on_url;
|
||||
parser_.on_fragment = on_fragment;
|
||||
parser_.on_header_field = on_header_field;
|
||||
parser_.on_header_value = on_header_value;
|
||||
parser_.on_headers_complete = on_headers_complete;
|
||||
parser_.on_body = on_body;
|
||||
parser_.on_message_complete = on_message_complete;
|
||||
|
||||
parser_.data = this;
|
||||
}
|
||||
|
||||
|
@ -356,6 +345,17 @@ void InitHttpParser(Handle<Object> target) {
|
|||
version_major_sym = NODE_PSYMBOL("versionMajor");
|
||||
version_minor_sym = NODE_PSYMBOL("versionMinor");
|
||||
should_keep_alive_sym = NODE_PSYMBOL("shouldKeepAlive");
|
||||
|
||||
settings.on_message_begin = Parser::on_message_begin;
|
||||
settings.on_path = Parser::on_path;
|
||||
settings.on_query_string = Parser::on_query_string;
|
||||
settings.on_url = Parser::on_url;
|
||||
settings.on_fragment = Parser::on_fragment;
|
||||
settings.on_header_field = Parser::on_header_field;
|
||||
settings.on_header_value = Parser::on_header_value;
|
||||
settings.on_headers_complete = Parser::on_headers_complete;
|
||||
settings.on_body = Parser::on_body;
|
||||
settings.on_message_complete = Parser::on_message_complete;
|
||||
}
|
||||
|
||||
} // namespace node
|
||||
|
|
Загрузка…
Ссылка в новой задаче