16 #include <sys/socket.h>
17 #include <netinet/in.h>
18 #include <netinet/tcp.h>
19 #include <arpa/inet.h>
30 #include <event2/dns.h>
32 #include "evhtp/config.h"
61 #ifndef EVHTP_DISABLE_REGEX
71 #define SET_BIT(VAR, FLAG) VAR |= FLAG
72 #define UNSET_BIT(VAR, FLAG) VAR &= ~FLAG
74 #define HTP_FLAG_ON(PRE, FLAG) SET_BIT(PRE->flags, FLAG)
75 #define HTP_FLAG_OFF(PRE, FLAG) UNSET_BIT(PRE->flags, FLAG)
77 #define HTP_IS_READING(b) ((bufferevent_get_enabled(b) & \
78 EV_READ) ? true : false)
79 #define HTP_IS_WRITING(b) ((bufferevent_get_enabled(b) & \
80 EV_WRITE) ? true : false)
82 #define HTP_LEN_OUTPUT(b) (evbuffer_get_length(bufferevent_get_output(b)))
83 #define HTP_LEN_INPUT(b) (evbuffer_get_length(bufferevent_get_input(b)))
85 #define HOOK_AVAIL(var, hook_name) (var->hooks && var->hooks->hook_name)
86 #define HOOK_FUNC(var, hook_name) (var->hooks->hook_name)
87 #define HOOK_ARGS(var, hook_name) var->hooks->hook_name ## _arg
89 #define HOOK_REQUEST_RUN(request, hook_name, ...) do { \
90 if (HOOK_AVAIL(request, hook_name)) { \
91 return HOOK_FUNC(request, hook_name) (request, __VA_ARGS__, \
92 HOOK_ARGS(request, hook_name)); \
94 if (request->conn && HOOK_AVAIL(request->conn, hook_name)) { \
95 return HOOK_FUNC(request->conn, hook_name) (request, __VA_ARGS__, \
96 HOOK_ARGS(request->conn, hook_name)); \
100 #define HOOK_REQUEST_RUN_NARGS(__request, hook_name) do { \
101 if (HOOK_AVAIL(__request, hook_name)) { \
102 return HOOK_FUNC(__request, hook_name) (__request, \
103 HOOK_ARGS(__request, hook_name)); \
105 if (__request->conn && HOOK_AVAIL(__request->conn, hook_name)) { \
106 return HOOK_FUNC(__request->conn, hook_name) (request, \
107 HOOK_ARGS(__request->conn, hook_name)); \
111 #ifndef EVHTP_DISABLE_EVTHR
117 #define htp__lock_(h) do { \
119 pthread_mutex_lock(h->lock); \
128 #define htp__unlock_(h) do { \
130 pthread_mutex_unlock(h->lock); \
134 #define htp__lock_(h) do { \
136 #define htp__unlock_(h) do { \
140 #ifndef TAILQ_FOREACH_SAFE
141 #define TAILQ_FOREACH_SAFE(var, head, field, tvar) \
142 for ((var) = TAILQ_FIRST((head)); \
143 (var) && ((tvar) = TAILQ_NEXT((var), field), 1); \
148 #define rc_scratch conn->scratch_buf
149 #define rc_parser conn->parser
152 #define ch_fini_arg hooks->on_connection_fini_arg
153 #define ch_fini hooks->on_connection_fini
156 #define cr_status request->status
157 #define cr_flags request->flags
158 #define cr_proto request->proto
161 #define rh_err hooks->on_error
162 #define rh_err_arg hooks->on_error_arg
164 #ifndef EVHTP_DISABLE_MEMFUNCTIONS
166 static void * (*malloc_)(
size_t sz) = malloc;
167 static void * (* realloc_)(
void * d,
size_t sz) = realloc;
168 static void (*
free_)(
void * d) = free;
237 size_t len = nmemb * size;
240 if ((p =
malloc_(len)) == NULL) {
249 return calloc(nmemb, size);
269 if ((p =
malloc_(len + 1)) == NULL) {
273 memcpy(p, str, len + 1);
296 if ((p =
malloc_(len + 1)) != NULL) {
297 memcpy(p, str, len + 1);
307 return strndup(str, len);
311 #define htp__malloc_(sz) malloc(sz)
312 #define htp__calloc_(n, sz) calloc(n, sz)
313 #define htp__strdup_(s) strdup(s)
314 #define htp__strndup_(n, sz) strndup(n, sz)
315 #define htp__realloc_(p, sz) realloc(p, sz)
316 #define htp__free_(p) free(p)
322 void *(*reallocfn_)(
void * p,
size_t sz),
323 void (*freefn_)(
void * p))
325 #ifndef EVHTP_DISABLE_MEMFUNCTIONS
350 return "Bad Request";
351 case EVHTP_RES_NOTFOUND:
353 case EVHTP_RES_SERVERR:
354 return "Internal Server Error";
355 case EVHTP_RES_CONTINUE:
357 case EVHTP_RES_FORBIDDEN:
359 case EVHTP_RES_SWITCH_PROTO:
360 return "Switching Protocols";
361 case EVHTP_RES_MOVEDPERM:
362 return "Moved Permanently";
363 case EVHTP_RES_PROCESSING:
365 case EVHTP_RES_URI_TOOLONG:
366 return "URI Too Long";
367 case EVHTP_RES_CREATED:
369 case EVHTP_RES_ACCEPTED:
371 case EVHTP_RES_NAUTHINFO:
372 return "No Auth Info";
373 case EVHTP_RES_NOCONTENT:
375 case EVHTP_RES_RSTCONTENT:
376 return "Reset Content";
377 case EVHTP_RES_PARTIAL:
378 return "Partial Content";
379 case EVHTP_RES_MSTATUS:
380 return "Multi-Status";
381 case EVHTP_RES_IMUSED:
383 case EVHTP_RES_FOUND:
385 case EVHTP_RES_SEEOTHER:
387 case EVHTP_RES_NOTMOD:
388 return "Not Modified";
389 case EVHTP_RES_USEPROXY:
391 case EVHTP_RES_SWITCHPROXY:
392 return "Switch Proxy";
393 case EVHTP_RES_TMPREDIR:
394 return "Temporary Redirect";
395 case EVHTP_RES_UNAUTH:
396 return "Unauthorized";
397 case EVHTP_RES_PAYREQ:
398 return "Payment Required";
399 case EVHTP_RES_METHNALLOWED:
400 return "Not Allowed";
401 case EVHTP_RES_NACCEPTABLE:
402 return "Not Acceptable";
403 case EVHTP_RES_PROXYAUTHREQ:
404 return "Proxy Authentication Required";
405 case EVHTP_RES_TIMEOUT:
406 return "Request Timeout";
407 case EVHTP_RES_CONFLICT:
411 case EVHTP_RES_LENREQ:
412 return "Length Required";
413 case EVHTP_RES_PRECONDFAIL:
414 return "Precondition Failed";
415 case EVHTP_RES_ENTOOLARGE:
416 return "Entity Too Large";
417 case EVHTP_RES_URITOOLARGE:
418 return "Request-URI Too Long";
419 case EVHTP_RES_UNSUPPORTED:
420 return "Unsupported Media Type";
421 case EVHTP_RES_RANGENOTSC:
422 return "Requested Range Not Satisfiable";
423 case EVHTP_RES_EXPECTFAIL:
424 return "Expectation Failed";
425 case EVHTP_RES_IAMATEAPOT:
426 return "I'm a teapot";
427 case EVHTP_RES_NOTIMPL:
428 return "Not Implemented";
429 case EVHTP_RES_BADGATEWAY:
430 return "Bad Gateway";
431 case EVHTP_RES_SERVUNAVAIL:
432 return "Service Unavailable";
433 case EVHTP_RES_GWTIMEOUT:
434 return "Gateway Timeout";
435 case EVHTP_RES_VERNSUPPORT:
436 return "HTTP Version Not Supported";
437 case EVHTP_RES_BWEXEED:
438 return "Bandwidth Limit Exceeded";
444 #ifndef EVHTP_DISABLE_SSL
446 #ifndef EVHTP_DISABLE_EVTHR
468 strnlen(
const char * s,
size_t maxlen)
473 for (e = s, n = 0; *e && n < maxlen; e++, n++) {
493 strndup(
const char * s,
size_t n)
495 size_t len = strnlen(s, n);
529 #define htp__is_http_11_(_major, _minor) \
530 (_major >= 1 && _minor >= 1)
541 #define htp__is_http_10_(_major, _minor) \
542 (_major >= 1 && _minor <= 0)
632 if (request == NULL) {
633 return EVHTP_RES_500;
652 if (request == NULL) {
653 return EVHTP_RES_500;
733 if (connection->
hooks != NULL && connection->ch_fini != NULL) {
734 return (connection->ch_fini)(connection, connection->ch_fini_arg);
749 if (request && request->
hooks && request->rh_err) {
750 (*request->rh_err)(request, errtype, request->rh_err_arg);
763 if (connection == NULL) {
767 if (connection->
request != NULL) {
798 if (connection->
hooks && connection->
hooks->on_write) {
799 return (connection->
hooks->on_write)(connection,
800 connection->
hooks->on_write_arg);
818 const char *
string,
size_t str_len)
821 switch (pattern[0]) {
823 while (pattern[1] ==
'*') {
844 if (pattern[0] !=
string[0]) {
857 while (*pattern ==
'*') {
866 if (plen == 0 && str_len == 0) {
882 static evhtp_callback_t *
885 unsigned int * start_offset,
886 unsigned int * end_offset)
889 evhtp_callback_t * callback;
891 #ifndef EVHTP_DISABLE_REGEX
892 regmatch_t pmatch[28];
899 path_len = strlen(path);
901 TAILQ_FOREACH(callback, cbs, next) {
902 switch (callback->type) {
904 if (strncmp(path, callback->val.path, callback->len) == 0) {
906 *end_offset = path_len;
912 #ifndef EVHTP_DISABLE_REGEX
914 if (regexec(callback->val.regex,
916 callback->val.regex->re_nsub + 1,
918 *start_offset = pmatch[callback->val.regex->re_nsub].rm_so;
919 *end_offset = pmatch[callback->val.regex->re_nsub].rm_eo;
928 size_t glob_len = strlen(callback->val.glob);
935 *end_offset = path_len;
988 const char * data_end = (
const char *)(data + len);
996 if (req_path == NULL) {
1012 }
else if (*data !=
'/') {
1028 if (data[len - 1] !=
'/') {
1035 for (i = (len - 1); i != 0; i--) {
1036 if (data[i] ==
'/') {
1044 path_len = (size_t)(&data[i] - data) + 1;
1045 file_len = (size_t)(data_end - &data[i + 1]);
1048 if ((
const char *)(data + path_len) > data_end) {
1053 if ((
const char *)(&data[i + 1] + file_len) > data_end) {
1073 if (i == 0 && data[i] ==
'/' && !
file && !
path) {
1139 return (*out != NULL) ? 0 : -1;
1150 if (authority == NULL) {
1219 if (request == NULL) {
1229 if (request->conn && request->conn->request == request) {
1230 request->conn->request = NULL;
1233 if (request->buffer_in != NULL) {
1237 if (request->buffer_out != NULL) {
1252 static evhtp_request_t *
1264 req->
htp = c ? c->htp : NULL;
1268 if (!(req->
buffer_in = evbuffer_new())) {
1308 evhtp_connection_t * c;
1355 evhtp_uri_t *
uri = c->request->uri;
1356 const char * fragment;
1357 int ignore_fragment;
1369 ignore_fragment = (c->htp->parser_flags &
1373 if (!ignore_fragment && (fragment = memchr(data,
'#', len))) {
1380 ptrdiff_t frag_offset;
1382 frag_offset = fragment - data;
1384 if (frag_offset < len) {
1390 fraglen = len - frag_offset;
1395 memcpy(
uri->fragment, fragment, fraglen);
1397 uri->fragment[fraglen] =
'\0';
1413 memcpy(
uri->query_raw, data, len);
1414 uri->query_raw[len] =
'\0';
1436 evhtp_header_t * hdr;
1441 if (key_s == NULL) {
1448 memcpy(key_s, data, len);
1468 evhtp_header_t * header;
1474 memcpy(val_s, data, len);
1483 header->v_heaped = 1;
1492 static inline evhtp_t *
1495 evhtp_t * evhtp_vhost;
1498 TAILQ_FOREACH(evhtp_vhost, &
evhtp->vhosts, next_vhost) {
1504 strlen(evhtp_vhost->server_name), name,
1505 strlen(name)) == 1) {
1509 TAILQ_FOREACH(
evhtp_alias, &evhtp_vhost->aliases, next) {
1516 strlen(name)) == 1) {
1529 evhtp_connection_t *
conn;
1531 evhtp_path_t * path;
1532 evhtp_hooks_t *
hooks;
1533 evhtp_callback_t * callback;
1537 if (request == NULL) {
1541 if ((
evhtp = request->htp) == NULL) {
1545 if ((
conn = request->conn) == NULL) {
1549 if ((
uri = request->uri) == NULL) {
1553 if ((path =
uri->path) == NULL) {
1563 &path->matched_soff, &path->matched_eoff))) {
1566 cbarg = callback->cbarg;
1567 hooks = callback->hooks;
1569 &path->matched_soff, &path->matched_eoff))) {
1572 cbarg = callback->cbarg;
1573 hooks = callback->hooks;
1579 path->matched_soff = 0;
1580 path->matched_eoff = (
unsigned int)strlen(path->full);
1583 if (path->match_start == NULL) {
1584 path->match_start =
htp__calloc_(strlen(path->full) + 1, 1);
1588 if (path->match_end == NULL) {
1589 path->match_end =
htp__calloc_(strlen(path->full) + 1, 1);
1593 if (path->matched_soff != UINT_MAX ) {
1594 if (path->matched_eoff - path->matched_soff) {
1595 memcpy(path->match_start, (
void *)(path->full + path->matched_soff),
1596 path->matched_eoff - path->matched_soff);
1598 memcpy(path->match_start, (
void *)(path->full + path->matched_soff),
1599 strlen((
const char *)(path->full + path->matched_soff)));
1602 memcpy(path->match_end,
1603 (
void *)(path->full + path->matched_eoff),
1604 strlen(path->full) - path->matched_eoff);
1607 if (
hooks != NULL) {
1608 if (request->hooks == NULL) {
1613 memcpy(request->hooks,
hooks,
sizeof(evhtp_hooks_t));
1617 request->cbarg =
cbarg;
1627 evhtp_t * evhtp_vhost;
1629 #ifndef EVHTP_DISABLE_SSL
1634 host = SSL_get_servername(c->ssl, TLSEXT_NAMETYPE_host_name);
1659 c->htp = evhtp_vhost;
1660 c->request->htp = evhtp_vhost;
1679 if (c != NULL && c->request != NULL) {
1680 if (c->request->uri == NULL) {
1693 evhtp_connection_t * c;
1694 evhtp_authority_t * authority;
1709 authority = c->request->uri->authority;
1713 if (authority->hostname == NULL) {
1719 memcpy(authority->hostname, data, len);
1720 authority->hostname[len] =
'\0';
1729 evhtp_authority_t * authority;
1737 authority = c->request->uri->authority;
1738 port = strtoul(data, &endptr, 10);
1740 if (endptr - data != len || port > 65535) {
1746 authority->port = port;
1755 evhtp_path_t * path;
1771 c->request->uri->path = path;
1791 evhtp_connection_t * c;
1819 evbuffer_add_printf(bufferevent_get_output(c->bev),
1820 "HTTP/%c.%c 100 Continue\r\n\r\n",
1832 struct evbuffer * buf;
1835 if (c->max_body_size > 0 && c->body_bytes_read + len >= c->max_body_size) {
1842 if ((buf = c->scratch_buf) == NULL) {
1846 evbuffer_add(buf, data, len);
1852 if (evbuffer_get_length(buf)) {
1853 evbuffer_add_buffer(c->request->buffer_in, buf);
1856 evbuffer_drain(buf, -1);
1858 c->body_bytes_read += len;
1925 const char * content_type;
1931 if (req->uri == NULL || req->uri->query != NULL) {
1940 evbuffer_get_length(req->buffer_in)) {
1944 content_type =
evhtp_kv_find(req->headers_in,
"content-type");
1946 if (content_type == NULL) {
1950 if (strncasecmp(content_type,
"application/x-www-form-urlencoded", 33)) {
1979 struct evbuffer * buf_in;
1981 uri = c->request->uri;
1982 buf_in = c->request->buffer_in;
1984 body_len = evbuffer_get_length(buf_in);
1985 body = (
const char *)evbuffer_pullup(buf_in, body_len);
1994 memcpy(uri->query_raw, body, body_len);
2005 if (c->request && c->request->cb) {
2006 (c->request->cb)(c->request, c->request->cbarg);
2019 #if LIBEVENT_VERSION_NUMBER < 0x02010000
2026 for (n = 0; n < n_vec; n++) {
2027 to_alloc += vec[n].iov_len;
2030 evbuffer_expand(buf, to_alloc);
2032 for (n = 0; n < n_vec; n++) {
2033 evbuffer_add(buf, vec[n].iov_base, vec[n].iov_len);
2035 res += vec[n].iov_len;
2040 return evbuffer_add_iovec(buf, vec, n_vec);
2047 struct evbuffer * buf = arg;
2048 struct evbuffer_iovec iov[4] = {
2049 { header->key, header->klen },
2051 { header->val, header->vlen },
2060 static struct evbuffer *
2063 struct evbuffer * buf;
2064 const char * content_type;
2068 unsigned char major;
2069 unsigned char minor;
2073 && request->headers_out
2074 && request->buffer_out
2076 && request->rc_parser);
2078 request->status = code;
2080 out_len = evbuffer_get_length(request->buffer_out);
2082 if ((buf = request->rc_scratch) == NULL) {
2083 request->rc_scratch = evbuffer_new();
2087 evbuffer_drain(buf, -1);
2109 switch (request->proto) {
2142 if (!content_type) {
2165 struct evbuffer_iovec iov[9] = {
2167 { (
void *)&major, 1 },
2169 { (
void *)&minor, 1 },
2171 { out_buf, strlen(out_buf) },
2173 { (
void *)status_str, strlen(status_str) },
2181 evbuffer_add(buf,
"\r\n", 2);
2183 if (evbuffer_get_length(request->buffer_out)) {
2184 evbuffer_add_buffer(buf, request->buffer_out);
2217 evhtp_connection_t * c = arg;
2233 log_debug(
"connection is paused, returning");
2241 buf = evbuffer_pullup(bufferevent_get_input(bev), avail);
2256 log_debug(
"EVHTP_CONN_FLAG_OWNER set, removing contexts");
2258 evbuffer_drain(bufferevent_get_input(bev), nread);
2265 switch (c->cr_status) {
2276 evbuffer_drain(bufferevent_get_input(bev), nread);
2283 log_debug(
"error %d, freeing connection",
2287 }
else if (nread < avail) {
2289 log_debug(
"Reading more data via resumption");
2298 evhtp_connection_t * conn;
2299 uint64_t keepalive_max;
2300 const char * errstr;
2307 log_error(
"No data associated with the bufferevent %p", bev);
2314 conn = (evhtp_connection_t *)arg;
2318 errstr =
"no request associated with connection";
2323 errstr =
"no parser registered with connection";
2329 errstr =
"no context associated with the server-connection";
2333 keepalive_max = conn->htp->max_keepalive_requests;
2340 log_error(
"shutting down connection: %s", errstr);
2363 bufferevent_enable(bev, EV_READ);
2367 log_debug(
"have input data, will travel");
2389 if (keepalive_max > 0) {
2390 if (++conn->num_requests >= keepalive_max) {
2409 conn->body_bytes_read = 0;
2412 if (conn->htp->parent != NULL
2419 conn->htp = conn->htp->parent;
2423 switch (conn->type) {
2425 type = htp_type_response;
2428 type = htp_type_request;
2454 evhtp_connection_t * c = arg;
2456 log_debug(
"%p %p eventcb %s%s%s%s", arg, (
void *)bev,
2457 events & BEV_EVENT_CONNECTED ?
"connected" :
"",
2458 events & BEV_EVENT_ERROR ?
"error" :
"",
2459 events & BEV_EVENT_TIMEOUT ?
"timeout" :
"",
2460 events & BEV_EVENT_EOF ?
"eof" :
"");
2462 if (c->hooks && c->hooks->on_event) {
2463 (c->hooks->on_event)(c, events, c->hooks->on_event_arg);
2466 if ((events & BEV_EVENT_CONNECTED)) {
2472 bufferevent_setcb(bev,
2481 #ifndef EVHTP_DISABLE_SSL
2482 if (c->ssl && !(events & BEV_EVENT_EOF)) {
2484 unsigned long sslerr;
2486 while ((sslerr = bufferevent_get_openssl_error(bev))) {
2487 log_error(
"SSL ERROR %lu:%i:%s:%i:%s:%i:%s",
2489 ERR_GET_REASON(sslerr),
2490 ERR_reason_error_string(sslerr),
2491 ERR_GET_LIB(sslerr),
2492 ERR_lib_error_string(sslerr),
2493 ERR_GET_FUNC(sslerr),
2494 ERR_func_error_string(sslerr));
2508 if (events == (BEV_EVENT_EOF | BEV_EVENT_READING)) {
2511 if (errno == EAGAIN) {
2523 bufferevent_enable(bev, EV_READ);
2553 evhtp_connection_t * c = arg;
2561 log_debug(
"cr status = OK %d", c->cr_status);
2587 bufferevent_enable(c->bev, EV_WRITE);
2595 bufferevent_enable(c->bev, EV_READ | EV_WRITE);
2615 args = htp->defaults.pre_accept_cbarg;
2616 res = htp->defaults.pre_accept(conn,
args);
2628 struct timeval * c_recv_timeo;
2629 struct timeval * c_send_timeo;
2632 evutil_closesocket(connection->sock);
2637 #ifndef EVHTP_DISABLE_SSL
2638 if (connection->htp->ssl_ctx != NULL) {
2639 connection->ssl = SSL_new(connection->htp->ssl_ctx);
2640 connection->bev = bufferevent_openssl_socket_new(evbase,
2643 BUFFEREVENT_SSL_ACCEPTING,
2644 connection->htp->bev_flags);
2645 SSL_set_app_data(connection->ssl, connection);
2651 connection->bev = bufferevent_socket_new(evbase,
2653 connection->htp->bev_flags);
2655 log_debug(
"enter sock=%d\n", connection->sock);
2657 #ifndef EVHTP_DISABLE_SSL
2661 if (connection->recv_timeo.tv_sec || connection->recv_timeo.tv_usec) {
2662 c_recv_timeo = &connection->recv_timeo;
2663 }
else if (connection->htp->recv_timeo.tv_sec ||
2664 connection->htp->recv_timeo.tv_usec) {
2665 c_recv_timeo = &connection->htp->recv_timeo;
2667 c_recv_timeo = NULL;
2670 if (connection->send_timeo.tv_sec || connection->send_timeo.tv_usec) {
2671 c_send_timeo = &connection->send_timeo;
2672 }
else if (connection->htp->send_timeo.tv_sec ||
2673 connection->htp->send_timeo.tv_usec) {
2674 c_send_timeo = &connection->htp->send_timeo;
2676 c_send_timeo = NULL;
2681 connection->resume_ev = event_new(evbase, -1, EV_READ | EV_PERSIST,
2683 event_add(connection->resume_ev, NULL);
2685 bufferevent_setcb(connection->bev,
2690 bufferevent_enable(connection->bev, EV_READ);
2703 static evhtp_connection_t *
2706 evhtp_connection_t * connection;
2711 ptype = htp_type_response;
2714 ptype = htp_type_request;
2726 connection->scratch_buf = evbuffer_new();
2735 connection->max_body_size = htp->max_body_size;
2739 connection->sock = sock;
2740 connection->htp = htp;
2741 connection->type = type;
2756 #ifdef LIBEVENT_HAS_SHUTDOWN
2757 #ifndef EVHTP_DISABLE_SSL
2759 htp__shutdown_eventcb_(
struct bufferevent * bev,
short events,
void * arg)
2776 args = htp->defaults.post_accept_cbarg;
2777 res = htp->defaults.post_accept(connection,
args);
2786 #ifndef EVHTP_DISABLE_EVTHR
2790 evhtp_t * htp = shared;
2791 evhtp_connection_t * connection = arg;
2794 connection->thread = thr;
2812 htp__accept_cb_(
struct evconnlistener * serv,
int fd,
struct sockaddr * s,
int sl,
void * arg)
2814 evhtp_t * htp = arg;
2815 evhtp_connection_t * connection;
2825 log_debug(
"fd = %d, conn = %p", fd, connection);
2836 memcpy(connection->saddr, s, sl);
2838 #ifndef EVHTP_DISABLE_EVTHR
2839 if (htp->thr_pool != NULL) {
2842 evutil_closesocket(connection->sock);
2852 connection->evbase = htp->evbase;
2865 #ifndef EVHTP_DISABLE_SSL
2866 #ifndef EVHTP_DISABLE_EVTHR
2869 #define _HTP_tid (unsigned long)pthread_self()
2871 #define _HTP_tid pthread_self().p
2874 #if OPENSSL_VERSION_NUMBER < 0x10000000L
2875 static unsigned long
2886 CRYPTO_THREADID_set_numeric(
id,
_HTP_tid);
2895 if (mode & CRYPTO_LOCK) {
2898 pthread_mutex_unlock(&(
ssl_locks[type]));
2908 evhtp_ssl_cfg_t * cfg;
2912 htp = (evhtp_t *)SSL_CTX_get_app_data(ctx);
2916 if (cfg->scache_del) {
2917 (cfg->scache_del)(htp, sid, slen);
2924 evhtp_connection_t * connection;
2925 evhtp_ssl_cfg_t * cfg;
2929 connection = (evhtp_connection_t *)SSL_get_app_data(ssl);
2930 if (connection->htp == NULL) {
2934 cfg = connection->htp->ssl_cfg;
2937 SSL_set_timeout(sess, cfg->scache_timeout);
2939 if (cfg->scache_add) {
2940 return (cfg->scache_add)(connection, sid, slen, sess);
2949 evhtp_connection_t * connection;
2950 evhtp_ssl_cfg_t * cfg;
2953 connection = (evhtp_connection_t * )SSL_get_app_data(ssl);
2955 if (connection->htp == NULL) {
2959 cfg = connection->htp->ssl_cfg;
2962 if (cfg->scache_get) {
2963 sess = (cfg->scache_get)(connection, sid, sid_len);
2975 evhtp_connection_t * connection;
2977 evhtp_t * evhtp_vhost;
2980 return SSL_TLSEXT_ERR_NOACK;
2983 if (!(sname = SSL_get_servername(ssl, TLSEXT_NAMETYPE_host_name))) {
2984 return SSL_TLSEXT_ERR_NOACK;
2987 if (!(connection = SSL_get_app_data(ssl))) {
2988 return SSL_TLSEXT_ERR_NOACK;
2991 if (!(
evhtp = connection->htp)) {
2992 return SSL_TLSEXT_ERR_NOACK;
2996 SSL_CTX * ctx = SSL_get_SSL_CTX(ssl);
2998 connection->htp = evhtp_vhost;
3002 SSL_set_SSL_CTX(ssl, evhtp_vhost->ssl_ctx);
3003 SSL_set_options(ssl, SSL_CTX_get_options(ctx));
3005 if ((SSL_get_verify_mode(ssl) == SSL_VERIFY_NONE) ||
3006 (SSL_num_renegotiations(ssl) == 0)) {
3007 SSL_set_verify(ssl, SSL_CTX_get_verify_mode(ctx),
3008 SSL_CTX_get_verify_callback(ctx));
3011 return SSL_TLSEXT_ERR_OK;
3014 return SSL_TLSEXT_ERR_NOACK;
3039 log_debug(
"connection is already paused");
3049 bufferevent_disable(c->bev, EV_READ);
3061 log_error(
"ODDITY, resuming when not paused?!?");
3069 event_active(c->resume_ev, EV_WRITE, 1);
3094 evhtp_header_t * header;
3108 evhtp_header_t * header;
3114 if (!(header = TAILQ_LAST(headers, evhtp_kvs))) {
3118 if (header->val != NULL) {
3122 header->vlen = strlen(val);
3124 if (val_alloc == 1) {
3128 header->val[header->vlen] =
'\0';
3129 memcpy(header->val, val, header->vlen);
3131 header->val = (
char *)val;
3134 header->v_heaped = val_alloc;
3157 char key_alloc,
char val_alloc)
3167 kv->k_heaped = key_alloc;
3168 kv->v_heaped = val_alloc;
3175 kv->klen = strlen(key);
3177 if (key_alloc == 1) {
3186 memcpy(s, key, kv->klen);
3191 kv->key = (
char *)key;
3196 kv->vlen = strlen(val);
3198 if (val_alloc == 1) {
3208 memcpy(s, val, kv->vlen);
3211 kv->val = (
char *)val;
3225 if (kv->k_heaped == 1) {
3229 if (kv->v_heaped == 1) {
3243 TAILQ_REMOVE(kvs, kv, next);
3261 for (kv = TAILQ_FIRST(kvs); kv != NULL; kv = save) {
3262 save = TAILQ_NEXT(kv, next);
3264 TAILQ_REMOVE(kvs, kv, next);
3277 if (kvs == NULL ||
cb == NULL) {
3281 TAILQ_FOREACH(kv, kvs, next) {
3284 if ((res =
cb(kv, arg))) {
3301 TAILQ_FOREACH(kv, kvs, next) {
3302 if (strcasecmp(kv->key, key) == 0) {
3337 TAILQ_FOREACH(kv, kvs, next) {
3338 if (strcasecmp(kv->key, key) == 0) {
3353 TAILQ_INSERT_TAIL(kvs, kv, next);
3361 if (dst == NULL || src == NULL) {
3365 TAILQ_FOREACH(kv, src, next) {
3415 unsigned char * optr;
3416 unsigned char * sptr;
3428 for (i = 0; i < str_len; i++) {
3442 if (ch >=
'0' && ch <=
'9') {
3443 d = (
unsigned char)(ch -
'0');
3448 c = (
unsigned char)(ch | 0x20);
3450 if (c >=
'a' && c <=
'f') {
3451 d = (
unsigned char)(c -
'a' + 10);
3462 if (ch >=
'0' && ch <=
'9') {
3463 ch = (
unsigned char)((d << 4) + ch -
'0');
3469 c = (
unsigned char)(ch | 0x20);
3471 if (c >=
'a' && c <=
'f') {
3472 ch = (
unsigned char)((d << 4) + c -
'a' + 10);
3495 if (len > (SIZE_MAX - (len + 2))) {
3505 #ifdef EVHTP_HAS_C99
3506 char key_buf[len + 1];
3507 char val_buf[len + 1];
3530 for (i = 0; i < len; i++) {
3533 if (key_idx >= len || val_idx >= len) {
3553 key_buf[key_idx++] = ch;
3554 key_buf[key_idx] =
'\0';
3563 key_buf[key_idx++] = ch;
3564 key_buf[key_idx] =
'\0';
3589 key_buf[key_idx++] = ch;
3590 key_buf[key_idx] =
'\0';
3597 if ((key_idx + 2) >= len) {
3602 key_buf[key_idx - 1] =
'%';
3603 key_buf[key_idx++] = ch;
3604 key_buf[key_idx] =
'\0';
3610 key_buf[key_idx++] = ch;
3611 key_buf[key_idx] =
'\0';
3620 key_buf[key_idx++] = ch;
3621 key_buf[key_idx] =
'\0';
3629 val_buf[val_idx++] = ch;
3630 val_buf[val_idx] =
'\0';
3646 val_buf[val_idx++] = ch;
3647 val_buf[val_idx] =
'\0';
3655 val_buf[val_idx++] = ch;
3656 val_buf[val_idx] =
'\0';
3664 if ((val_idx + 2) >= len) {
3673 val_buf[val_idx - 1] =
'%';
3674 val_buf[val_idx++] = ch;
3675 val_buf[val_idx] =
'\0';
3681 val_buf[val_idx++] = ch;
3682 val_buf[val_idx] =
'\0';
3691 val_buf[val_idx++] = ch;
3692 val_buf[val_idx] =
'\0';
3727 #ifndef EVHTP_HAS_C99
3734 #ifndef EVHTP_HAS_C99
3754 evhtp_connection_t * c;
3755 struct evbuffer * reply_buf;
3764 bufferevent_write_buffer(c->bev, reply_buf);
3765 evbuffer_drain(reply_buf, -1);
3771 evhtp_connection_t * c;
3775 bufferevent_write_buffer(c->bev, buf);
3787 evhtp_connection_t * c;
3788 struct evbuffer * reply_buf;
3789 struct bufferevent * bev;
3805 bufferevent_write_buffer(bev, reply_buf);
3807 evbuffer_drain(reply_buf, -1);
3813 return code != EVHTP_RES_NOCONTENT &&
3814 code != EVHTP_RES_NOTMOD &&
3815 (code < 100 || code >= 200) &&
3816 method != htp_method_HEAD;
3822 evhtp_header_t * content_len;
3827 switch (request->proto) {
3865 if (evbuffer_get_length(request->buffer_out) > 0) {
3869 sres = snprintf(lstr,
sizeof(lstr),
"%x\r\n",
3870 (
unsigned)evbuffer_get_length(request->buffer_out));
3872 if (sres >=
sizeof(lstr) || sres < 0) {
3878 evbuffer_prepend(request->buffer_out, lstr, strlen(lstr));
3879 evbuffer_add(request->buffer_out,
"\r\n", 2);
3890 struct evbuffer * output;
3892 if (evbuffer_get_length(buf) == 0) {
3896 output = bufferevent_get_output(request->conn->bev);
3899 evbuffer_add_printf(output,
"%x\r\n",
3900 (
unsigned)evbuffer_get_length(buf));
3906 evbuffer_add(output,
"\r\n", 2);
3909 bufferevent_flush(request->conn->bev, EV_WRITE, BEV_FLUSH);
3926 if (htp == NULL || htp->server == NULL) {
3938 if (htp == NULL || sock == -1) {
3939 log_error(
"htp = %p && sock = %d", htp, sock);
3943 if (setsockopt(sock, SOL_SOCKET, SO_KEEPALIVE, (
void *)&on,
sizeof(on)) == -1) {
3947 if (setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, (
void *)&on,
sizeof(on)) == -1) {
3951 #if defined(SO_REUSEPORT)
3953 if (setsockopt(sock, SOL_SOCKET, SO_REUSEPORT, (
void *)&on,
sizeof(on)) == -1) {
3954 if (errno != EOPNOTSUPP) {
3959 log_warn(
"SO_REUSEPORT NOT SUPPORTED");
3965 #if defined(TCP_NODELAY)
3967 if (setsockopt(sock, IPPROTO_TCP, TCP_NODELAY, (
void *)&on,
sizeof(on)) == -1) {
3968 if (errno != EOPNOTSUPP) {
3979 #if defined(TCP_DEFER_ACCEPT)
3981 if (setsockopt(sock, IPPROTO_TCP, TCP_DEFER_ACCEPT, (
void *)&on,
sizeof(on)) == -1) {
3982 if (errno != EOPNOTSUPP) {
3987 log_warn(
"DEFER_ACCEPT NOT SUPPORTED");
4001 if (htp == NULL || sock == -1) {
4002 log_error(
"htp = %p && sock = %d", htp, sock);
4007 htp->server = evconnlistener_new(htp->evbase,
4010 LEV_OPT_CLOSE_ON_FREE | LEV_OPT_REUSEABLE,
4014 if (htp->server == NULL) {
4018 #ifndef EVHTP_DISABLE_SSL
4019 if (htp->ssl_ctx != NULL) {
4025 if (TAILQ_FIRST(&htp->vhosts) != NULL) {
4026 SSL_CTX_set_tlsext_servername_callback(htp->ssl_ctx,
4036 if (htp->server != NULL) {
4048 struct sockaddr * sa,
4052 evutil_socket_t fd = -1;
4063 signal(SIGPIPE, SIG_IGN);
4067 if ((fd = socket(sa->sa_family, SOCK_STREAM, 0)) == -1) {
4072 evutil_make_socket_closeonexec(fd);
4073 evutil_make_socket_nonblocking(fd);
4079 if (sa->sa_family == AF_INET6) {
4080 if (setsockopt(fd, IPPROTO_IPV6, IPV6_V6ONLY, &on,
sizeof(on)) == -1) {
4085 if (bind(fd, sa, sin_len) == -1) {
4095 evutil_closesocket(fd);
4105 evutil_closesocket(fd);
4117 struct sockaddr_un sockun = { 0 };
4119 struct sockaddr * sa;
4120 struct sockaddr_in6 sin6 = { 0 };
4121 struct sockaddr_in sin = { 0 };
4124 if (!strncmp(baddr,
"ipv6:", 5)) {
4126 sin_len =
sizeof(
struct sockaddr_in6);
4127 sin6.sin6_port = htons(port);
4128 sin6.sin6_family = AF_INET6;
4130 evutil_inet_pton(AF_INET6, baddr, &sin6.sin6_addr);
4131 sa = (
struct sockaddr *)&sin6;
4132 }
else if (!strncmp(baddr,
"unix:", 5)) {
4136 if (strlen(baddr) >=
sizeof(sockun.sun_path)) {
4140 sin_len =
sizeof(
struct sockaddr_un);
4141 sockun.sun_family = AF_UNIX;
4143 strncpy(sockun.sun_path, baddr, strlen(baddr));
4145 sa = (
struct sockaddr *)&sockun;
4151 if (!strncmp(baddr,
"ipv4:", 5)) {
4155 sin_len =
sizeof(
struct sockaddr_in);
4156 sin.sin_family = AF_INET;
4157 sin.sin_port = htons(port);
4158 sin.sin_addr.s_addr = inet_addr(baddr);
4160 sa = (
struct sockaddr *)&sin;
4169 evhtp_callback_t * callback;
4170 evhtp_callback_t * tmp;
4172 if (callbacks == NULL) {
4177 TAILQ_REMOVE(callbacks, callback, next);
4188 evhtp_callback_t * hcb;
4201 hcb->len = strlen(path);
4214 #ifndef EVHTP_DISABLE_REGEX
4224 if (regcomp(hcb->val.regex, (
char *)path, REG_EXTENDED) != 0) {
4255 if (callback == NULL) {
4259 switch (callback->type) {
4266 #ifndef EVHTP_DISABLE_REGEX
4273 if (callback->hooks) {
4285 TAILQ_INSERT_TAIL(cbs,
cb, next);
4293 if (*hooks == NULL) {
4294 if (!(*hooks =
htp__calloc_(
sizeof(evhtp_hooks_t), 1))) {
4302 (*hooks)->on_headers_start_arg = arg;
4306 (*hooks)->on_header_arg = arg;
4310 (*hooks)->on_headers_arg = arg;
4314 (*hooks)->on_path_arg = arg;
4318 (*hooks)->on_read_arg = arg;
4322 (*hooks)->on_request_fini_arg = arg;
4326 (*hooks)->on_connection_fini_arg = arg;
4330 (*hooks)->on_connection_error_arg = arg;
4334 (*hooks)->on_error_arg = arg;
4338 (*hooks)->on_new_chunk_arg = arg;
4342 (*hooks)->on_chunk_fini_arg = arg;
4346 (*hooks)->on_chunks_fini_arg = arg;
4350 (*hooks)->on_hostname_arg = arg;
4354 (*hooks)->on_write_arg = arg;
4358 (*hooks)->on_event_arg = arg;
4437 if (hooks == NULL) {
4491 evhtp_callback_t * hcb;
4495 if (htp->callbacks == NULL) {
4502 TAILQ_INIT(htp->callbacks);
4526 evhtp_callback_t * callback;
4534 TAILQ_FOREACH(callback, htp->callbacks, next) {
4535 if (strcmp(callback->val.path, path) == 0) {
4543 #ifndef EVHTP_DISABLE_EVTHR
4547 evhtp_t * htp = (evhtp_t *)arg;
4549 if (htp->thread_init_cb) {
4550 htp->thread_init_cb(htp, thr, htp->thread_cbarg);
4557 evhtp_t * htp = (evhtp_t *)arg;
4559 if (htp->thread_exit_cb) {
4560 htp->thread_exit_cb(htp, thr, htp->thread_cbarg);
4568 int nthreads,
void * arg)
4574 htp->thread_cbarg = arg;
4575 htp->thread_init_cb = init_cb;
4576 htp->thread_exit_cb = exit_cb;
4578 #ifndef EVHTP_DISABLE_SSL
4595 int nthreads,
void * arg)
4604 int nthreads,
void * arg)
4611 #ifndef EVHTP_DISABLE_EVTHR
4619 if (!(htp->lock =
htp__malloc_(
sizeof(pthread_mutex_t)))) {
4623 return pthread_mutex_init(htp->lock, NULL);
4628 #ifndef EVHTP_DISABLE_REGEX
4631 const char * pattern,
4635 evhtp_callback_t * hcb;
4639 if (htp->callbacks == NULL) {
4646 TAILQ_INIT(htp->callbacks);
4672 evhtp_callback_t * hcb;
4676 if (htp->callbacks == NULL) {
4683 TAILQ_INIT(htp->callbacks);
4707 htp->defaults.cb =
cb;
4708 htp->defaults.cbarg = arg;
4714 htp->defaults.pre_accept =
cb;
4715 htp->defaults.pre_accept_cbarg = arg;
4721 htp->defaults.post_accept =
cb;
4722 htp->defaults.post_accept_cbarg = arg;
4725 #ifndef EVHTP_DISABLE_SSL
4726 #ifndef EVHTP_DISABLE_EVTHR
4745 pthread_mutex_init(&(
ssl_locks[i]), NULL);
4748 #if OPENSSL_VERSION_NUMBER < 0x10000000L
4767 if (cfg == NULL || htp == NULL || cfg->pemfile == NULL) {
4771 #if OPENSSL_VERSION_NUMBER < 0x10100000L
4773 ERR_load_crypto_strings();
4774 SSL_load_error_strings();
4775 OpenSSL_add_all_algorithms();
4793 if (RAND_poll() != 1) {
4798 if (RAND_bytes(&c, 1) != 1) {
4803 #if OPENSSL_VERSION_NUMBER < 0x10000000L
4804 STACK_OF(SSL_COMP) * comp_methods = SSL_COMP_get_compression_methods();
4805 sk_SSL_COMP_zero(comp_methods);
4809 #if OPENSSL_VERSION_NUMBER < 0x10100000L
4810 htp->ssl_ctx = SSL_CTX_new(SSLv23_server_method());
4812 htp->ssl_ctx = SSL_CTX_new(TLS_server_method());
4817 #if OPENSSL_VERSION_NUMBER >= 0x10000000L
4818 SSL_CTX_set_options(htp->ssl_ctx, SSL_MODE_RELEASE_BUFFERS | SSL_OP_NO_COMPRESSION);
4819 SSL_CTX_set_timeout(htp->ssl_ctx, cfg->ssl_ctx_timeout);
4822 SSL_CTX_set_options(htp->ssl_ctx, cfg->ssl_opts);
4824 #ifndef OPENSSL_NO_ECDH
4825 if (cfg->named_curve != NULL) {
4826 EC_KEY * ecdh = NULL;
4829 nid = OBJ_sn2nid(cfg->named_curve);
4832 log_error(
"ECDH initialization failed: unknown curve %s", cfg->named_curve);
4835 ecdh = EC_KEY_new_by_curve_name(nid);
4838 log_error(
"ECDH initialization failed for curve %s", cfg->named_curve);
4841 SSL_CTX_set_tmp_ecdh(htp->ssl_ctx, ecdh);
4846 #ifndef OPENSSL_NO_DH
4847 if (cfg->dhparams != NULL) {
4851 fh = fopen(cfg->dhparams,
"r");
4854 dh = PEM_read_DHparams(fh, NULL, NULL, NULL);
4856 SSL_CTX_set_tmp_dh(htp->ssl_ctx, dh);
4859 log_error(
"DH initialization failed: unable to parse file %s", cfg->dhparams);
4864 log_error(
"DH initialization failed: unable to open file %s", cfg->dhparams);
4870 if (cfg->ciphers != NULL) {
4871 if (SSL_CTX_set_cipher_list(htp->ssl_ctx, cfg->ciphers) == 0) {
4877 SSL_CTX_load_verify_locations(htp->ssl_ctx, cfg->cafile, cfg->capath);
4878 X509_STORE_set_flags(SSL_CTX_get_cert_store(htp->ssl_ctx), cfg->store_flags);
4879 SSL_CTX_set_verify(htp->ssl_ctx, cfg->verify_peer, cfg->x509_verify_cb);
4881 if (cfg->x509_chk_issued_cb != NULL) {
4882 #if OPENSSL_VERSION_NUMBER < 0x10100000L
4883 htp->ssl_ctx->cert_store->check_issued = cfg->x509_chk_issued_cb;
4885 X509_STORE_set_check_issued(SSL_CTX_get_cert_store(htp->ssl_ctx), cfg->x509_chk_issued_cb);
4889 if (cfg->verify_depth) {
4890 SSL_CTX_set_verify_depth(htp->ssl_ctx, cfg->verify_depth);
4893 switch (cfg->scache_type) {
4895 cache_mode = SSL_SESS_CACHE_OFF;
4898 cache_mode = SSL_SESS_CACHE_SERVER;
4902 SSL_CTX_use_certificate_chain_file(htp->ssl_ctx, cfg->pemfile);
4904 char *
const key = cfg->privfile ? cfg->privfile : cfg->pemfile;
4906 if (cfg->decrypt_cb != NULL) {
4907 EVP_PKEY * pkey = cfg->decrypt_cb(key);
4913 SSL_CTX_use_PrivateKey(htp->ssl_ctx, pkey);
4916 EVP_PKEY_free(pkey);
4918 SSL_CTX_use_PrivateKey_file(htp->ssl_ctx, key, SSL_FILETYPE_PEM);
4921 SSL_CTX_set_session_id_context(htp->ssl_ctx,
4925 SSL_CTX_set_app_data(htp->ssl_ctx, htp);
4926 SSL_CTX_set_session_cache_mode(htp->ssl_ctx, cache_mode);
4928 if (cache_mode != SSL_SESS_CACHE_OFF) {
4929 SSL_CTX_sess_set_cache_size(htp->ssl_ctx,
4930 cfg->scache_size ? cfg->scache_size : 1024);
4938 if (cfg->scache_init) {
4939 cfg->args = (cfg->scache_init)(htp);
4949 struct bufferevent *
4952 return connection->bev;
4955 struct bufferevent *
4960 if (connection->hooks) {
4964 if (connection->request && connection->request->hooks) {
4975 bufferevent_disable(bev, EV_READ);
4976 bufferevent_setcb(bev, NULL, NULL, NULL, NULL);
4981 struct bufferevent *
4987 struct bufferevent *
5013 evhtp_connection_t *
5016 return request->conn;
5022 return request->proto;
5028 return request->status;
5039 const struct timeval * rtimeo,
5040 const struct timeval * wtimeo)
5046 bufferevent_set_timeouts(c->bev, rtimeo, wtimeo);
5053 c->max_body_size = c->htp->max_body_size;
5055 c->max_body_size = len;
5080 if (connection->resume_ev) {
5084 if (connection->bev) {
5085 #ifdef LIBEVENT_HAS_SHUTDOWN
5086 bufferevent_shutdown(connection->bev, htp__shutdown_eventcb_);
5088 #ifndef EVHTP_DISABLE_SSL
5089 if (connection->ssl != NULL) {
5090 SSL_set_shutdown(connection->ssl, SSL_RECEIVED_SHUTDOWN);
5091 SSL_shutdown(connection->ssl);
5105 if (request == NULL) {
5115 if (r_timeo != NULL) {
5116 htp->recv_timeo = *r_timeo;
5119 if (w_timeo != NULL) {
5120 htp->send_timeo = *w_timeo;
5127 htp->max_keepalive_requests = num;
5133 htp->bev_flags = flags;
5139 htp->max_body_size = len;
5151 htp->parser_flags = flags;
5154 #define HTP_FLAG_FNGEN(NAME, TYPE) void \
5155 evhtp ## NAME ## _enable_flag(TYPE v, int flag) { \
5156 HTP_FLAG_ON(v, flag); \
5160 evhtp ## NAME ## _disable_flag(TYPE v, int flag) { \
5161 HTP_FLAG_OFF(v, flag); \
5165 evhtp ## NAME ## _get_flags(TYPE v) { \
5179 evhtp_alias_t * alias;
5185 if (!(alias =
htp__calloc_(
sizeof(evhtp_alias_t), 1))) {
5189 log_debug(
"Adding %s to aliases", name);
5199 TAILQ_INSERT_TAIL(&
evhtp->aliases, alias, next);
5213 va_start(argp, name);
5217 while ((p = va_arg(argp,
const char *)) != NULL) {
5234 if (
evhtp == NULL || name == NULL || vhost == NULL) {
5238 if (TAILQ_FIRST(&vhost->vhosts) != NULL) {
5255 vhost->parent =
evhtp;
5264 TAILQ_INSERT_TAIL(&
evhtp->vhosts, vhost, next_vhost);
5295 htp->evbase = evbase;
5297 htp->bev_flags = BEV_OPT_CLOSE_ON_FREE | BEV_OPT_DEFER_CALLBACKS;
5303 TAILQ_INIT(&htp->vhosts);
5304 TAILQ_INIT(&htp->aliases);
5334 if (
evhtp == NULL) {
5338 #ifndef EVHTP_DISABLE_EVTHR
5346 #ifndef EVHTP_DISABLE_SSL
5377 evhtp_connection_t *
5383 evhtp_connection_t *
5385 const char * addr, uint16_t port)
5387 evhtp_connection_t * conn;
5397 conn->evbase = evbase;
5398 conn->bev = bufferevent_socket_new(evbase, -1, BEV_OPT_CLOSE_ON_FREE);
5400 if (conn->bev == NULL) {
5406 bufferevent_enable(conn->bev, EV_READ);
5407 bufferevent_setcb(conn->bev, NULL, NULL,
5410 if (dns_base != NULL) {
5411 err = bufferevent_socket_connect_hostname(conn->bev, dns_base,
5412 AF_UNSPEC, addr, port);
5414 struct sockaddr_in sin4;
5415 struct sockaddr_in6 sin6;
5416 struct sockaddr * sin;
5419 if (inet_pton(AF_INET, addr, &sin4.sin_addr)) {
5420 sin4.sin_family = AF_INET;
5421 sin4.sin_port = htons(port);
5422 sin = (
struct sockaddr *)&sin4;
5423 salen =
sizeof(sin4);
5424 }
else if (inet_pton(AF_INET6, addr, &sin6.sin6_addr)) {
5425 sin6.sin6_family = AF_INET6;
5426 sin6.sin6_port = htons(port);
5427 sin = (
struct sockaddr *)&sin6;
5428 salen =
sizeof(sin6);
5436 err = bufferevent_socket_connect(conn->bev, sin, salen);
5449 #ifndef EVHTP_DISABLE_SSL
5451 #define ssl_sk_new_ bufferevent_openssl_socket_new
5452 #define ssl_sk_connect_ bufferevent_socket_connect
5454 evhtp_connection_t *
5460 evhtp_connection_t * conn;
5461 struct sockaddr_in sin;
5462 const char * errstr;
5464 if (evbase == NULL) {
5472 conn->evbase = evbase;
5476 if ((conn->ssl = SSL_new(ctx)) == NULL) {
5477 errstr =
"unable to allocate SSL context";
5482 if ((conn->bev =
ssl_sk_new_(evbase, -1, conn->ssl,
5483 BUFFEREVENT_SSL_CONNECTING,
5484 BEV_OPT_CLOSE_ON_FREE)) == NULL) {
5485 errstr =
"unable to allocate bev context";
5489 if (bufferevent_enable(conn->bev, EV_READ) == -1) {
5490 errstr =
"unable to enable reading";
5494 bufferevent_setcb(conn->bev, NULL, NULL,
5498 sin.sin_family = AF_INET;
5499 sin.sin_addr.s_addr = inet_addr(addr);
5500 sin.sin_port = htons(port);
5503 (
struct sockaddr *)&sin,
5504 sizeof(sin)) == -1) {
5505 errstr =
"sk_connect_ failure";
5511 if (errstr != NULL) {
5528 evhtp_request_t * r;
5542 htp_method meth,
const char * uri)
5544 struct evbuffer * obuf;
5547 obuf = bufferevent_get_output(c->bev);
5562 evbuffer_add_printf(obuf,
"%s %s HTTP/%s\r\n",
5565 if (evbuffer_get_length(r->buffer_out)) {
5567 char out_buf[64] = { 0 };
5568 size_t out_len = evbuffer_get_length(r->buffer_out);
5578 evbuffer_add_reference(obuf,
"\r\n", 2, NULL, NULL);
5581 if (evbuffer_get_length(r->buffer_out)) {
5582 evbuffer_add_buffer(obuf, r->buffer_out);
#define EVHTP_PARSE_QUERY_FLAG_TREAT_SEMICOLON_AS_SEP
pthread_mutex_t evhtp_mutex_t
#define EVHTP_CONN_FLAG_VHOST_VIA_SNI
set to 1 if the vhost was found via SSL SNI
#define EVHTP_PARSE_QUERY_FLAG_STRICT
#define EVHTP_PARSE_QUERY_FLAG_IGNORE_FRAGMENTS
#define EVHTP_CONN_FLAG_OWNER
set to 1 if this structure owns the bufferevent
unsigned char evhtp_ssl_data_t
evhtp_res(* evhtp_hook_headers_start_cb)(evhtp_request_t *r, void *arg)
evhtp_res(* evhtp_hook_chunk_new_cb)(evhtp_request_t *r, uint64_t len, void *arg)
#define evhtp_headers_find_header
#define EVHTP_PARSE_QUERY_FLAG_ALLOW_EMPTY_VALS
evhtp_res(* evhtp_hook_hostname_cb)(evhtp_request_t *r, const char *hostname, void *arg)
evhtp_res(* evhtp_hook_connection_fini_cb)(evhtp_connection_t *connection, void *arg)
struct evhtp_kvs evhtp_headers_t
#define EVHTP_CONN_FLAG_WAITING
used to make sure resuming happens AFTER sending a reply
evhtp_res(* evhtp_hook_conn_err_cb)(evhtp_connection_t *connection, evhtp_error_flags errtype, void *arg)
#define EVHTP_PARSE_QUERY_FLAG_IGNORE_HEX
evhtp_res(* evhtp_hook_request_fini_cb)(evhtp_request_t *req, void *arg)
#define EVHTP_CONN_FLAG_PAUSED
this connection has been marked as paused
SSL_SESSION evhtp_ssl_sess_t
#define EVHTP_FLAG_DEFAULTS
evhtp_res(* evhtp_hook_path_cb)(evhtp_request_t *req, evhtp_path_t *path, void *arg)
#define EVHTP_FLAG_ENABLE_100_CONT
#define EVHTP_REQ_FLAG_CHUNKED
void(* evhtp_callback_cb)(evhtp_request_t *req, void *arg)
#define EVHTP_FLAG_ENABLE_NODELAY
evhtp_res(* evhtp_post_accept_cb)(evhtp_connection_t *conn, void *arg)
@ evhtp_callback_type_glob
@ evhtp_callback_type_hash
@ evhtp_callback_type_regex
#define EVHTP_REQ_FLAG_FINISHED
#define EVHTP_PARSE_QUERY_FLAG_DEFAULT
evhtp_res(* evhtp_hook_chunks_fini_cb)(evhtp_request_t *r, void *arg)
#define EVHTP_PARSE_QUERY_FLAG_ALLOW_NULL_VALS
#define EVHTP_CONN_FLAG_FREE_CONN
#define evhtp_safe_free(_var, _freefn)
evhtp_hook_type
types associated with where a developer can hook into during the request processing cycle.
@ evhtp_hook_on_error
type which defines to hook whenever an error occurs
@ evhtp_hook_on_header
type which defines to hook after one header has been parsed
@ evhtp_hook_on_read
type which defines to hook whenever the parser recieves data in a body
@ evhtp_hook_on_new_chunk
@ evhtp_hook_on_chunk_complete
@ evhtp_hook_on_request_fini
type which defines to hook before the request is free'd
@ evhtp_hook_on_chunks_complete
@ evhtp_hook_on_conn_error
type which defines to hook whenever a connection error occurs
@ evhtp_hook_on_headers_start
@ evhtp_hook_on_path
type which defines to hook once a path has been parsed
@ evhtp_hook_on_connection_fini
@ evhtp_hook_on_headers
type which defines to hook after all headers have been parsed
#define evhtp_request_content_len(r)
evhtp_res(* evhtp_hook_read_cb)(evhtp_request_t *req, struct evbuffer *buf, void *arg)
#define EVHTP_REQ_FLAG_ERROR
evhtp_res(* evhtp_hook_header_cb)(evhtp_request_t *req, evhtp_header_t *hdr, void *arg)
#define evhtp_headers_for_each
uint8_t evhtp_error_flags
#define EVHTP_CONN_FLAG_KEEPALIVE
set to 1 after the first request has been processed and the connection is kept open
evhtp_res(* evhtp_hook)()
int(* evhtp_kvs_iterator)(evhtp_kv_t *kv, void *arg)
#define EVHTP_CONN_FLAG_ERROR
@ evhtp_ssl_scache_type_user
@ evhtp_ssl_scache_type_builtin
@ evhtp_ssl_scache_type_disabled
evhtp_res(* evhtp_hook_chunk_fini_cb)(evhtp_request_t *r, void *arg)
evhtp_res(* evhtp_hook_headers_cb)(evhtp_request_t *req, evhtp_headers_t *hdr, void *arg)
evhtp_res(* evhtp_pre_accept_cb)(evhtp_connection_t *conn, void *arg)
void(* evhtp_hook_err_cb)(evhtp_request_t *req, evhtp_error_flags errtype, void *arg)
void(* evhtp_thread_exit_cb)(evhtp_t *htp, evthr_t *thr, void *arg)
struct evhtp_kvs evhtp_kvs_t
evhtp_res(* evhtp_hook_write_cb)(evhtp_connection_t *conn, void *arg)
#define EVHTP_FLAG_ENABLE_REUSEPORT
void(* evhtp_thread_init_cb)(evhtp_t *htp, evthr_t *thr, void *arg)
#define EVHTP_FLAG_ENABLE_DEFER_ACCEPT
struct evhtp_kvs evhtp_query_t
#define EVHTP_RES_DATA_TOO_LONG
#define EVHTP_REQ_FLAG_KEEPALIVE
void(* evhtp_hook_event_cb)(evhtp_connection_t *conn, short events, void *arg)
struct evhtp_callbacks evhtp_callbacks_t
#define EVHTP_CONN_FLAG_CONNECTED
client specific - set after successful connection
void evhtp_set_pre_accept_cb(evhtp_t *htp, evhtp_pre_accept_cb cb, void *arg)
call a user-defined function before the connection is accepted.
#define HTP_IS_WRITING(b)
static void *(* realloc_)(void *d, size_t sz)
const char * evhtp_header_find(evhtp_headers_t *headers, const char *key)
finds the value of a key in a evhtp_headers_t structure
void evhtp_kvs_add_kv(evhtp_kvs_t *kvs, evhtp_kv_t *kv)
appends a key/val structure to a evhtp_kvs_t tailq
static int htp__request_parse_hostname_(htparser *p, const char *data, size_t len)
static void * htp__malloc_(size_t size)
Wrapper for malloc so that a different malloc can be used if desired.
evhtp_connection_t * evhtp_connection_new(struct event_base *evbase, const char *addr, uint16_t port)
allocate a new connection
void evhtp_connection_set_max_body_size(evhtp_connection_t *c, uint64_t len)
set a max body size for a specific connection, this will default to the size set by evhtp_set_max_bod...
void evhtp_kv_rm_and_free(evhtp_kvs_t *kvs, evhtp_kv_t *kv)
free's resources associated with 'kv' if ONLY found within the key/value list
void evhtp_free(evhtp_t *evhtp)
Frees evhtp_t structure; will stop and free threads associated with the structure,...
void evhtp_set_timeouts(evhtp_t *htp, const struct timeval *r_timeo, const struct timeval *w_timeo)
set a read/write timeout on all things evhtp_t.
void evhtp_connection_set_timeouts(evhtp_connection_t *c, const struct timeval *rtimeo, const struct timeval *wtimeo)
sets a connection-specific read/write timeout which overrides the global read/write settings.
static void htp__thread_exit_(evthr_t *thr, void *arg)
static evhtp_res htp__hook_connection_error_(struct evhtp_connection *connection, evhtp_error_flags errtype)
runs the user-defined hook when a connection error occurs
void evhtp_send_reply(evhtp_request_t *request, evhtp_res code)
generates all the right information for a reply to be sent to the client
static evhtp_res htp__hook_chunk_new_(struct evhtp_request *request, uint64_t len)
Runs the user defined request hook.
void evhtp_send_reply_end(evhtp_request_t *request)
int evhtp_bind_socket(evhtp_t *htp, const char *baddr, uint16_t port, int backlog)
bind to a socket, optionally with specific protocol support formatting.
int evhtp_callback_set_hook(evhtp_callback_t *callback, evhtp_hook_type type, evhtp_hook cb, void *arg)
void evhtp_send_reply_body(evhtp_request_t *request, struct evbuffer *buf)
static void htp__request_free_(evhtp_request_t *request)
frees all data in an evhtp_request_t along with calling finished hooks
static int htp__request_parse_headers_start_(htparser *p)
evhtp_query_t * evhtp_parse_query(const char *query, size_t len)
Parses the query portion of the uri into a set of key/values in a strict manner.
static evhtp_proto htp__protocol_(const char major, const char minor)
returns the HTTP protocol version
static evhtp_res htp__hook_headers_(struct evhtp_request *request, evhtp_headers_t *headers)
runs the user-defined on_Headers hook for a request after all headers have been parsed.
TAILQ_HEAD(evhtp_callbacks, evhtp_callback)
static int htp__request_parse_headers_(htparser *p)
static void htp__accept_cb_(struct evconnlistener *serv, int fd, struct sockaddr *s, int sl, void *arg)
static void htp__thread_init_(evthr_t *thr, void *arg)
static void * htp__realloc_(void *ptr, size_t size)
Wrapper for realloc so that a different realloc can be used if desired.
int evhtp_callbacks_add_callback(evhtp_callbacks_t *cbs, evhtp_callback_t *cb)
Adds a evhtp_callback_t to the evhtp_callbacks_t list.
static char * htp__strdup_(const char *str)
implementation of strdup function.
void evhtp_set_gencb(evhtp_t *htp, evhtp_callback_cb cb, void *arg)
sets a callback which is called if no other callbacks are matched
static int htp__request_parse_header_val_(htparser *p, const char *data, size_t len)
static unsigned long htp__ssl_get_thread_id_(void)
static int session_id_context
static int htp__request_parse_chunk_fini_(htparser *p)
#define HOOK_REQUEST_RUN_NARGS(__request, hook_name)
static int htp__path_new_(evhtp_path_t **out, const char *data, size_t len)
parses the path and file from an input buffer
static htparse_hooks request_psets
callback definitions for request processing from libhtparse
void evhtp_request_resume(evhtp_request_t *request)
Wrapper around evhtp_connection_resume.
void evhtp_connection_pause(evhtp_connection_t *c)
pauses a connection (disables reading)
static evhtp_res htp__hook_header_(struct evhtp_request *request, evhtp_header_t *header)
runs the user-defined on_header hook for a request
static void htp__path_free_(struct evhtp_path *path)
Correctly frees the evhtp_path_t ptr that is passed in.
#define HTP_FLAG_FNGEN(NAME, TYPE)
evhtp_kv_t * evhtp_kvs_find_kv(evhtp_kvs_t *kvs, const char *key)
find the evhtp_kv_t reference 'key' from the k/val list 'kvs'
static void htp__ssl_thread_lock_(int mode, int type, const char *file, int line)
static int htp__require_uri_(evhtp_connection_t *c)
int evhtp_bind_sockaddr(evhtp_t *htp, struct sockaddr *sa, size_t sin_len, int backlog)
bind to an already allocated sockaddr.
void evhtp_callbacks_free(evhtp_callbacks_t *callbacks)
static void htp__uri_free_(evhtp_uri_t *uri)
frees an overlay URI structure
int evhtp_ssl_use_threads(void)
static void * htp__calloc_(size_t nmemb, size_t size)
Wrapper for calloc so that a different calloc can be used if desired.
static int htp__request_parse_chunk_new_(htparser *p)
evhtp_request_t * evhtp_request_new(evhtp_callback_cb cb, void *arg)
allocate a new request
int evhtp_add_vhost(evhtp_t *evhtp, const char *name, evhtp_t *vhost)
add an evhtp_t structure (with its own callbacks) to a base evhtp_t structure for virtual hosts.
#define htp__unlock_(h)
Helper macro to unlock htp lock.
static void(* free_)(void *d)
const char * evhtp_kv_find(evhtp_kvs_t *kvs, const char *key)
find the string value of 'key' from the key/value list 'kvs'
evhtp_callback_t * evhtp_get_cb(evhtp_t *htp, const char *path)
attempts to find the callback matching the exact string 'needle'.
static size_t htp__evbuffer_add_iovec_(struct evbuffer *buf, struct evbuffer_iovec *vec, int n_vec)
static evhtp_res htp__hook_chunks_fini_(struct evhtp_request *request)
Runs the user defined on chunk_finis hook.
static int htp__run_pre_accept_(evhtp_t *htp, evhtp_connection_t *conn)
static void htp__connection_eventcb_(struct bufferevent *bev, short events, void *arg)
static int htp__ssl_servername_(evhtp_ssl_t *ssl, int *unused, void *arg)
static int htp__request_parse_fini_(htparser *p)
static int htp__request_parse_body_(htparser *p, const char *data, size_t len)
static int ssl_locks_initialized
void evhtp_send_reply_start(evhtp_request_t *request, evhtp_res code)
static int evhtp_is_hex_query_char(unsigned char ch)
int evhtp_add_aliases(evhtp_t *htp, const char *name,...)
set a variable number of aliases in one call @reference evhtp_add_alias
static evhtp_callback_t * htp__callback_find_(evhtp_callbacks_t *cbs, const char *path, unsigned int *start_offset, unsigned int *end_offset)
Locates a given callback offsets performs a regex pattern match.
static void *(* malloc_)(size_t sz)
static int htp__request_parse_chunks_fini_(htparser *p)
void evhtp_kvs_free(evhtp_kvs_t *kvs)
frees a the list of key/values, and all underlying entries
void evhtp_send_reply_chunk(evhtp_request_t *request, struct evbuffer *buf)
send a chunk reply.
struct bufferevent * evhtp_request_get_bev(evhtp_request_t *request)
returns the underlying requests bufferevent
static evhtp_res htp__hook_request_fini_(struct evhtp_request *request)
runs the user-defined hook called just prior to a request been free()'d
static void htp__ssl_delete_scache_ent_(evhtp_ssl_ctx_t *ctx, evhtp_ssl_sess_t *sess)
void evhtp_request_free(evhtp_request_t *request)
#define HTP_IS_READING(b)
static evhtp_res htp__hook_headers_start_(struct evhtp_request *request)
Runs the user defined on_headers_start hook.
int evhtp_accept_socket(evhtp_t *htp, evutil_socket_t sock, int backlog)
create the listener plus setup various options with an already-bound socket.
int evhtp_connection_unset_hook(evhtp_connection_t *conn, evhtp_hook_type type)
void evhtp_set_mem_functions(void *(*mallocfn_)(size_t len), void *(*reallocfn_)(void *p, size_t sz), void(*freefn_)(void *p))
static int htp__glob_match_(const char *pattern, size_t plen, const char *string, size_t str_len)
glob/wildcard type pattern matching.
static int htp__unset_hook_(evhtp_hooks_t **hooks, evhtp_hook_type type)
static int htp__request_parse_start_(htparser *p)
Starts the parser for the connection associated with the parser struct.
evhtp_header_t * evhtp_header_key_add(evhtp_headers_t *headers, const char *key, char key_alloc)
creates a new evhtp_header_t, sets only the key, and adds to the evhtp_headers TAILQ
static int htp__request_set_callbacks_(evhtp_request_t *request)
static int htp__connection_accept_(struct event_base *evbase, evhtp_connection_t *connection)
evhtp_query_t * evhtp_parse_query_wflags(const char *query, const size_t len, const int flags)
Parses the query portion of the uri into a set of key/values.
int evhtp_unescape_string(unsigned char **out, unsigned char *str, size_t str_len)
Unescapes strings like '%7B1,%202,%203%7D' would become '{1, 2, 3}'.
void evhtp_kv_free(evhtp_kv_t *kv)
frees resources allocated for a single key/value
static int htp__request_parse_args_(htparser *p, const char *data, size_t len)
parses http request arguments
#define HTP_LEN_OUTPUT(b)
static evhtp_res htp__hook_path_(struct evhtp_request *request, struct evhtp_path *path)
runs the user-defined on_path hook for a request
void evhtp_send_reply_chunk_start(evhtp_request_t *request, evhtp_res code)
start a chunked response.
#define htp__is_http_10_(_major, _minor)
helper function to determine if http version is HTTP/1.1
void evhtp_set_max_keepalive_requests(evhtp_t *htp, uint64_t num)
sets a maximum number of requests that a single connection can make.
void evhtp_set_post_accept_cb(evhtp_t *htp, evhtp_post_accept_cb cb, void *arg)
call a user-defined function right after a connection is accepted.
void evhtp_send_reply_chunk_end(evhtp_request_t *request)
call when all chunks have been sent and you wish to send the last bits.
evhtp_header_t * evhtp_header_new(const char *key, const char *val, char kalloc, char valloc)
creates a new evhtp_header_t key/val structure
evhtp_hooks_t * evhtp_request_get_hooks(evhtp_request_t *r)
returns request hooks
void evhtp_set_bev_flags(evhtp_t *htp, int flags)
bufferevent flags which will be used for bev sockets.
#define htp__is_http_11_(_major, _minor)
helper macro to determine if http version is HTTP/1.0
static evhtp_res htp__hook_chunk_fini_(struct evhtp_request *request)
Runs the user defined on_chunk_fini hook.
evhtp_t * evhtp_new(struct event_base *evbase, void *arg)
creates a new evhtp_t instance
evhtp_callback_t * evhtp_callback_new(const char *path, evhtp_callback_type type, evhtp_callback_cb cb, void *arg)
creates a new evhtp_callback_t structure.
void evhtp_set_parser_flags(evhtp_t *htp, int flags)
during the request processing cycle, these flags will be used to for query argument parsing.
static void htp__connection_readcb_(struct bufferevent *bev, void *arg)
int evhtp_use_callback_locks(evhtp_t *htp)
creates a lock around callbacks and hooks, allowing for threaded applications to add/remove/modify ho...
static void htp__free_(void *ptr)
Wrapper for free so that a different free can be used if desired.
static evhtp_t * htp__request_find_vhost_(evhtp_t *evhtp, const char *name)
#define htp__lock_(h)
Helper macro to lock htp structure.
static int htp__request_parse_header_key_(htparser *p, const char *data, size_t len)
static int evhtp__new_(evhtp_t **out, struct event_base *evbase, void *arg)
Allocates new evhtp_t structure.
static evhtp_connection_t * htp__connection_new_(evhtp_t *htp, evutil_socket_t sock, evhtp_type type)
static int htp__create_headers_(evhtp_header_t *header, void *arg)
void evhtp_callback_free(evhtp_callback_t *callback)
safely frees callback structure memory and internals
struct bufferevent * evhtp_request_take_ownership(evhtp_request_t *request)
static evhtp_res htp__hook_body_(struct evhtp_request *request, struct evbuffer *buf)
runs the user-defined on_body hook for requests containing a body.
int evhtp_connection_set_hook(evhtp_connection_t *conn, evhtp_hook_type type, evhtp_hook cb, void *arg)
sets a callback hook for either a connection or a path/regex .
evhtp_hooks_t * evhtp_connection_get_hooks(evhtp_connection_t *c)
evhtp_proto evhtp_request_get_proto(evhtp_request_t *request)
static int htp__request_parse_path_(htparser *p, const char *data, size_t len)
evhtp_callback_t * evhtp_set_glob_cb(evhtp_t *htp, const char *pattern, evhtp_callback_cb cb, void *arg)
sets a callback to to be executed on simple glob/wildcard patterns this is useful if the app does not...
void evhtp_request_pause(evhtp_request_t *request)
Wrapper around evhtp_connection_pause.
int evhtp_kvs_for_each(evhtp_kvs_t *kvs, evhtp_kvs_iterator cb, void *arg)
callback iterator which executes 'cb' for every entry in 'kvs'
#define HTP_FLAG_ON(PRE, FLAG)
int evhtp_use_threads_wexit(evhtp_t *htp, evhtp_thread_init_cb init_cb, evhtp_thread_exit_cb exit_cb, int nthreads, void *arg)
Temporary function which will be renamed evhtp_use_threads in the future.
evhtp_connection_t * evhtp_connection_new_dns(struct event_base *evbase, struct evdns_base *dns_base, const char *addr, uint16_t port)
allocate a new connection
int evhtp_request_unset_hook(evhtp_request_t *req, evhtp_hook_type type)
static void htp__default_request_cb_(evhtp_request_t *request, void *arg)
static char * htp__strndup_(const char *str, size_t len)
implementation of strndup function.
int evhtp_response_needs_body(const evhtp_res code, const htp_method method)
Determine if a response should have a body.
void evhtp_headers_add_header(evhtp_headers_t *headers, evhtp_header_t *header)
adds an evhtp_header_t to the end of the evhtp_headers_t tailq
static evhtp_request_t * htp__request_new_(evhtp_connection_t *c)
Creates a new evhtp_request_t.
int evhtp_use_threads(evhtp_t *htp, evhtp_thread_init_cb init_cb, int nthreads, void *arg)
Enable thread-pool support for an evhtp_t context.
static evhtp_res htp__hook_connection_write_(struct evhtp_connection *connection)
Runs the user defined on_write hook.
void evhtp_unbind_socket(evhtp_t *htp)
stops the listening socket.
static int htp__request_parse_host_(htparser *p, const char *data, size_t len)
void evhtp_connection_resume(evhtp_connection_t *c)
resumes a connection (enables reading) and activates resume event.
unsigned int evhtp_request_status(evhtp_request_t *r)
static evhtp_res htp__hook_hostname_(struct evhtp_request *r, const char *hostname)
Runs the user defined hostname processing hook.
static evhtp_res htp__hook_connection_fini_(struct evhtp_connection *connection)
runs the user-definedhook called just prior to a connection being closed
void evhtp_request_set_max_body_size(evhtp_request_t *req, uint64_t len)
just calls evhtp_connection_set_max_body_size for the request.
static int htp__ssl_add_scache_ent_(evhtp_ssl_t *ssl, evhtp_ssl_sess_t *sess)
struct bufferevent * evhtp_connection_get_bev(evhtp_connection_t *connection)
returns the underlying connections bufferevent
int evhtp_unset_all_hooks(evhtp_hooks_t **hooks)
removes all hooks.
static evhtp_ssl_sess_t * htp__ssl_get_scache_ent_(evhtp_ssl_t *ssl, evhtp_ssl_data_t *sid, int sid_len, int *copy)
static evhtp_mutex_t * ssl_locks
static void htp__connection_resumecb_(int fd, short events, void *arg)
static void htp__hook_error_(struct evhtp_request *request, evhtp_error_flags errtype)
runs the user-defined hook when a connection error occurs
const char * evhtp_request_get_status_code_str(evhtp_request_t *request)
wrapper around get_status_code that returns the string version of the last status code set for a requ...
static void htp__connection_writecb_(struct bufferevent *bev, void *arg)
static const char * status_code_to_str(evhtp_res code)
returns string status code from enum code
evhtp_callback_t * evhtp_set_cb(evhtp_t *htp, const char *path, evhtp_callback_cb cb, void *arg)
sets a callback to be executed on a specific path
#define HTP_FLAG_OFF(PRE, FLAG)
void evhtp_connection_free(evhtp_connection_t *connection)
free's all connection related resources, this will also call your request fini hook and request fini ...
evhtp_connection_t * evhtp_request_get_connection(evhtp_request_t *request)
returns the underlying evhtp_connection_t structure from a request
void evhtp_connection_set_bev(evhtp_connection_t *conn, struct bufferevent *bev)
Sets the connections underlying bufferevent.
evhtp_header_t * evhtp_header_val_add(evhtp_headers_t *headers, const char *val, char val_alloc)
finds the last header in the headers tailq and adds the value
evhtp_callback_t * evhtp_set_regex_cb(evhtp_t *htp, const char *pattern, evhtp_callback_cb cb, void *arg)
sets a callback to be executed based on a regex pattern
int evhtp_callback_unset_hook(evhtp_callback_t *callback, evhtp_hook_type type)
evhtp_hooks_t * evhtp_callback_get_hooks(evhtp_callback_t *cb)
returns callback hooks
#define HOOK_REQUEST_RUN(request, hook_name,...)
evhtp_connection_t * evhtp_connection_ssl_new(struct event_base *evbase, const char *addr, uint16_t port, evhtp_ssl_ctx_t *ctx)
evhtp_kvs_t * evhtp_kvs_new(void)
creates an empty list of key/values
static int htp__use_threads_(evhtp_t *htp, evhtp_thread_init_cb init_cb, evhtp_thread_exit_cb exit_cb, int nthreads, void *arg)
void evhtp_kvs_add_kvs(evhtp_kvs_t *dst, evhtp_kvs_t *src)
appends all key/val structures from src tailq onto dst tailq
void evhtp_disable_100_continue(evhtp_t *htp)
static int htp__serv_setsockopts_(evhtp_t *htp, evutil_socket_t sock)
static void htp__authority_free_(evhtp_authority_t *authority)
frees an authority structure
static int htp__authority_new_(evhtp_authority_t **out)
create an authority structure
static int htp__set_hook_(evhtp_hooks_t **hooks, evhtp_hook_type type, evhtp_hook cb, void *arg)
void evhtp_request_set_keepalive(evhtp_request_t *request, int val)
int evhtp_add_alias(evhtp_t *evhtp, const char *name)
Add an alias hostname for a virtual-host specific evhtp_t.
htp_method evhtp_request_get_method(evhtp_request_t *r)
returns the htp_method enum version of the request method.
evhtp_kv_t * evhtp_kv_new(const char *key, const char *val, char key_alloc, char val_alloc)
Allocates a new key/value structure.
int evhtp_make_request(evhtp_connection_t *c, evhtp_request_t *r, htp_method meth, const char *uri)
make a client request
int evhtp_request_set_hook(evhtp_request_t *req, evhtp_hook_type type, evhtp_hook cb, void *arg)
void evhtp_request_set_bev(evhtp_request_t *request, struct bufferevent *bev)
sets the underlying bufferevent for a evhtp_request
static void htp__run_in_thread_(evthr_t *thr, void *arg, void *shared)
static int htp__should_parse_query_body_(evhtp_request_t *req)
determines if the request body contains the query arguments.
static int htp__run_post_accept_(evhtp_t *htp, evhtp_connection_t *connection)
static struct evbuffer * htp__create_reply_(evhtp_request_t *request, evhtp_res code)
void evhtp_set_max_body_size(evhtp_t *htp, uint64_t len)
set a max body size to accept for an incoming request, this will default to unlimited.
evhtp_res evhtp_request_get_status_code(evhtp_request_t *request)
Returns the last status code set for a request (request/response)
struct bufferevent * evhtp_connection_take_ownership(evhtp_connection_t *connection)
let a user take ownership of the underlying bufferevent and free all other underlying resources.
static int htp__uri_new_(evhtp_uri_t **out)
create an overlay URI structure
int evhtp_ssl_init(evhtp_t *htp, evhtp_ssl_cfg_t *cfg)
static int htp__request_parse_port_(htparser *p, const char *data, size_t len)
#define TAILQ_FOREACH_SAFE(var, head, field, tvar)
#define evhtp_alloc_assert(x)
#define evhtp_unlikely(x)
#define evhtp_modp_uchartoa(_val)
EVHTP_EXPORT size_t evhtp_modp_u32toa(uint32_t value, char *str)
converts uint32_t value to string
EVHTP_EXPORT size_t evhtp_modp_sizetoa(size_t value, char *str)
based on the system architecture, convert a size_t number to a string.
htpparse_error htparser_get_error(htparser *p)
void * htparser_get_userdata(htparser *p)
size_t htparser_run(htparser *p, htparse_hooks *hooks, const char *data, size_t len)
htp_method htparser_get_method(htparser *p)
void htparser_set_major(htparser *p, unsigned char major)
int htparser_should_keep_alive(htparser *p)
unsigned char htparser_get_minor(htparser *p)
htp_scheme htparser_get_scheme(htparser *p)
void htparser_init(htparser *p, htp_type type)
uint64_t htparser_get_content_length(htparser *p)
const char * htparser_get_methodstr_m(htp_method meth)
void htparser_set_minor(htparser *p, unsigned char minor)
unsigned char htparser_get_major(htparser *p)
unsigned int htparser_get_status(htparser *p)
unsigned char htparser_get_multipart(htparser *p)
void htparser_set_userdata(htparser *p, void *ud)
htparser * htparser_new(void)
structure which represents authority information in a URI
structure containing a single callback and configuration
void * cbarg
user-defind arguments passed to the cb
evhtp_callback_type type
the type of callback (regex|path)
union evhtp_callback::@0 val
evhtp_hooks_t * hooks
per-callback hooks
evhtp_callback_cb cb
the actual callback function
evhtp_request_t * request
the request currently being processed
structure which represents a URI path and or file
char * file
the filename if present (c.html)
char * full
the full path+file (/a/b/c.html)
char * path
the path (/a/b/)
a structure containing all information for a http request.
struct evbuffer * buffer_in
buffer containing data from client
void * cbarg
argument which is passed to the cb function
evhtp_uri_t * uri
request URI information
struct evbuffer * buffer_out
buffer containing data to client
evhtp_headers_t * headers_out
headers to client
evhtp_headers_t * headers_in
headers from client
evhtp_t * htp
the parent evhtp_t structure
evhtp_hooks_t * hooks
request specific hooks
evhtp_res status
The HTTP response code or other error conditions.
evhtp_connection_t * conn
the associated connection
a generic container representing an entire URI strucutre
evhtp_authority_t * authority
main structure containing all configuration information
char * server_name
the name included in Host: responses
evthr_pool_t * thr_pool
connection threadpool
struct timeval send_timeo
int bev_flags
bufferevent flags to use on bufferevent_*_socket_new()
struct timeval recv_timeo
evhtp_ssl_ctx_t * ssl_ctx
if ssl enabled, this is the servers CTX
uint64_t max_keepalive_requests
evhtp_callbacks_t * callbacks
evhtp_defaults_t defaults
evbase_t * evthr_get_base(evthr_t *thr)
void evthr_pool_free(evthr_pool_t *pool)
evthr_res evthr_pool_defer(evthr_pool_t *pool, evthr_cb cb, void *arg)
evthr_pool_t * evthr_pool_wexit_new(int nthreads, evthr_init_cb init_cb, evthr_exit_cb exit_cb, void *shared)
int evthr_pool_start(evthr_pool_t *pool)
evthr_res evthr_pool_stop(evthr_pool_t *pool)