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,
189 static const char tokens[256] = {
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 };
224 static const int8_t
unhex[256] =
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)
412 #define LOWER(c) (unsigned char)(c | 0x20)
413 #define IS_ALPHA(c) (LOWER(c) >= 'a' && LOWER(c) <= 'z')
414 #define IS_NUM(c) ((c) >= '0' && (c) <= '9')
415 #define IS_ALPHANUM(c) (IS_ALPHA(c) || IS_NUM(c))
416 #define IS_HEX(c) (IS_NUM(c) || (LOWER(c) >= 'a' && LOWER(c) <= 'f'))
417 #define IS_MARK(c) ((c) == '-' || (c) == '_' || (c) == '.' || \
418 (c) == '!' || (c) == '~' || (c) == '*' || (c) == '\'' || (c) == '(' || \
420 #define IS_USERINFO_CHAR(c) (IS_ALPHANUM(c) || IS_MARK(c) || (c) == '%' || \
421 (c) == ';' || (c) == ':' || (c) == '&' || (c) == '=' || (c) == '+' || \
422 (c) == '$' || (c) == ',')
424 #define STRICT_TOKEN(c) (tokens[(unsigned char)c])
426 #if HTTP_PARSER_STRICT
427 #define TOKEN(c) (tokens[(unsigned char)c])
428 #define IS_URL_CHAR(c) (BIT_AT(normal_url_char, (unsigned char)c))
429 #define IS_HOST_CHAR(c) (IS_ALPHANUM(c) || (c) == '.' || (c) == '-')
431 #define TOKEN(c) ((c == ' ') ? ' ' : tokens[(unsigned char)c])
432 #define IS_URL_CHAR(c) \
433 (BIT_AT(normal_url_char, (unsigned char)c) || ((c) & 0x80))
434 #define IS_HOST_CHAR(c) \
435 (IS_ALPHANUM(c) || (c) == '.' || (c) == '-' || (c) == '_')
442 #define IS_HEADER_CHAR(ch) \
443 (ch == CR || ch == LF || ch == 9 || ((unsigned char)ch > 31 && ch != 127))
445 #define start_state (parser->type == HTTP_REQUEST ? s_start_req : s_start_res)
448 #if HTTP_PARSER_STRICT
449 # define STRICT_CHECK(cond) \
452 SET_ERRNO(HPE_STRICT); \
456 # define NEW_MESSAGE() (http_should_keep_alive(parser) ? start_state : s_dead)
458 # define STRICT_CHECK(cond)
459 # define NEW_MESSAGE() start_state
464 #define HTTP_STRERROR_GEN(n, s) { "HPE_" #n, s },
471 #undef HTTP_STRERROR_GEN
489 if (ch ==
' ' || ch ==
'\r' || ch ==
'\n') {
493 #if HTTP_PARSER_STRICT
494 if (ch ==
'\t' || ch ==
'\f') {
505 if (ch ==
'/' || ch ==
'*') {
641 const char *p = data;
642 const char *header_field_mark = 0;
643 const char *header_value_mark = 0;
644 const char *url_mark = 0;
645 const char *body_mark = 0;
646 const char *status_mark = 0;
678 header_field_mark = data;
680 header_value_mark = data;
702 for (p=data; p != data + len; p++) {
723 if (ch ==
CR || ch ==
LF)
752 parser->
method = HTTP_HEAD;
894 if (ch ==
CR || ch ==
LF)
922 if (ch ==
CR || ch ==
LF)
935 case 'A': parser->
method = HTTP_ACL;
break;
936 case 'B': parser->
method = HTTP_BIND;
break;
937 case 'C': parser->
method = HTTP_CONNECT;
break;
938 case 'D': parser->
method = HTTP_DELETE;
break;
939 case 'G': parser->
method = HTTP_GET;
break;
940 case 'H': parser->
method = HTTP_HEAD;
break;
941 case 'L': parser->
method = HTTP_LOCK;
break;
942 case 'M': parser->
method = HTTP_MKCOL;
break;
943 case 'N': parser->
method = HTTP_NOTIFY;
break;
944 case 'O': parser->
method = HTTP_OPTIONS;
break;
945 case 'P': parser->
method = HTTP_POST;
948 case 'R': parser->
method = HTTP_REPORT;
break;
949 case 'S': parser->
method = HTTP_SUBSCRIBE;
break;
950 case 'T': parser->
method = HTTP_TRACE;
break;
951 case 'U': parser->
method = HTTP_UNLOCK;
break;
972 if (ch ==
' ' && matcher[parser->
index] ==
'\0') {
974 }
else if (ch == matcher[parser->
index]) {
976 }
else if ((ch >=
'A' && ch <=
'Z') || ch ==
'-') {
978 switch (parser->
method << 16 | parser->
index << 8 | ch) {
979 #define XX(meth, pos, ch, new_meth) \
980 case (HTTP_##meth << 16 | pos << 8 | ch): \
981 parser->method = HTTP_##new_meth; break;
983 XX(POST, 1,
'U', PUT)
984 XX(POST, 1,
'A', PATCH)
985 XX(POST, 1,
'R', PROPFIND)
986 XX(PUT, 2,
'R', PURGE)
987 XX(CONNECT, 1,
'H', CHECKOUT)
988 XX(CONNECT, 2,
'P', COPY)
989 XX(MKCOL, 1,
'O', MOVE)
990 XX(MKCOL, 1,
'E', MERGE)
991 XX(MKCOL, 1,
'-', MSEARCH)
992 XX(MKCOL, 2,
'A', MKACTIVITY)
993 XX(MKCOL, 3,
'A', MKCALENDAR)
994 XX(SUBSCRIBE, 1,
'E', SEARCH)
995 XX(REPORT, 2,
'B', REBIND)
996 XX(PROPFIND, 4,
'P', PROPPATCH)
997 XX(LOCK, 1,
'I', LINK)
998 XX(UNLOCK, 2,
'S', UNSUBSCRIBE)
999 XX(UNLOCK, 2,
'B', UNBIND)
1000 XX(UNLOCK, 3,
'I', UNLINK)
1017 if (ch ==
' ')
break;
1020 if (parser->
method == HTTP_CONNECT) {
1233 const char* start = p;
1234 for (; p != data + len; p++) {
1338 assert(0 &&
"Unknown header_state");
1345 if (p == data + len) {
1361 if (ch ==
' ' || ch ==
'\t')
break;
1419 }
else if (
c ==
'c') {
1421 }
else if (
c ==
'u') {
1441 const char* start = p;
1443 for (; p != data + len; p++) {
1472 size_t limit = data + len - p;
1476 p_cr = (
const char*) memchr(p,
CR, limit);
1477 p_lf = (
const char*) memchr(p,
LF, limit);
1479 if (p_lf != NULL && p_cr >= p_lf)
1483 }
else if (
UNLIKELY(p_lf != NULL)) {
1495 assert(0 &&
"Shouldn't get here.");
1502 if (ch ==
' ')
break;
1541 }
else if (
c ==
'c') {
1543 }
else if (
c ==
'u') {
1547 }
else if (
c ==
' ' ||
c ==
'\t') {
1570 }
else if (parser->
index ==
sizeof(
CLOSE)-2) {
1610 }
else if (ch !=
' ') {
1625 if (p == data + len)
1643 if (ch ==
' ' || ch ==
'\t') {
1679 if (ch ==
' ' || ch ==
'\t') {
1826 (uint64_t) ((data + len) - p));
1877 assert(parser->
nread == 1);
1880 unhex_val =
unhex[(
unsigned char)ch];
1902 unhex_val =
unhex[(
unsigned char)ch];
1904 if (unhex_val == -1) {
1905 if (ch ==
';' || ch ==
' ') {
1959 (uint64_t) ((data + len) - p));
1996 assert(0 &&
"unhandled state");
2012 assert(((header_field_mark ? 1 : 0) +
2013 (header_value_mark ? 1 : 0) +
2014 (url_mark ? 1 : 0) +
2015 (body_mark ? 1 : 0) +
2016 (status_mark ? 1 : 0)) <= 1);
2088 void *data = parser->
data;
2089 memset(parser, 0,
sizeof(*parser));
2090 parser->
data = data;
2099 memset(settings, 0,
sizeof(*settings));
2159 if (
IS_HEX(ch) || ch ==
':' || ch ==
'.') {
2176 if (
IS_ALPHANUM(ch) || ch ==
'%' || ch ==
'.' || ch ==
'-' || ch ==
'_' ||
2280 memset(u, 0,
sizeof(*u));
2296 for (p = buf; p < buf + buflen; p++) {
2337 assert(!
"Unexpected state");
2397 assert(0 &&
"Attempting to pause parser in error state");
#define XX(num, name, string)
void http_parser_settings_init(http_parser_settings *settings)
static enum state parse_url_char(enum state s, const char ch)
#define CALLBACK_DATA_NOADVANCE(FOR)
static int http_parse_host(const char *buf, struct http_parser_url *u, int found_at)
unsigned long http_parser_version(void)
@ h_matching_transfer_encoding
@ h_matching_connection_token
@ h_matching_connection_upgrade
@ h_matching_proxy_connection
@ h_connection_keep_alive
@ h_matching_connection_token_start
@ h_matching_connection_keep_alive
@ h_transfer_encoding_chunked
@ h_matching_content_length
@ h_matching_connection_close
@ h_matching_transfer_encoding_chunked
#define PARSING_HEADER(state)
#define HTTP_STRERROR_GEN(n, s)
#define CALLBACK_NOTIFY(FOR)
static const char tokens[256]
size_t http_parser_execute(http_parser *parser, const http_parser_settings *settings, const char *data, size_t len)
static const int8_t unhex[256]
int http_body_is_final(const struct http_parser *parser)
#define STRICT_CHECK(cond)
int http_message_needs_eof(const http_parser *parser)
static const char * method_strings[]
void http_parser_url_init(struct http_parser_url *u)
#define TRANSFER_ENCODING
static const uint8_t normal_url_char[32]
const char * http_errno_description(enum http_errno err)
static struct @2 http_strerror_tab[]
const char * http_errno_name(enum http_errno err)
#define CALLBACK_DATA_(FOR, LEN, ER)
#define IS_HEADER_CHAR(ch)
void http_parser_pause(http_parser *parser, int paused)
int http_should_keep_alive(const http_parser *parser)
#define COUNT_HEADER_SIZE(V)
#define CALLBACK_DATA(FOR)
const char * http_method_str(enum http_method m)
@ s_header_value_discard_ws_almost_done
@ s_chunk_size_almost_done
@ s_res_first_status_code
@ s_header_value_discard_lws
@ s_req_query_string_start
@ s_req_spaces_before_url
@ s_req_schema_slash_slash
@ s_header_value_discard_ws
@ s_chunk_data_almost_done
#define IS_USERINFO_CHAR(c)
@ s_http_host_v6_zone_start
static enum http_host_state http_parse_host_char(enum http_host_state s, const char ch)
int http_parser_parse_url(const char *buf, size_t buflen, int is_connect, struct http_parser_url *u)
#define CALLBACK_NOTIFY_NOADVANCE(FOR)
void http_parser_init(http_parser *parser, enum http_parser_type t)
#define HTTP_METHOD_MAP(XX)
@ HPE_INVALID_CONTENT_LENGTH
@ HPE_UNEXPECTED_CONTENT_LENGTH
@ HPE_CB_headers_complete
@ HPE_INVALID_INTERNAL_STATE
@ HPE_INVALID_HEADER_TOKEN
#define HTTP_PARSER_ERRNO(p)
#define HTTP_ERRNO_MAP(XX)
#define HTTP_MAX_HEADER_SIZE
@ F_CONNECTION_KEEP_ALIVE
#define HTTP_PARSER_VERSION_MINOR
#define HTTP_PARSER_VERSION_MAJOR
#define HTTP_PARSER_VERSION_PATCH
http_cb on_headers_complete
struct http_parser_url::@3 field_data[UF_MAX]
unsigned int header_state
unsigned short http_major
unsigned int lenient_http_headers
unsigned short http_minor
void err(int eval, const char *fmt,...)