6#ifdef EVHTP_HAS_SYS_TYPES
11#include "evhtp/parser.h"
12#include "evhtp/config.h"
14#if '\n' != '\x0a' || 'A' != 65
15#error "You have somehow found a non-ASCII host. We can't build here."
18#define PARSER_STACK_MAX 8192
19#define LF (unsigned char)10
20#define CR (unsigned char)13
21#define CRLF "\x0d\x0a"
129 "struct htparser {\n"
130 " htpparse_error = %d\n"
131 " parser_state = %d\n"
132 " parser_flags = %d\n"
133 " eval_hdr_val = %d\n"
140 " content_len = %zu\n"
142 " bytes_read = %zu\n"
143 " total_read = %zu\n"
145 " status_count = %d\n"
146 " scheme_offset = %s\n"
147 " host_offset = %s\n"
148 " port_offset = %s\n"
149 " path_offset = %s\n"
150 " args_offset = %s\n"
182#define log_htparser__s_(p)
197 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
198 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
199 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
200 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, -1, -1, -1, -1, -1, -1,
201 -1, 10, 11, 12, 13, 14, 15, -1, -1, -1, -1, -1, -1, -1, -1, -1,
202 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
203 -1, 10, 11, 12, 13, 14, 15, -1, -1, -1, -1, -1, -1, -1, -1, -1,
204 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1
208 "htparse_error_none",
209 "htparse_error_too_big",
210 "htparse_error_invalid_method",
211 "htparse_error_invalid_requestline",
212 "htparse_error_invalid_schema",
213 "htparse_error_invalid_protocol",
214 "htparse_error_invalid_version",
215 "htparse_error_invalid_header",
216 "htparse_error_invalid_chunk_size",
217 "htparse_error_invalid_chunk",
218 "htparse_error_invalid_state",
219 "htparse_error_user",
220 "htparse_error_status",
221 "htparse_error_unknown"
243#define _MIN_READ(a, b) ((a) < (b) ? (a) : (b))
245#ifndef HOST_BIG_ENDIAN
247#define _str3_cmp(m, c0, c1, c2, c3) \
248 *(uint32_t *)m == ((c3 << 24) | (c2 << 16) | (c1 << 8) | c0)
250#define _str3Ocmp(m, c0, c1, c2, c3) \
251 *(uint32_t *)m == ((c3 << 24) | (c2 << 16) | (c1 << 8) | c0)
253#define _str4cmp(m, c0, c1, c2, c3) \
254 *(uint32_t *)m == ((c3 << 24) | (c2 << 16) | (c1 << 8) | c0)
256#define _str5cmp(m, c0, c1, c2, c3, c4) \
257 *(uint32_t *)m == ((c3 << 24) | (c2 << 16) | (c1 << 8) | c0) \
260#define _str6cmp(m, c0, c1, c2, c3, c4, c5) \
261 *(uint32_t *)m == ((c3 << 24) | (c2 << 16) | (c1 << 8) | c0) \
262 && (((uint32_t *)m)[1] & 0xffff) == ((c5 << 8) | c4)
264#define _str7_cmp(m, c0, c1, c2, c3, c4, c5, c6, c7) \
265 *(uint32_t *)m == ((c3 << 24) | (c2 << 16) | (c1 << 8) | c0) \
266 && ((uint32_t *)m)[1] == ((c7 << 24) | (c6 << 16) | (c5 << 8) | c4)
268#define _str8cmp(m, c0, c1, c2, c3, c4, c5, c6, c7) \
269 *(uint32_t *)m == ((c3 << 24) | (c2 << 16) | (c1 << 8) | c0) \
270 && ((uint32_t *)m)[1] == ((c7 << 24) | (c6 << 16) | (c5 << 8) | c4)
272#define _str9cmp(m, c0, c1, c2, c3, c4, c5, c6, c7, c8) \
273 *(uint32_t *)m == ((c3 << 24) | (c2 << 16) | (c1 << 8) | c0) \
274 && ((uint32_t *)m)[1] == ((c7 << 24) | (c6 << 16) | (c5 << 8) | c4) \
278#define _str3_cmp(m, c0, c1, c2, c3) \
279 m[0] == c0 && m[1] == c1 && m[2] == c2
281#define _str3Ocmp(m, c0, c1, c2, c3) \
282 m[0] == c0 && m[2] == c2 && m[3] == c3
284#define _str4cmp(m, c0, c1, c2, c3) \
285 m[0] == c0 && m[1] == c1 && m[2] == c2 && m[3] == c3
287#define _str5cmp(m, c0, c1, c2, c3, c4) \
288 m[0] == c0 && m[1] == c1 && m[2] == c2 && m[3] == c3 && m[4] == c4
290#define _str6cmp(m, c0, c1, c2, c3, c4, c5) \
291 m[0] == c0 && m[1] == c1 && m[2] == c2 && m[3] == c3 \
292 && m[4] == c4 && m[5] == c5
294#define _str7_cmp(m, c0, c1, c2, c3, c4, c5, c6, c7) \
295 m[0] == c0 && m[1] == c1 && m[2] == c2 && m[3] == c3 \
296 && m[4] == c4 && m[5] == c5 && m[6] == c6
298#define _str8cmp(m, c0, c1, c2, c3, c4, c5, c6, c7) \
299 m[0] == c0 && m[1] == c1 && m[2] == c2 && m[3] == c3 \
300 && m[4] == c4 && m[5] == c5 && m[6] == c6 && m[7] == c7
302#define _str9cmp(m, c0, c1, c2, c3, c4, c5, c6, c7, c8) \
303 m[0] == c0 && m[1] == c1 && m[2] == c2 && m[3] == c3 \
304 && m[4] == c4 && m[5] == c5 && m[6] == c6 && m[7] == c7 && m[8] == c8
308#define __HTPARSE_GENHOOK(__n) \
309 static inline int hook_ ## __n ## _run(htparser * p, htparse_hooks * hooks) { \
310 log_debug("enter"); \
311 if (hooks && (hooks)->__n) \
313 return (hooks)->__n(p); \
319#define __HTPARSE_GENDHOOK(__n) \
320 static inline int hook_ ## __n ## _run(htparser * p, \
321 htparse_hooks * hooks, \
322 const char * s, size_t l) { \
323 log_debug("enter"); \
324 if (hooks && (hooks)->__n) \
326 return (hooks)->__n(p, s, l); \
353static inline uint64_t
359 while (n && isblank(str[n - 1]))
371 for (value = 0; n--; str++)
375 if (*str < '0' || *str >
'9')
381 check = value * 10 + (*str -
'0');
383 if ((value && check <= value))
405 for (value = 0; n--; str++)
407 if (*str < '0' || *str >
'9')
412 value = value * 10 + (*str -
'0');
415 if (value > INTMAX_MAX)
436 if (e > htparse_error_generic)
438 return "htparse_no_such_error";
488 if (meth >= htp_method_UNKNOWN)
572 memset(p, 0, offsetof(
htparser, buf));
575 p->
error = htparse_error_none;
576 p->
method = htp_method_UNKNOWN;
589 char c = (
unsigned char)(ch | 0x20);
591 if (c >=
'a' && c <=
'z')
596 if ((ch >=
'0' && ch <=
'9') || ch ==
'.' || ch ==
'-')
611 return htp_method_GET;
616 return htp_method_PUT;
625 return htp_method_POST;
630 return htp_method_COPY;
635 return htp_method_MOVE;
640 return htp_method_LOCK;
643 if (
_str4cmp(m,
'H',
'E',
'A',
'D'))
645 return htp_method_HEAD;
651 if (
_str5cmp(m,
'M',
'K',
'C',
'O',
'L'))
653 return htp_method_MKCOL;
656 if (
_str5cmp(m,
'T',
'R',
'A',
'C',
'E'))
658 return htp_method_TRACE;
661 if (
_str5cmp(m,
'P',
'A',
'T',
'C',
'H'))
663 return htp_method_PATCH;
668 if (
_str6cmp(m,
'D',
'E',
'L',
'E',
'T',
'E'))
670 return htp_method_DELETE;
673 if (
_str6cmp(m,
'U',
'N',
'L',
'O',
'C',
'K'))
675 return htp_method_UNLOCK;
680 if (
_str7_cmp(m,
'O',
'P',
'T',
'I',
'O',
'N',
'S',
'\0'))
682 return htp_method_OPTIONS;
685 if (
_str7_cmp(m,
'C',
'O',
'N',
'N',
'E',
'C',
'T',
'\0'))
687 return htp_method_CONNECT;
692 if (
_str8cmp(m,
'P',
'R',
'O',
'P',
'F',
'I',
'N',
'D'))
694 return htp_method_PROPFIND;
700 if (
_str9cmp(m,
'P',
'R',
'O',
'P',
'P',
'A',
'T',
'C',
'H'))
702 return htp_method_PROPPATCH;
708 return htp_method_UNKNOWN;
711#define HTP_SET_BUF(CH) do { \
712 if (evhtp_likely((p->buf_idx + 1) < PARSER_STACK_MAX)) { \
713 p->buf[p->buf_idx++] = CH; \
714 p->buf[p->buf_idx] = '\0'; \
716 p->error = htparse_error_too_big; \
732 p->
error = htparse_error_none;
735 for (i = 0; i < len; i++)
742 log_debug(
"[%p] data[%zu] = %c (%x)", p, i, isprint(ch) ? ch :
' ', ch);
751 if (ch ==
CR || ch ==
LF)
756 if ((ch < 'A' || ch >
'Z') && ch !=
'_')
758 p->
error = htparse_error_inval_reqline;
760 log_debug(
"s_start invalid fist char '%c'", ch);
768 p->
error = htparse_error_none;
769 p->
method = htp_method_UNKNOWN;
784 res = hook_on_msg_begin_run(p, hooks);
790 }
else if (p->
type == htp_type_response && ch ==
'H') {
793 log_debug(
"not type of request or response?");
796 p->
error = htparse_error_inval_reqline;
802 p->
error = htparse_error_user;
815 res = hook_method_run(p, hooks, p->
buf, p->
buf_idx);
822 p->
error = htparse_error_user;
828 if ((ch < 'A' || ch >
'Z') && ch !=
'_')
830 p->
error = htparse_error_inval_method;
842 log_debug(
"[%p] s_spaces_before_uri", p);
851 if (p->
method == htp_method_CONNECT)
866 p->
error = htparse_error_inval_reqline;
894 c = (
unsigned char)(ch | 0x20);
896 if (c >=
'a' && c <=
'z') {
905 p->
error = htparse_error_inval_reqline;
915 c = (
unsigned char)(ch | 0x20);
917 if (c >=
'a' && c <=
'z') {
924 p->
scheme = htp_scheme_unknown;
930 p->
scheme = htp_scheme_ftp;
936 p->
scheme = htp_scheme_nfs;
944 p->
scheme = htp_scheme_http;
951 p->
scheme = htp_scheme_https;
957 res = hook_scheme_run(p, hooks,
966 p->
error = htparse_error_user;
972 p->
error = htparse_error_inval_schema;
987 p->
error = htparse_error_inval_schema;
992 log_debug(
"[%p] s_schema_slash_slash", p);
1002 p->
error = htparse_error_inval_schema;
1021 res = hook_host_run(p, hooks,
1027 p->
error = htparse_error_user;
1051 p->
error = htparse_error_inval_state;
1068 p->
error = htparse_error_inval_schema;
1074 p->
error = htparse_error_user;
1080 c = (
unsigned char)(ch | 0x20);
1082 if ((c >=
'a' && c <=
'f')
1083 || (ch >=
'0' && ch <=
'9')
1095 p->
error = htparse_error_user;
1104 p->
error = htparse_error_inval_schema;
1109 if (ch >=
'0' && ch <=
'9') {
1124 p->
error = htparse_error_inval_state;
1140 p->
error = htparse_error_inval_reqline;
1149 p->
error = htparse_error_user;
1155 log_debug(
"[%p] s_after_slash_in_uri", p);
1159 if (
usual[ch >> 5] & (1 << (ch & 0x1f)))
1172 int r2 = hook_uri_run(p, hooks, p->
buf, p->
buf_idx);
1218 p->
error = htparse_error_user;
1231 if (
usual[ch >> 5] & (1 << (ch & 0x1f))) {
1255 r2 = hook_uri_run(p, hooks, p->
buf, p->
buf_idx);
1282 res = hook_path_run(p, hooks,
1299 p->
error = htparse_error_user;
1311 if (
usual[ch >> 5] & (1 << (ch & 0x1f))) {
1376 p->
error = htparse_error_user;
1403 p->
error = htparse_error_inval_proto;
1416 p->
error = htparse_error_inval_proto;
1426 p->
error = htparse_error_inval_proto;
1436 p->
error = htparse_error_inval_proto;
1446 p->
error = htparse_error_inval_proto;
1451 if (ch < '1' || ch >
'9')
1453 p->
error = htparse_error_inval_ver;
1457 p->
major = ch -
'0';
1467 if (ch < '0' || ch >
'9')
1469 p->
error = htparse_error_inval_ver;
1476 if (ch < '0' || ch >
'9')
1478 p->
error = htparse_error_inval_ver;
1482 p->
minor = ch -
'0';
1491 }
else if (p->
type == htp_type_response)
1502 p->
error = htparse_error_inval_reqline;
1503 log_debug(
"[s_minor_digit] LF without CR!");
1508 if (ch < '0' || ch >
'9')
1510 p->
error = htparse_error_inval_ver;
1529 if (ch < '0' || ch >
'9')
1531 p->
error = htparse_error_status;
1555 p->
error = htparse_error_generic;
1582 p->
error = htparse_error_inval_ver;
1592 res = hook_on_hdrs_begin_run(p, hooks);
1596 p->
error = htparse_error_user;
1607 res = hook_on_hdrs_begin_run(p, hooks);
1610 p->
error = htparse_error_user;
1615 p->
error = htparse_error_inval_reqline;
1659 res = hook_hdr_key_run(p, hooks, p->
buf, p->
buf_idx);
1666 if (!strcasecmp(p->
buf,
"host"))
1672 if (!strcasecmp(p->
buf,
"connection"))
1678 if (!strcasecmp(p->
buf,
"content-type"))
1684 if (!strcasecmp(p->
buf,
"content-length"))
1690 if (!strcasecmp(p->
buf,
"proxy-connection"))
1696 if (!strcasecmp(p->
buf,
"transfer-encoding"))
1708 p->
error = htparse_error_user;
1738 log_debug(
"[%p] s_hdrline_hdr_space_before_val", p);
1762 p->
error = htparse_error_inval_hdr;
1781 if (hook_hostname_run(p, hooks, p->
buf, p->
buf_idx))
1784 p->
error = htparse_error_user;
1797 p->
error = htparse_error_too_big;
1803 switch (p->
buf[0]) {
1815 A_case = (p->
buf[5] ==
'A') ?
'A' :
'a';
1816 S_buf = (
const char *)(p->
buf + 1);
1819 'e',
'e',
'p',
'-', A_case,
'l',
'i',
'v',
'e'))
1831 C_case = (p->
buf[0] ==
'C') ?
'C' :
'c';
1832 S_buf = (
const char *)p->
buf;
1834 if (
_str5cmp(S_buf, C_case,
'l',
'o',
's',
'e'))
1847 switch (p->
buf[0]) {
1857 S_buf = (
const char *)(p->
buf + 1);
1859 if (
_str6cmp(S_buf,
'h',
'u',
'n',
'k',
'e',
'd'))
1874 switch (p->
buf[0]) {
1879 S_buf = (
const char *)(p->
buf + 1);
1881 if (
_str8cmp(S_buf,
'u',
'l',
't',
'i',
'p',
'a',
'r',
't'))
1903 p->
error = htparse_error_inval_hdr;
1920 log_debug(
"[%p] s_hdrline_hdr_almost_done", p);
1927 res = hook_on_msg_complete_run(p, hooks);
1935 p->
error = htparse_error_inval_hdr;
1941 p->
error = htparse_error_user;
1947 log_debug(
"[%p] s_hdrline_hdr_done", p);
1951 res = hook_hdr_val_run(p, hooks, p->
buf, p->
buf_idx);
1956 p->
error = htparse_error_user;
1963 p->
error = htparse_error_inval_hdr;
1972 res = hook_hdr_val_run(p, hooks, p->
buf, p->
buf_idx);
1980 p->
error = htparse_error_user;
1988 log_debug(
"[%p] s_hdrline_almost_done", p);
1992 res = hook_on_hdrs_complete_run(p, hooks);
1996 p->
error = htparse_error_user;
2004 res = hook_on_msg_complete_run(p, hooks);
2014 res = hook_on_msg_complete_run(p, hooks);
2022 p->
error = htparse_error_user;
2028 p->
error = htparse_error_inval_hdr;
2034 p->
error = htparse_error_user;
2046 res = hook_on_msg_complete_run(p, hooks);
2058 res = hook_on_msg_complete_run(p, hooks);
2064 p->
error = htparse_error_user;
2070 c =
unhex[(
unsigned char)ch];
2074 p->
error = htparse_error_inval_chunk_sz;
2088 c =
unhex[(
unsigned char)ch];
2092 p->
error = htparse_error_inval_chunk_sz;
2103 p->
error = htparse_error_inval_chunk_sz;
2111 res = hook_on_chunks_complete_run(p, hooks);
2116 res = hook_on_new_chunk_run(p, hooks);
2123 p->
error = htparse_error_user;
2132 const char * pp = &data[i];
2133 const char * pe = (
const char *)(data + len);
2138 res = hook_body_run(p, hooks, pp, to_read);
2153 p->
error = htparse_error_user;
2162 p->
error = htparse_error_inval_chunk;
2172 p->
error = htparse_error_inval_chunk;
2179 if (hook_on_chunk_complete_run(p, hooks))
2181 p->
error = htparse_error_user;
2191 const char * pp = &data[i];
2192 const char * pe = (
const char *)(data + len);
2196 res = hook_body_run(p, hooks, pp, to_read);
2203 p->
error = htparse_error_user;
2208 res = hook_on_msg_complete_run(p, hooks);
2214 p->
error = htparse_error_user;
2222 log_debug(
"[%p] This is a silly state....", p);
2223 p->
error = htparse_error_inval_state;
#define evhtp_unlikely(x)
static ssize_t _str_to_ssize_t(char *str, size_t n)
#define _str3_cmp(m, c0, c1, c2, c3)
@ eval_hdr_val_transfer_encoding
@ eval_hdr_val_content_type
@ eval_hdr_val_content_length
@ eval_hdr_val_proxy_connection
@ eval_hdr_val_connection
htpparse_error htparser_get_error(htparser *p)
#define __HTPARSE_GENHOOK(__n)
#define _str8cmp(m, c0, c1, c2, c3, c4, c5, c6, c7)
size_t htparser_run(htparser *p, htparse_hooks *hooks, const char *data, size_t len)
htp_method htparser_get_method(htparser *p)
static htp_method get_method(const char *m, const size_t sz)
htparser * htparser_new(void)
#define _str9cmp(m, c0, c1, c2, c3, c4, c5, c6, c7, c8)
#define _str4cmp(m, c0, c1, c2, c3)
void htparser_set_major(htparser *p, unsigned char major)
static const char * errstr_map[]
void * htparser_get_userdata(htparser *p)
#define log_htparser__s_(p)
uint64_t htparser_get_content_pending(htparser *p)
#define _str5cmp(m, c0, c1, c2, c3, c4)
@ parser_flag_connection_close
@ parser_flag_connection_keep_alive
int htparser_should_keep_alive(htparser *p)
const char * htparser_get_strerror(htparser *p)
uint64_t htparser_get_total_bytes_read(htparser *p)
unsigned char htparser_get_minor(htparser *p)
htp_scheme htparser_get_scheme(htparser *p)
void htparser_init(htparser *p, htp_type type)
#define _str3Ocmp(m, c0, c1, c2, c3)
static const char * method_strmap[]
#define _str7_cmp(m, c0, c1, c2, c3, c4, c5, c6, c7)
uint64_t htparser_get_content_length(htparser *p)
const char * htparser_get_methodstr(htparser *p)
static int is_host_char(unsigned char ch)
@ s_chunk_size_almost_done
@ s_hdrline_hdr_almost_done
@ s_hdrline_hdr_space_before_val
@ s_chunk_data_almost_done
void htparser_set_minor(htparser *p, unsigned char minor)
unsigned char htparser_get_major(htparser *p)
uint64_t htparser_get_bytes_read(htparser *p)
unsigned int htparser_get_status(htparser *p)
#define __HTPARSE_GENDHOOK(__n)
unsigned char htparser_get_multipart(htparser *p)
#define _str6cmp(m, c0, c1, c2, c3, c4, c5)
void htparser_set_userdata(htparser *p, void *ud)
static uint64_t str_to_uint64(char *str, size_t n, int *err)
const char * htparser_get_methodstr_m(htp_method meth)
char buf[PARSER_STACK_MAX]
unsigned int status_count
uint64_t total_bytes_read
uint64_t orig_content_len