33 # define ULLONG_MAX ((uint64_t) -1)
37 # define MIN(a,b) ((a) < (b) ? (a) : (b))
41 # define ARRAY_SIZE(a) (sizeof(a) / sizeof((a)[0]))
45 # define BIT_AT(a, i) \
46 (!!((unsigned int) (a)[(unsigned int) (i) >> 3] & \
47 (1 << ((unsigned int) (i) & 7))))
51 # define ELEM_AT(a, i, v) ((unsigned int) (i) < ARRAY_SIZE(a) ? (a)[(i)] : (v))
54 #define SET_ERRNO(e) \
56 parser->http_errno = (e); \
59 #define CURRENT_STATE() p_state
60 #define UPDATE_STATE(V) p_state = (enum state) (V);
63 parser->state = CURRENT_STATE(); \
71 # define LIKELY(X) __builtin_expect(!!(X), 1)
72 # define UNLIKELY(X) __builtin_expect(!!(X), 0)
74 # define LIKELY(X) (X)
75 # define UNLIKELY(X) (X)
80 #define CALLBACK_NOTIFY_(FOR, ER) \
82 assert(HTTP_PARSER_ERRNO(parser) == HPE_OK); \
84 if (LIKELY(settings->on_##FOR)) { \
85 parser->state = CURRENT_STATE(); \
86 if (UNLIKELY(0 != settings->on_##FOR(parser))) { \
87 SET_ERRNO(HPE_CB_##FOR); \
89 UPDATE_STATE(parser->state); \
92 if (UNLIKELY(HTTP_PARSER_ERRNO(parser) != HPE_OK)) { \
99 #define CALLBACK_NOTIFY(FOR) CALLBACK_NOTIFY_(FOR, p - data + 1)
102 #define CALLBACK_NOTIFY_NOADVANCE(FOR) CALLBACK_NOTIFY_(FOR, p - data)
105 #define CALLBACK_DATA_(FOR, LEN, ER) \
107 assert(HTTP_PARSER_ERRNO(parser) == HPE_OK); \
110 if (LIKELY(settings->on_##FOR)) { \
111 parser->state = CURRENT_STATE(); \
113 settings->on_##FOR(parser, FOR##_mark, (LEN)))) { \
114 SET_ERRNO(HPE_CB_##FOR); \
116 UPDATE_STATE(parser->state); \
119 if (UNLIKELY(HTTP_PARSER_ERRNO(parser) != HPE_OK)) { \
128 #define CALLBACK_DATA(FOR) \
129 CALLBACK_DATA_(FOR, p - FOR##_mark, p - data + 1)
132 #define CALLBACK_DATA_NOADVANCE(FOR) \
133 CALLBACK_DATA_(FOR, p - FOR##_mark, p - data)
154 #define COUNT_HEADER_SIZE(V) \
156 parser->nread += (V); \
157 if (UNLIKELY(parser->nread > (HTTP_MAX_HEADER_SIZE))) { \
158 SET_ERRNO(HPE_HEADER_OVERFLOW); \
164 #define PROXY_CONNECTION "proxy-connection"
165 #define CONNECTION "connection"
166 #define CONTENT_LENGTH "content-length"
167 #define TRANSFER_ENCODING "transfer-encoding"
168 #define UPGRADE "upgrade"
169 #define CHUNKED "chunked"
170 #define KEEP_ALIVE "keep-alive"
171 #define CLOSE "close"
176 #define XX(num, name, string) #string,
191 0, 0, 0, 0, 0, 0, 0, 0,
193 0, 0, 0, 0, 0, 0, 0, 0,
195 0, 0, 0, 0, 0, 0, 0, 0,
197 0, 0, 0, 0, 0, 0, 0, 0,
199 0,
'!', 0,
'#',
'$',
'%',
'&',
'\'',
201 0, 0,
'*',
'+', 0,
'-',
'.', 0,
203 '0',
'1',
'2',
'3',
'4',
'5',
'6',
'7',
205 '8',
'9', 0, 0, 0, 0, 0, 0,
207 0,
'a',
'b',
'c',
'd',
'e',
'f',
'g',
209 'h',
'i',
'j',
'k',
'l',
'm',
'n',
'o',
211 'p',
'q',
'r',
's',
't',
'u',
'v',
'w',
213 'x',
'y',
'z', 0, 0, 0,
'^',
'_',
215 '`',
'a',
'b',
'c',
'd',
'e',
'f',
'g',
217 'h',
'i',
'j',
'k',
'l',
'm',
'n',
'o',
219 'p',
'q',
'r',
's',
't',
'u',
'v',
'w',
221 'x',
'y',
'z', 0,
'|', 0,
'~', 0 };
225 {-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1
226 ,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1
227 ,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1
228 , 0, 1, 2, 3, 4, 5, 6, 7, 8, 9,-1,-1,-1,-1,-1,-1
229 ,-1,10,11,12,13,14,15,-1,-1,-1,-1,-1,-1,-1,-1,-1
230 ,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1
231 ,-1,10,11,12,13,14,15,-1,-1,-1,-1,-1,-1,-1,-1,-1
232 ,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1
236 #if HTTP_PARSER_STRICT
245 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0,
247 0 |
T(2) | 0 | 0 |
T(16) | 0 | 0 | 0,
249 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0,
251 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0,
253 0 | 2 | 4 | 0 | 16 | 32 | 64 | 128,
255 1 | 2 | 4 | 8 | 16 | 32 | 64 | 128,
257 1 | 2 | 4 | 8 | 16 | 32 | 64 | 128,
259 1 | 2 | 4 | 8 | 16 | 32 | 64 | 0,
261 1 | 2 | 4 | 8 | 16 | 32 | 64 | 128,
263 1 | 2 | 4 | 8 | 16 | 32 | 64 | 128,
265 1 | 2 | 4 | 8 | 16 | 32 | 64 | 128,
267 1 | 2 | 4 | 8 | 16 | 32 | 64 | 128,
269 1 | 2 | 4 | 8 | 16 | 32 | 64 | 128,
271 1 | 2 | 4 | 8 | 16 | 32 | 64 | 128,
273 1 | 2 | 4 | 8 | 16 | 32 | 64 | 128,
275 1 | 2 | 4 | 8 | 16 | 32 | 64 | 0, };
360 #define PARSING_HEADER(state) (state <= s_headers_done)
410 #define LOWER(c) (unsigned char)(c | 0x20)
411 #define IS_ALPHA(c) (LOWER(c) >= 'a' && LOWER(c) <= 'z')
412 #define IS_NUM(c) ((c) >= '0' && (c) <= '9')
413 #define IS_ALPHANUM(c) (IS_ALPHA(c) || IS_NUM(c))
414 #define IS_HEX(c) (IS_NUM(c) || (LOWER(c) >= 'a' && LOWER(c) <= 'f'))
415 #define IS_MARK(c) ((c) == '-' || (c) == '_' || (c) == '.' || \
416 (c) == '!' || (c) == '~' || (c) == '*' || (c) == '\'' || (c) == '(' || \
418 #define IS_USERINFO_CHAR(c) (IS_ALPHANUM(c) || IS_MARK(c) || (c) == '%' || \
419 (c) == ';' || (c) == ':' || (c) == '&' || (c) == '=' || (c) == '+' || \
420 (c) == '$' || (c) == ',')
422 #define STRICT_TOKEN(c) (tokens[(unsigned char)c])
424 #if HTTP_PARSER_STRICT
425 #define TOKEN(c) (tokens[(unsigned char)c])
426 #define IS_URL_CHAR(c) (BIT_AT(normal_url_char, (unsigned char)c))
427 #define IS_HOST_CHAR(c) (IS_ALPHANUM(c) || (c) == '.' || (c) == '-')
429 #define TOKEN(c) ((c == ' ') ? ' ' : tokens[(unsigned char)c])
430 #define IS_URL_CHAR(c) \
431 (BIT_AT(normal_url_char, (unsigned char)c) || ((c) & 0x80))
432 #define IS_HOST_CHAR(c) \
433 (IS_ALPHANUM(c) || (c) == '.' || (c) == '-' || (c) == '_')
437 #define start_state (parser->type == HTTP_REQUEST ? s_start_req : s_start_res)
440 #if HTTP_PARSER_STRICT
441 # define STRICT_CHECK(cond) \
444 SET_ERRNO(HPE_STRICT); \
448 # define NEW_MESSAGE() (http_should_keep_alive(parser) ? start_state : s_dead)
450 # define STRICT_CHECK(cond)
451 # define NEW_MESSAGE() start_state
456 #define HTTP_STRERROR_GEN(n, s) { "HPE_" #n, s },
463 #undef HTTP_STRERROR_GEN
481 if (ch ==
' ' || ch ==
'\r' || ch ==
'\n') {
485 #if HTTP_PARSER_STRICT
486 if (ch ==
'\t' || ch ==
'\f') {
497 if (ch ==
'/' || ch ==
'*') {
633 const char *p = data;
634 const char *header_field_mark = 0;
635 const char *header_value_mark = 0;
636 const char *url_mark = 0;
637 const char *body_mark = 0;
638 const char *status_mark = 0;
669 header_field_mark = data;
671 header_value_mark = data;
693 for (p=data; p != data + len; p++) {
714 if (ch ==
CR || ch ==
LF)
743 parser->
method = HTTP_HEAD;
793 if (
UNLIKELY(ch < '0' || ch >
'9')) {
947 if (ch ==
CR || ch ==
LF)
960 case 'C': parser->
method = HTTP_CONNECT;
break;
961 case 'D': parser->
method = HTTP_DELETE;
break;
962 case 'G': parser->
method = HTTP_GET;
break;
963 case 'H': parser->
method = HTTP_HEAD;
break;
964 case 'L': parser->
method = HTTP_LOCK;
break;
965 case 'M': parser->
method = HTTP_MKCOL;
break;
966 case 'N': parser->
method = HTTP_NOTIFY;
break;
967 case 'O': parser->
method = HTTP_OPTIONS;
break;
968 case 'P': parser->
method = HTTP_POST;
971 case 'R': parser->
method = HTTP_REPORT;
break;
972 case 'S': parser->
method = HTTP_SUBSCRIBE;
break;
973 case 'T': parser->
method = HTTP_TRACE;
break;
974 case 'U': parser->
method = HTTP_UNLOCK;
break;
995 if (ch ==
' ' && matcher[parser->
index] ==
'\0') {
997 }
else if (ch == matcher[parser->
index]) {
999 }
else if (parser->
method == HTTP_CONNECT) {
1000 if (parser->
index == 1 && ch ==
'H') {
1001 parser->
method = HTTP_CHECKOUT;
1002 }
else if (parser->
index == 2 && ch ==
'P') {
1003 parser->
method = HTTP_COPY;
1008 }
else if (parser->
method == HTTP_MKCOL) {
1009 if (parser->
index == 1 && ch ==
'O') {
1010 parser->
method = HTTP_MOVE;
1011 }
else if (parser->
index == 1 && ch ==
'E') {
1012 parser->
method = HTTP_MERGE;
1013 }
else if (parser->
index == 1 && ch ==
'-') {
1014 parser->
method = HTTP_MSEARCH;
1015 }
else if (parser->
index == 2 && ch ==
'A') {
1016 parser->
method = HTTP_MKACTIVITY;
1017 }
else if (parser->
index == 3 && ch ==
'A') {
1018 parser->
method = HTTP_MKCALENDAR;
1023 }
else if (parser->
method == HTTP_SUBSCRIBE) {
1024 if (parser->
index == 1 && ch ==
'E') {
1025 parser->
method = HTTP_SEARCH;
1030 }
else if (parser->
index == 1 && parser->
method == HTTP_POST) {
1032 parser->
method = HTTP_PROPFIND;
1033 }
else if (ch ==
'U') {
1034 parser->
method = HTTP_PUT;
1035 }
else if (ch ==
'A') {
1036 parser->
method = HTTP_PATCH;
1041 }
else if (parser->
index == 2) {
1042 if (parser->
method == HTTP_PUT) {
1044 parser->
method = HTTP_PURGE;
1049 }
else if (parser->
method == HTTP_UNLOCK) {
1051 parser->
method = HTTP_UNSUBSCRIBE;
1060 }
else if (parser->
index == 4 && parser->
method == HTTP_PROPFIND && ch ==
'P') {
1061 parser->
method = HTTP_PROPPATCH;
1073 if (ch ==
' ')
break;
1076 if (parser->
method == HTTP_CONNECT) {
1179 if (
UNLIKELY(ch < '1' || ch >
'9')) {
1318 const char* start = p;
1319 for (; p != data + len; p++) {
1423 assert(0 &&
"Unknown header_state");
1430 if (p == data + len) {
1446 if (ch ==
' ' || ch ==
'\t')
break;
1498 }
else if (c ==
'c') {
1500 }
else if (c ==
'u') {
1520 const char* start = p;
1522 for (; p != data + len; p++) {
1546 size_t limit = data + len - p;
1550 p_cr = (
const char*) memchr(p,
CR, limit);
1551 p_lf = (
const char*) memchr(p,
LF, limit);
1553 if (p_lf != NULL && p_cr >= p_lf)
1557 }
else if (
UNLIKELY(p_lf != NULL)) {
1569 assert(0 &&
"Shouldn't get here.");
1576 if (ch ==
' ')
break;
1615 }
else if (c ==
'c') {
1617 }
else if (c ==
'u') {
1621 }
else if (c ==
' ' || c ==
'\t') {
1644 }
else if (parser->
index ==
sizeof(
CLOSE)-2) {
1684 }
else if (ch !=
' ') {
1699 if (p == data + len)
1714 if (ch ==
' ' || ch ==
'\t') {
1750 if (ch ==
' ' || ch ==
'\t') {
1796 parser->
method == HTTP_CONNECT);
1878 (uint64_t) ((data + len) - p));
1929 assert(parser->
nread == 1);
1932 unhex_val =
unhex[(
unsigned char)ch];
1954 unhex_val =
unhex[(
unsigned char)ch];
1956 if (unhex_val == -1) {
1957 if (ch ==
';' || ch ==
' ') {
2011 (uint64_t) ((data + len) - p));
2048 assert(0 &&
"unhandled state");
2064 assert(((header_field_mark ? 1 : 0) +
2065 (header_value_mark ? 1 : 0) +
2066 (url_mark ? 1 : 0) +
2067 (body_mark ? 1 : 0) +
2068 (status_mark ? 1 : 0)) <= 1);
2140 void *data = parser->
data;
2141 memset(parser, 0,
sizeof(*parser));
2142 parser->
data = data;
2151 memset(settings, 0,
sizeof(*settings));
2156 assert(((
size_t) err) <
2163 assert(((
size_t) err) <
2213 if (
IS_HEX(ch) || ch ==
':' || ch ==
'.') {
2319 for (p = buf; p < buf + buflen; p++) {
2361 assert(!
"Unexpected state");
2400 u->
port = (uint16_t) v;
2414 SET_ERRNO((paused) ? HPE_PAUSED : HPE_OK);
2416 assert(0 &&
"Attempting to pause parser in error state");
static const int8_t unhex[256]
static const uint8_t normal_url_char[32]
#define HTTP_MAX_HEADER_SIZE
static int http_parse_host(const char *buf, struct http_parser_url *u, int found_at)
#define HTTP_ERRNO_MAP(XX)
#define CALLBACK_NOTIFY_NOADVANCE(FOR)
const char * http_errno_name(enum http_errno err)
#define CALLBACK_DATA_NOADVANCE(FOR)
http_cb on_headers_complete
unsigned short http_minor
#define HTTP_PARSER_VERSION_MAJOR
#define PARSING_HEADER(state)
#define HTTP_METHOD_MAP(XX)
size_t http_parser_execute(http_parser *parser, const http_parser_settings *settings, const char *data, size_t len)
#define CALLBACK_DATA(FOR)
void http_parser_settings_init(http_parser_settings *settings)
unsigned int header_state
#define HTTP_PARSER_VERSION_PATCH
#define TRANSFER_ENCODING
#define HTTP_STRERROR_GEN(n, s)
const char * http_method_str(enum http_method m)
void http_parser_pause(http_parser *parser, int paused)
#define HTTP_PARSER_ERRNO(p)
static const char * method_strings[]
int http_parser_parse_url(const char *buf, size_t buflen, int is_connect, struct http_parser_url *u)
int http_should_keep_alive(const http_parser *parser)
#define HTTP_PARSER_VERSION_MINOR
int http_body_is_final(const struct http_parser *parser)
const char * http_errno_description(enum http_errno err)
unsigned short http_major
READ-ONLY.
#define COUNT_HEADER_SIZE(V)
#define CALLBACK_NOTIFY(FOR)
int http_message_needs_eof(const http_parser *parser)
struct http_parser_url::@3 field_data[UF_MAX]
void http_parser_init(http_parser *parser, enum http_parser_type t)
#define XX(num, name, string)
unsigned long http_parser_version(void)
static enum state parse_url_char(enum state s, const char ch)
static struct @2 http_strerror_tab[]
#define IS_USERINFO_CHAR(c)
#define STRICT_CHECK(cond)
#define CALLBACK_DATA_(FOR, LEN, ER)
unsigned int type
PRIVATE.
static const char tokens[256]
static enum http_host_state http_parse_host_char(enum http_host_state s, const char ch)