6 #include "evhtp/parser.h" 7 #include "evhtp/config.h" 10 #if '\n' != '\x0a' || 'A' != 65 11 #error "You have somehow found a non-ASCII host. We can't build here." 14 #define PARSER_STACK_MAX 8192 15 #define LF (unsigned char)10 16 #define CR (unsigned char)13 17 #define CRLF "\x0d\x0a" 125 "struct htparser {\n" 126 " htpparse_error = %d\n" 127 " parser_state = %d\n" 128 " parser_flags = %d\n" 129 " eval_hdr_val = %d\n" 136 " content_len = %zu\n" 138 " bytes_read = %zu\n" 139 " total_read = %zu\n" 141 " status_count = %d\n" 142 " scheme_offset = %s\n" 143 " host_offset = %s\n" 144 " port_offset = %s\n" 145 " path_offset = %s\n" 146 " args_offset = %s\n" 178 #define log_htparser__s_(p) 193 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
194 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
195 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
196 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, -1, -1, -1, -1, -1, -1,
197 -1, 10, 11, 12, 13, 14, 15, -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, 10, 11, 12, 13, 14, 15, -1, -1, -1, -1, -1, -1, -1, -1, -1,
200 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1
204 "htparse_error_none",
205 "htparse_error_too_big",
206 "htparse_error_invalid_method",
207 "htparse_error_invalid_requestline",
208 "htparse_error_invalid_schema",
209 "htparse_error_invalid_protocol",
210 "htparse_error_invalid_version",
211 "htparse_error_invalid_header",
212 "htparse_error_invalid_chunk_size",
213 "htparse_error_invalid_chunk",
214 "htparse_error_invalid_state",
215 "htparse_error_user",
216 "htparse_error_unknown" 238 #define _MIN_READ(a, b) ((a) < (b) ? (a) : (b)) 240 #ifndef HOST_BIG_ENDIAN 242 #define _str3_cmp(m, c0, c1, c2, c3) \ 243 *(uint32_t *)m == ((c3 << 24) | (c2 << 16) | (c1 << 8) | c0) 245 #define _str3Ocmp(m, c0, c1, c2, c3) \ 246 *(uint32_t *)m == ((c3 << 24) | (c2 << 16) | (c1 << 8) | c0) 248 #define _str4cmp(m, c0, c1, c2, c3) \ 249 *(uint32_t *)m == ((c3 << 24) | (c2 << 16) | (c1 << 8) | c0) 251 #define _str5cmp(m, c0, c1, c2, c3, c4) \ 252 *(uint32_t *)m == ((c3 << 24) | (c2 << 16) | (c1 << 8) | c0) \ 255 #define _str6cmp(m, c0, c1, c2, c3, c4, c5) \ 256 *(uint32_t *)m == ((c3 << 24) | (c2 << 16) | (c1 << 8) | c0) \ 257 && (((uint32_t *)m)[1] & 0xffff) == ((c5 << 8) | c4) 259 #define _str7_cmp(m, c0, c1, c2, c3, c4, c5, c6, c7) \ 260 *(uint32_t *)m == ((c3 << 24) | (c2 << 16) | (c1 << 8) | c0) \ 261 && ((uint32_t *)m)[1] == ((c7 << 24) | (c6 << 16) | (c5 << 8) | c4) 263 #define _str8cmp(m, c0, c1, c2, c3, c4, c5, c6, c7) \ 264 *(uint32_t *)m == ((c3 << 24) | (c2 << 16) | (c1 << 8) | c0) \ 265 && ((uint32_t *)m)[1] == ((c7 << 24) | (c6 << 16) | (c5 << 8) | c4) 267 #define _str9cmp(m, c0, c1, c2, c3, c4, c5, c6, c7, c8) \ 268 *(uint32_t *)m == ((c3 << 24) | (c2 << 16) | (c1 << 8) | c0) \ 269 && ((uint32_t *)m)[1] == ((c7 << 24) | (c6 << 16) | (c5 << 8) | c4) \ 273 #define _str3_cmp(m, c0, c1, c2, c3) \ 274 m[0] == c0 && m[1] == c1 && m[2] == c2 276 #define _str3Ocmp(m, c0, c1, c2, c3) \ 277 m[0] == c0 && m[2] == c2 && m[3] == c3 279 #define _str4cmp(m, c0, c1, c2, c3) \ 280 m[0] == c0 && m[1] == c1 && m[2] == c2 && m[3] == c3 282 #define _str5cmp(m, c0, c1, c2, c3, c4) \ 283 m[0] == c0 && m[1] == c1 && m[2] == c2 && m[3] == c3 && m[4] == c4 285 #define _str6cmp(m, c0, c1, c2, c3, c4, c5) \ 286 m[0] == c0 && m[1] == c1 && m[2] == c2 && m[3] == c3 \ 287 && m[4] == c4 && m[5] == c5 289 #define _str7_cmp(m, c0, c1, c2, c3, c4, c5, c6, c7) \ 290 m[0] == c0 && m[1] == c1 && m[2] == c2 && m[3] == c3 \ 291 && m[4] == c4 && m[5] == c5 && m[6] == c6 293 #define _str8cmp(m, c0, c1, c2, c3, c4, c5, c6, c7) \ 294 m[0] == c0 && m[1] == c1 && m[2] == c2 && m[3] == c3 \ 295 && m[4] == c4 && m[5] == c5 && m[6] == c6 && m[7] == c7 297 #define _str9cmp(m, c0, c1, c2, c3, c4, c5, c6, c7, c8) \ 298 m[0] == c0 && m[1] == c1 && m[2] == c2 && m[3] == c3 \ 299 && m[4] == c4 && m[5] == c5 && m[6] == c6 && m[7] == c7 && m[8] == c8 303 #define __HTPARSE_GENHOOK(__n) \ 304 static inline int hook_ ## __n ## _run(htparser * p, htparse_hooks * hooks) \ 306 log_debug("enter"); \ 307 if (hooks && (hooks)->__n) \ 309 return (hooks)->__n(p); \ 315 #define __HTPARSE_GENDHOOK(__n) \ 316 static inline int hook_ ## __n ## _run(htparser * p, \ 317 htparse_hooks * hooks, \ 318 const char * s, size_t l) \ 320 log_debug("enter"); \ 321 if (hooks && (hooks)->__n) \ 323 return (hooks)->__n(p, s, l); \ 350 static inline uint64_t
356 while (n && isblank(str[n - 1]))
368 for (value = 0; n--; str++)
372 if (*str < '0' || *str >
'9')
378 check = value * 10 + (*str -
'0');
380 if ((value && check <= value))
392 static inline ssize_t
402 for (value = 0; n--; str++)
404 if (*str < '0' || *str >
'9')
409 value = value * 10 + (*str -
'0');
412 if (value > INTMAX_MAX)
433 if (e > (htparse_error_generic + 1))
435 return "htparse_no_such_error";
438 return errstr_map[e];
485 if (meth >= htp_method_UNKNOWN)
490 return method_strmap[meth];
572 p->
error = htparse_error_none;
573 p->
method = htp_method_UNKNOWN;
586 char c = (
unsigned char)(ch | 0x20);
588 if (c >=
'a' && c <=
'z')
593 if ((ch >=
'0' && ch <=
'9') || ch ==
'.' || ch ==
'-')
608 return htp_method_GET;
613 return htp_method_PUT;
622 return htp_method_POST;
627 return htp_method_COPY;
632 return htp_method_MOVE;
637 return htp_method_LOCK;
640 if (
_str4cmp(m,
'H',
'E',
'A',
'D'))
642 return htp_method_HEAD;
648 if (
_str5cmp(m,
'M',
'K',
'C',
'O',
'L'))
650 return htp_method_MKCOL;
653 if (
_str5cmp(m,
'T',
'R',
'A',
'C',
'E'))
655 return htp_method_TRACE;
658 if (
_str5cmp(m,
'P',
'A',
'T',
'C',
'H'))
660 return htp_method_PATCH;
665 if (
_str6cmp(m,
'D',
'E',
'L',
'E',
'T',
'E'))
667 return htp_method_DELETE;
670 if (
_str6cmp(m,
'U',
'N',
'L',
'O',
'C',
'K'))
672 return htp_method_UNLOCK;
677 if (
_str7_cmp(m,
'O',
'P',
'T',
'I',
'O',
'N',
'S',
'\0'))
679 return htp_method_OPTIONS;
682 if (
_str7_cmp(m,
'C',
'O',
'N',
'N',
'E',
'C',
'T',
'\0'))
684 return htp_method_CONNECT;
689 if (
_str8cmp(m,
'P',
'R',
'O',
'P',
'F',
'I',
'N',
'D'))
691 return htp_method_PROPFIND;
697 if (
_str9cmp(m,
'P',
'R',
'O',
'P',
'P',
'A',
'T',
'C',
'H'))
699 return htp_method_PROPPATCH;
705 return htp_method_UNKNOWN;
718 p->
error = htparse_error_none;
721 for (i = 0; i < len; i++)
728 log_debug(
"[%p] data[%zu] = %c (%x)", p, i, isprint(ch) ? ch :
' ', ch);
732 p->
error = htparse_error_too_big;
743 if (ch ==
CR || ch ==
LF)
748 if ((ch < 'A' || ch >
'Z') && ch !=
'_')
750 p->
error = htparse_error_inval_reqline;
752 log_debug(
"s_start invalid fist char '%c'", ch);
760 p->
error = htparse_error_none;
761 p->
method = htp_method_UNKNOWN;
776 res = hook_on_msg_begin_run(p, hooks);
784 }
else if (p->
type == htp_type_response && ch ==
'H')
788 log_debug(
"not type of request or response?");
791 p->
error = htparse_error_inval_reqline;
797 p->
error = htparse_error_user;
810 res = hook_method_run(p, hooks, p->
buf, p->
buf_idx);
817 p->
error = htparse_error_user;
823 if ((ch < 'A' || ch >
'Z') && ch !=
'_')
825 p->
error = htparse_error_inval_method;
838 log_debug(
"[%p] s_spaces_before_uri", p);
847 if (p->
method == htp_method_CONNECT)
863 p->
error = htparse_error_inval_reqline;
890 c = (
unsigned char)(ch | 0x20);
892 if (c >=
'a' && c <=
'z')
901 p->
error = htparse_error_inval_reqline;
911 c = (
unsigned char)(ch | 0x20);
913 if (c >=
'a' && c <=
'z')
922 p->
scheme = htp_scheme_unknown;
928 p->
scheme = htp_scheme_ftp;
934 p->
scheme = htp_scheme_nfs;
942 p->
scheme = htp_scheme_http;
949 p->
scheme = htp_scheme_https;
955 res = hook_scheme_run(p, hooks,
966 p->
error = htparse_error_user;
972 p->
error = htparse_error_inval_schema;
988 p->
error = htparse_error_inval_schema;
993 log_debug(
"[%p] s_schema_slash_slash", p);
1004 p->
error = htparse_error_inval_schema;
1027 res = hook_host_run(p, hooks,
1033 p->
error = htparse_error_user;
1058 p->
error = htparse_error_inval_state;
1076 p->
error = htparse_error_inval_schema;
1082 p->
error = htparse_error_user;
1088 c = (
unsigned char)(ch | 0x20);
1090 if ((c >=
'a' && c <=
'f') ||
1091 (ch >=
'0' && ch <=
'9') || ch ==
':' || ch ==
'.')
1104 p->
error = htparse_error_user;
1112 p->
error = htparse_error_inval_schema;
1117 if (ch >=
'0' && ch <=
'9')
1134 p->
error = htparse_error_inval_state;
1151 p->
error = htparse_error_inval_reqline;
1160 p->
error = htparse_error_user;
1166 log_debug(
"[%p] s_after_slash_in_uri", p);
1170 if (usual[ch >> 5] & (1 << (ch & 0x1f)))
1186 int r2 = hook_uri_run(p, hooks, p->
buf, p->
buf_idx);
1234 p->
error = htparse_error_user;
1246 if (usual[ch >> 5] & (1 << (ch & 0x1f)))
1272 r2 = hook_uri_run(p, hooks, p->
buf, p->
buf_idx);
1299 res = hook_path_run(p, hooks,
1319 p->
error = htparse_error_user;
1331 if (usual[ch >> 5] & (1 << (ch & 0x1f)))
1401 p->
error = htparse_error_user;
1428 p->
error = htparse_error_inval_proto;
1441 p->
error = htparse_error_inval_proto;
1451 p->
error = htparse_error_inval_proto;
1461 p->
error = htparse_error_inval_proto;
1471 p->
error = htparse_error_inval_proto;
1476 if (ch < '1' || ch >
'9')
1478 p->
error = htparse_error_inval_ver;
1482 p->
major = ch -
'0';
1492 if (ch < '0' || ch >
'9')
1494 p->
error = htparse_error_inval_ver;
1501 if (ch < '0' || ch >
'9')
1503 p->
error = htparse_error_inval_ver;
1507 p->
minor = ch -
'0';
1516 }
else if (p->
type == htp_type_response)
1527 p->
error = htparse_error_inval_reqline;
1528 log_debug(
"[s_minor_digit] LF without CR!");
1533 if (ch < '0' || ch >
'9')
1535 p->
error = htparse_error_inval_ver;
1554 if (ch < '0' || ch >
'9')
1556 p->
error = htparse_error_status;
1580 p->
error = htparse_error_generic;
1607 p->
error = htparse_error_inval_ver;
1617 res = hook_on_hdrs_begin_run(p, hooks);
1621 p->
error = htparse_error_user;
1632 res = hook_on_hdrs_begin_run(p, hooks);
1635 p->
error = htparse_error_user;
1640 p->
error = htparse_error_inval_reqline;
1685 res = hook_hdr_key_run(p, hooks, p->
buf, p->
buf_idx);
1692 if (!strcasecmp(p->
buf,
"host"))
1698 if (!strcasecmp(p->
buf,
"connection"))
1704 if (!strcasecmp(p->
buf,
"content-type"))
1710 if (!strcasecmp(p->
buf,
"content-length"))
1716 if (!strcasecmp(p->
buf,
"proxy-connection"))
1722 if (!strcasecmp(p->
buf,
"transfer-encoding"))
1734 p->
error = htparse_error_user;
1765 log_debug(
"[%p] s_hdrline_hdr_space_before_val", p);
1790 p->
error = htparse_error_inval_hdr;
1810 if (hook_hostname_run(p, hooks, p->
buf, p->
buf_idx))
1813 p->
error = htparse_error_user;
1826 p->
error = htparse_error_too_big;
1832 switch (p->
buf[0]) {
1844 A_case = (p->
buf[5] ==
'A') ?
'A' :
'a';
1845 S_buf = (
const char *)(p->
buf + 1);
1848 'e',
'e',
'p',
'-', A_case,
'l',
'i',
'v',
'e'))
1860 C_case = (p->
buf[0] ==
'C') ?
'C' :
'c';
1861 S_buf = (
const char *)p->
buf;
1863 if (
_str5cmp(S_buf, C_case,
'l',
'o',
's',
'e'))
1876 switch (p->
buf[0]) {
1886 S_buf = (
const char *)(p->
buf + 1);
1888 if (
_str6cmp(S_buf,
'h',
'u',
'n',
'k',
'e',
'd'))
1903 switch (p->
buf[0]) {
1908 S_buf = (
const char *)(p->
buf + 1);
1910 if (
_str8cmp(S_buf,
'u',
'l',
't',
'i',
'p',
'a',
'r',
't'))
1932 p->
error = htparse_error_inval_hdr;
1950 log_debug(
"[%p] s_hdrline_hdr_almost_done", p);
1957 res = hook_on_msg_complete_run(p, hooks);
1965 p->
error = htparse_error_inval_hdr;
1971 p->
error = htparse_error_user;
1977 log_debug(
"[%p] s_hdrline_hdr_done", p);
1981 res = hook_hdr_val_run(p, hooks, p->
buf, p->
buf_idx);
1986 p->
error = htparse_error_user;
1993 p->
error = htparse_error_inval_hdr;
2002 res = hook_hdr_val_run(p, hooks, p->
buf, p->
buf_idx);
2012 p->
error = htparse_error_user;
2020 log_debug(
"[%p] s_hdrline_almost_done", p);
2024 res = hook_on_hdrs_complete_run(p, hooks);
2028 p->
error = htparse_error_user;
2036 res = hook_on_msg_complete_run(p, hooks);
2046 res = hook_on_msg_complete_run(p, hooks);
2054 p->
error = htparse_error_user;
2060 p->
error = htparse_error_inval_hdr;
2066 p->
error = htparse_error_user;
2078 res = hook_on_msg_complete_run(p, hooks);
2090 res = hook_on_msg_complete_run(p, hooks);
2096 p->
error = htparse_error_user;
2102 c = unhex[(
unsigned char)ch];
2106 p->
error = htparse_error_inval_chunk_sz;
2120 c = unhex[(
unsigned char)ch];
2124 p->
error = htparse_error_inval_chunk_sz;
2135 p->
error = htparse_error_inval_chunk_sz;
2143 res = hook_on_chunks_complete_run(p, hooks);
2148 res = hook_on_new_chunk_run(p, hooks);
2155 p->
error = htparse_error_user;
2164 const char * pp = &data[i];
2165 const char * pe = (
const char *)(data + len);
2170 res = hook_body_run(p, hooks, pp, to_read);
2185 p->
error = htparse_error_user;
2194 p->
error = htparse_error_inval_chunk;
2204 p->
error = htparse_error_inval_chunk;
2211 if (hook_on_chunk_complete_run(p, hooks))
2213 p->
error = htparse_error_user;
2223 const char * pp = &data[i];
2224 const char * pe = (
const char *)(data + len);
2229 res = hook_body_run(p, hooks, pp, to_read);
2237 res = hook_on_msg_complete_run(p, hooks);
2243 p->
error = htparse_error_user;
2251 log_debug(
"[%p] This is a silly state....", p);
2252 p->
error = htparse_error_inval_state;
htp_scheme htparser_get_scheme(htparser *p)
uint64_t orig_content_len
char buf[PARSER_STACK_MAX]
static const char * errstr_map[]
#define __HTPARSE_GENHOOK(__n)
static int is_host_char(unsigned char ch)
#define _str4cmp(m, c0, c1, c2, c3)
const char * htparser_get_methodstr_m(htp_method meth)
unsigned char htparser_get_multipart(htparser *p)
void htparser_set_minor(htparser *p, unsigned char minor)
#define __HTPARSE_GENDHOOK(__n)
#define _str9cmp(m, c0, c1, c2, c3, c4, c5, c6, c7, c8)
uint64_t htparser_get_total_bytes_read(htparser *p)
htp_method htparser_get_method(htparser *p)
uint64_t htparser_get_bytes_read(htparser *p)
#define _str8cmp(m, c0, c1, c2, c3, c4, c5, c6, c7)
#define _str6cmp(m, c0, c1, c2, c3, c4, c5)
size_t htparser_run(htparser *p, htparse_hooks *hooks, const char *data, size_t len)
const char * htparser_get_strerror(htparser *p)
#define _str7_cmp(m, c0, c1, c2, c3, c4, c5, c6, c7)
#define _str3Ocmp(m, c0, c1, c2, c3)
#define _str5cmp(m, c0, c1, c2, c3, c4)
static const char * method_strmap[]
#define log_htparser__s_(p)
void htparser_init(htparser *p, htp_type type)
uint64_t total_bytes_read
const char * htparser_get_methodstr(htparser *p)
unsigned char htparser_get_major(htparser *p)
static htp_method get_method(const char *m, const size_t sz)
unsigned int status_count
void htparser_set_userdata(htparser *p, void *ud)
static uint64_t str_to_uint64(char *str, size_t n, int *err)
void * htparser_get_userdata(htparser *p)
static ssize_t _str_to_ssize_t(char *str, size_t n)
htpparse_error htparser_get_error(htparser *p)
uint64_t htparser_get_content_pending(htparser *p)
htparser * htparser_new(void)
unsigned int htparser_get_status(htparser *p)
uint64_t htparser_get_content_length(htparser *p)
unsigned char htparser_get_minor(htparser *p)
#define evhtp_unlikely(x)
#define _str3_cmp(m, c0, c1, c2, c3)
int htparser_should_keep_alive(htparser *p)
void htparser_set_major(htparser *p, unsigned char major)