15 #include <sys/socket.h> 16 #include <netinet/in.h> 17 #include <netinet/tcp.h> 18 #include <arpa/inet.h> 29 #include <event2/dns.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 HOOK_AVAIL(var, hook_name) (var->hooks && var->hooks->hook_name) 78 #define HOOK_FUNC(var, hook_name) (var->hooks->hook_name) 79 #define HOOK_ARGS(var, hook_name) var->hooks->hook_name ## _arg 81 #define HOOK_REQUEST_RUN(request, hook_name, ...) do { \ 82 if (HOOK_AVAIL(request, hook_name)) \ 84 return HOOK_FUNC(request, hook_name) (request, __VA_ARGS__, \ 85 HOOK_ARGS(request, hook_name)); \ 88 if (request->conn && HOOK_AVAIL(request->conn, hook_name)) \ 90 return HOOK_FUNC(request->conn, hook_name) (request, __VA_ARGS__, \ 91 HOOK_ARGS(request->conn, hook_name)); \ 95 #define HOOK_REQUEST_RUN_NARGS(__request, hook_name) do { \ 96 if (HOOK_AVAIL(__request, hook_name)) \ 98 return HOOK_FUNC(__request, hook_name) (__request, \ 99 HOOK_ARGS(__request, hook_name)); \ 102 if (__request->conn && HOOK_AVAIL(__request->conn, hook_name)) \ 104 return HOOK_FUNC(__request->conn, hook_name) (request, \ 105 HOOK_ARGS(__request->conn, hook_name)); \ 109 #ifndef EVHTP_DISABLE_EVTHR 115 #define htp__lock_(h) do { \ 118 pthread_mutex_lock(h->lock); \ 127 #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 159 #define rh_err hooks->on_error 160 #define rh_err_arg hooks->on_error_arg 162 #ifndef EVHTP_DISABLE_MEMFUNCTIONS 164 static void * (*malloc_)(
size_t sz) = malloc;
165 static void * (* realloc_)(
void * d,
size_t sz) = realloc;
166 static void (*
free_)(
void * d) = free;
232 size_t len = nmemb * size;
235 if ((p =
malloc_(len)) == NULL)
245 return calloc(nmemb, size);
266 if ((p =
malloc_(len + 1)) == NULL)
271 memcpy(p, str, len + 1);
295 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++)
494 strndup(
const char * s,
size_t n)
496 size_t len = strnlen(s, n);
532 #define htp__is_http_11_(_major, _minor) \ 533 (_major >= 1 && _minor >= 1) 544 #define htp__is_http_10_(_major, _minor) \ 545 (_major >= 1 && _minor <= 0) 741 if (connection->hooks != NULL && connection->ch_fini != NULL)
743 return (connection->ch_fini)(connection, connection->ch_fini_arg);
758 if (request && request->hooks && request->rh_err)
760 (*request->rh_err)(request, errtype, request->rh_err_arg);
773 if (connection == NULL)
778 if (connection->request != NULL)
810 if (connection->hooks && connection->hooks->on_write)
812 return (connection->hooks->on_write)(connection,
813 connection->hooks->on_write_arg);
831 const char *
string,
size_t str_len)
835 switch (pattern[0]) {
837 while (pattern[1] ==
'*')
862 if (pattern[0] !=
string[0])
877 while (*pattern ==
'*')
887 if (plen == 0 && str_len == 0)
904 static evhtp_callback_t *
907 unsigned int * start_offset,
908 unsigned int * end_offset)
912 #ifndef EVHTP_DISABLE_REGEX 913 regmatch_t pmatch[28];
915 evhtp_callback_t * callback;
922 path_len = strlen(path);
924 TAILQ_FOREACH(callback, cbs, next) {
925 switch (callback->type) {
927 if (strncmp(path, callback->val.path, callback->len) == 0)
930 *end_offset = path_len;
935 #ifndef EVHTP_DISABLE_REGEX 937 if (regexec(callback->val.regex,
939 callback->val.regex->re_nsub + 1,
942 *start_offset = pmatch[callback->val.regex->re_nsub].rm_so;
943 *end_offset = pmatch[callback->val.regex->re_nsub].rm_eo;
952 size_t glob_len = strlen(callback->val.glob);
960 *end_offset = path_len;
992 evhtp_path_t * req_path;
993 const char * data_end = (
const char *)(data + len);
1010 }
else if (*data !=
'/')
1021 if (data[len - 1] !=
'/')
1029 for (i = (len - 1); i != 0; i--)
1040 path_len = (size_t)(&data[i] - data) + 1;
1041 file_len = (size_t)(data_end - &data[i + 1]);
1044 if ((
const char *)(data + path_len) > data_end)
1052 if ((
const char *)(&data[i + 1] + file_len) > data_end)
1069 if (i == 0 && data[i] ==
'/' && !file && !path)
1097 req_path->path =
path;
1098 req_path->file = file;
1134 evhtp_authority_t * authority;
1143 return (*out != NULL) ? 0 : -1;
1154 if (authority == NULL)
1206 uri->authority = NULL;
1238 if (request->conn && request->conn->request == request)
1240 request->conn->request = NULL;
1243 if (request->buffer_in != NULL)
1248 if (request->buffer_out != NULL)
1264 static evhtp_request_t *
1267 evhtp_request_t * req;
1277 req->htp = c ? c->htp : NULL;
1301 TAILQ_INIT(req->headers_in);
1302 TAILQ_INIT(req->headers_out);
1370 evhtp_uri_t * uri = c->request->uri;
1371 const char * fragment;
1372 int ignore_fragment;
1386 ignore_fragment = (c->htp->parser_flags &
1390 if (!ignore_fragment && (fragment = memchr(data,
'#', len)))
1398 ptrdiff_t frag_offset;
1400 frag_offset = fragment - data;
1402 if (frag_offset < len)
1409 fraglen = len - frag_offset;
1414 memcpy(uri->fragment, fragment, fraglen);
1416 uri->fragment[fraglen] =
'\0';
1433 memcpy(uri->query_raw, data, len);
1434 uri->query_raw[
len] =
'\0';
1463 memcpy(key_s, data, len);
1488 memcpy(val_s, data, len);
1498 header->v_heaped = 1;
1508 static inline evhtp_t *
1511 evhtp_t * evhtp_vhost;
1512 evhtp_alias_t * evhtp_alias;
1514 TAILQ_FOREACH(evhtp_vhost, &evhtp->vhosts, next_vhost) {
1521 strlen(evhtp_vhost->server_name), name,
1527 TAILQ_FOREACH(evhtp_alias, &evhtp_vhost->aliases, next) {
1528 if (evhtp_alias->alias == NULL)
1534 strlen(evhtp_alias->alias), name,
1549 evhtp_connection_t * conn;
1551 evhtp_path_t *
path;
1552 evhtp_hooks_t *
hooks;
1553 evhtp_callback_t * callback;
1557 if (request == NULL)
1562 if ((evhtp = request->htp) == NULL)
1567 if ((conn = request->conn) == NULL)
1572 if ((uri = request->uri) == NULL)
1577 if ((path = uri->path) == NULL)
1588 &path->matched_soff, &path->matched_eoff)))
1592 cbarg = callback->cbarg;
1593 hooks = callback->hooks;
1595 &path->matched_soff, &path->matched_eoff)))
1599 cbarg = callback->cbarg;
1600 hooks = callback->hooks;
1603 cb = evhtp->defaults.cb;
1604 cbarg = evhtp->defaults.cbarg;
1606 path->matched_soff = 0;
1607 path->matched_eoff = (
unsigned int)strlen(path->full);
1610 if (path->match_start == NULL)
1612 path->match_start =
htp__calloc_(strlen(path->full) + 1, 1);
1616 if (path->match_end == NULL)
1618 path->match_end =
htp__calloc_(strlen(path->full) + 1, 1);
1622 if (path->matched_soff != UINT_MAX )
1624 if (path->matched_eoff - path->matched_soff)
1626 memcpy(path->match_start, (
void *)(path->full + path->matched_soff),
1627 path->matched_eoff - path->matched_soff);
1629 memcpy(path->match_start, (
void *)(path->full + path->matched_soff),
1630 strlen((
const char *)(path->full + path->matched_soff)));
1633 memcpy(path->match_end,
1634 (
void *)(path->full + path->matched_eoff),
1635 strlen(path->full) - path->matched_eoff);
1640 if (request->hooks == NULL)
1646 memcpy(request->hooks, hooks,
sizeof(evhtp_hooks_t));
1650 request->cbarg =
cbarg;
1660 evhtp_t * evhtp_vhost;
1662 #ifndef EVHTP_DISABLE_SSL 1668 host = SSL_get_servername(c->ssl, TLSEXT_NAMETYPE_host_name);
1694 c->htp = evhtp_vhost;
1695 c->request->htp = evhtp_vhost;
1715 if (c != NULL && c->request != NULL)
1717 if (c->request->uri == NULL)
1731 evhtp_connection_t * c;
1732 evhtp_authority_t * authority;
1749 authority = c->request->uri->authority;
1753 if (authority->hostname == NULL)
1760 memcpy(authority->hostname, data, len);
1761 authority->hostname[
len] =
'\0';
1770 evhtp_authority_t * authority;
1779 authority = c->request->uri->authority;
1780 port = strtoul(data, &endptr, 10);
1782 if (endptr - data != len || port > 65535)
1789 authority->port = port;
1798 evhtp_path_t *
path;
1817 c->request->uri->path =
path;
1838 evhtp_connection_t * c;
1871 evbuffer_add_printf(bufferevent_get_output(c->bev),
1872 "HTTP/%c.%c 100 Continue\r\n\r\n",
1884 struct evbuffer * buf;
1887 if (c->max_body_size > 0 && c->body_bytes_read + len >= c->max_body_size)
1895 if ((buf = c->scratch_buf) == NULL)
1900 evbuffer_add(buf, data, len);
1907 if (evbuffer_get_length(buf))
1909 evbuffer_add_buffer(c->request->buffer_in, buf);
1912 evbuffer_drain(buf, -1);
1914 c->body_bytes_read +=
len;
1972 const char * content_type;
1979 if (req->uri == NULL || req->uri->query != NULL)
1990 evbuffer_get_length(req->buffer_in))
1995 content_type =
evhtp_kv_find(req->headers_in,
"content-type");
1997 if (content_type == NULL)
2002 if (strncasecmp(content_type,
"application/x-www-form-urlencoded", 33))
2030 struct evbuffer * buf_in;
2032 uri = c->request->uri;
2033 buf_in = c->request->buffer_in;
2035 body_len = evbuffer_get_length(buf_in);
2036 body = (
const char *)evbuffer_pullup(buf_in, body_len);
2041 memcpy(uri->query_raw, body, body_len);
2053 if (c->request && c->request->cb)
2055 (c->request->cb)(c->request, c->request->cbarg);
2069 struct evbuffer * buf = arg;
2071 evbuffer_expand(buf, header->klen + 2 + header->vlen + 2);
2072 evbuffer_add(buf, header->key, header->klen);
2073 evbuffer_add(buf,
": ", 2);
2074 evbuffer_add(buf, header->val, header->vlen);
2075 evbuffer_add(buf,
"\r\n", 2);
2080 static struct evbuffer *
2082 struct evbuffer * buf;
2083 const char * content_type;
2087 unsigned char major;
2088 unsigned char minor;
2092 && request->headers_out
2093 && request->buffer_out
2095 && request->rc_parser);
2098 out_len = evbuffer_get_length(request->buffer_out);
2100 if ((buf = request->rc_scratch) == NULL)
2102 request->rc_scratch = evbuffer_new();
2106 evbuffer_drain(buf, -1);
2130 switch (request->proto) {
2180 sres = snprintf(res_buf,
sizeof(res_buf),
"HTTP/%c.%c %s %s\r\n",
2183 if (sres >=
sizeof(res_buf) || sres < 0)
2188 evbuffer_add_printf(buf,
"HTTP/%c.%c %d %s\r\n",
2193 evbuffer_add(buf, res_buf, sres);
2198 evbuffer_add(buf,
"\r\n", 2);
2200 if (evbuffer_get_length(request->buffer_out))
2202 evbuffer_add_buffer(buf, request->buffer_out);
2235 evhtp_connection_t * c = arg;
2245 avail = evbuffer_get_length(bufferevent_get_input(bev));
2262 buf = evbuffer_pullup(bufferevent_get_input(bev), avail);
2267 nread =
htparser_run(c->parser, &request_psets, (
const char *)buf, avail);
2278 log_debug(
"EVHTP_CONN_FLAG_OWNER set, removing contexts");
2280 evbuffer_drain(bufferevent_get_input(bev), nread);
2288 switch (c->cr_status) {
2299 evbuffer_drain(bufferevent_get_input(bev), nread);
2308 log_debug(
"error %d, freeing connection",
2312 }
else if (nread < avail)
2315 log_debug(
"Reading more data via resumption");
2324 evhtp_connection_t * conn;
2325 uint64_t keepalive_max;
2326 const char * errstr;
2332 log_error(
"No data associated with the bufferevent %p", bev);
2334 bufferevent_free(bev);
2339 conn = (evhtp_connection_t *)arg;
2344 errstr =
"no request associated with connection";
2350 errstr =
"no parser registered with connection";
2358 errstr =
"no context associated with the server-connection";
2362 keepalive_max = conn->htp->max_keepalive_requests;
2370 log_error(
"shutting down connection: %s", errstr);
2389 bufferevent_enable(bev, EV_READ);
2391 if (evbuffer_get_length(bufferevent_get_input(bev)))
2405 || evbuffer_get_length(bufferevent_get_output(bev)))
2415 if (keepalive_max > 0)
2417 conn->num_requests += 1;
2419 if (conn->num_requests >= keepalive_max)
2439 conn->body_bytes_read = 0;
2443 if (conn->htp->parent != NULL
2451 conn->htp = conn->htp->parent;
2455 switch (conn->type) {
2457 type = htp_type_response;
2460 type = htp_type_request;
2485 evhtp_connection_t * c = arg;
2487 log_debug(
"%p %p eventcb %s%s%s%s", arg, (
void *)bev,
2488 events & BEV_EVENT_CONNECTED ?
"connected" :
"",
2489 events & BEV_EVENT_ERROR ?
"error" :
"",
2490 events & BEV_EVENT_TIMEOUT ?
"timeout" :
"",
2491 events & BEV_EVENT_EOF ?
"eof" :
"");
2493 if (c->hooks && c->hooks->on_event)
2495 (c->hooks->on_event)(c, events, c->hooks->on_event_arg);
2498 if ((events & BEV_EVENT_CONNECTED))
2506 bufferevent_setcb(bev,
2515 #ifndef EVHTP_DISABLE_SSL 2516 if (c->ssl && !(events & BEV_EVENT_EOF))
2519 unsigned long sslerr;
2521 while ((sslerr = bufferevent_get_openssl_error(bev))) {
2522 log_error(
"SSL ERROR %lu:%i:%s:%i:%s:%i:%s",
2524 ERR_GET_REASON(sslerr),
2525 ERR_reason_error_string(sslerr),
2526 ERR_GET_LIB(sslerr),
2527 ERR_lib_error_string(sslerr),
2528 ERR_GET_FUNC(sslerr),
2529 ERR_func_error_string(sslerr));
2543 if (events == (BEV_EVENT_EOF | BEV_EVENT_READING))
2545 if (errno == EAGAIN)
2555 bufferevent_enable(bev, EV_READ);
2584 evhtp_connection_t * c = arg;
2608 if (evbuffer_get_length(bufferevent_get_output(c->bev)))
2612 bufferevent_enable(c->bev, EV_WRITE);
2614 bufferevent_enable(c->bev, EV_READ | EV_WRITE);
2630 args = htp->defaults.pre_accept_cbarg;
2631 res = htp->defaults.pre_accept(conn, args);
2644 struct timeval * c_recv_timeo;
2645 struct timeval * c_send_timeo;
2649 evutil_closesocket(connection->sock);
2654 #ifndef EVHTP_DISABLE_SSL 2655 if (connection->htp->ssl_ctx != NULL)
2657 connection->ssl = SSL_new(connection->htp->ssl_ctx);
2658 connection->bev = bufferevent_openssl_socket_new(evbase,
2661 BUFFEREVENT_SSL_ACCEPTING,
2662 connection->htp->bev_flags);
2663 SSL_set_app_data(connection->ssl, connection);
2668 connection->bev = bufferevent_socket_new(evbase,
2670 connection->htp->bev_flags);
2672 log_debug(
"enter sock=%d\n", connection->sock);
2674 #ifndef EVHTP_DISABLE_SSL 2678 if (connection->recv_timeo.tv_sec || connection->recv_timeo.tv_usec)
2680 c_recv_timeo = &connection->recv_timeo;
2681 }
else if (connection->htp->recv_timeo.tv_sec ||
2682 connection->htp->recv_timeo.tv_usec)
2684 c_recv_timeo = &connection->htp->recv_timeo;
2686 c_recv_timeo = NULL;
2689 if (connection->send_timeo.tv_sec || connection->send_timeo.tv_usec)
2691 c_send_timeo = &connection->send_timeo;
2692 }
else if (connection->htp->send_timeo.tv_sec ||
2693 connection->htp->send_timeo.tv_usec)
2695 c_send_timeo = &connection->htp->send_timeo;
2697 c_send_timeo = NULL;
2702 connection->resume_ev = event_new(evbase, -1, EV_READ | EV_PERSIST,
2704 event_add(connection->resume_ev, NULL);
2706 bufferevent_enable(connection->bev, EV_READ);
2707 bufferevent_setcb(connection->bev,
2723 static evhtp_connection_t *
2726 evhtp_connection_t * connection;
2731 ptype = htp_type_response;
2734 ptype = htp_type_request;
2740 connection =
htp__calloc_(
sizeof(evhtp_connection_t), 1);
2743 connection->scratch_buf = evbuffer_new();
2747 connection->sock = sock;
2748 connection->htp = htp;
2749 connection->type =
type;
2760 #ifdef LIBEVENT_HAS_SHUTDOWN 2761 #ifndef EVHTP_DISABLE_SSL 2763 htp__shutdown_eventcb_(
struct bufferevent * bev,
short events,
void * arg)
2781 args = htp->defaults.post_accept_cbarg;
2782 res = htp->defaults.post_accept(connection, args);
2792 #ifndef EVHTP_DISABLE_EVTHR 2796 evhtp_t * htp = shared;
2797 evhtp_connection_t * connection = arg;
2800 connection->thread = thr;
2820 htp__accept_cb_(
struct evconnlistener * serv,
int fd,
struct sockaddr * s,
int sl,
void * arg)
2822 evhtp_t * htp = arg;
2823 evhtp_connection_t * connection;
2834 log_debug(
"fd = %d, conn = %p", fd, connection);
2839 memcpy(connection->saddr, s, sl);
2841 #ifndef EVHTP_DISABLE_EVTHR 2842 if (htp->thr_pool != NULL)
2847 evutil_closesocket(connection->sock);
2856 connection->evbase = htp->evbase;
2871 #ifndef EVHTP_DISABLE_SSL 2872 #ifndef EVHTP_DISABLE_EVTHR 2873 static unsigned long 2878 return (
unsigned long)pthread_self();
2881 return (
unsigned long)(pthread_self().p);
2888 if (type < ssl_num_locks)
2890 if (mode & CRYPTO_LOCK)
2892 pthread_mutex_lock(&(ssl_locks[type]));
2894 pthread_mutex_unlock(&(ssl_locks[type]));
2904 evhtp_ssl_cfg_t * cfg;
2908 htp = (evhtp_t *)SSL_CTX_get_app_data(ctx);
2912 if (cfg->scache_del)
2914 (cfg->scache_del)(htp, sid, slen);
2921 evhtp_connection_t * connection;
2922 evhtp_ssl_cfg_t * cfg;
2926 connection = (evhtp_connection_t *)SSL_get_app_data(ssl);
2927 if (connection->htp == NULL)
2932 cfg = connection->htp->ssl_cfg;
2935 SSL_set_timeout(sess, cfg->scache_timeout);
2937 if (cfg->scache_add)
2939 return (cfg->scache_add)(connection, sid, slen, sess);
2948 evhtp_connection_t * connection;
2949 evhtp_ssl_cfg_t * cfg;
2952 connection = (evhtp_connection_t * )SSL_get_app_data(ssl);
2954 if (connection->htp == NULL)
2958 cfg = connection->htp->ssl_cfg;
2961 if (cfg->scache_get)
2963 sess = (cfg->scache_get)(connection, sid, sid_len);
2975 evhtp_connection_t * connection;
2977 evhtp_t * evhtp_vhost;
2981 return SSL_TLSEXT_ERR_NOACK;
2984 if (!(sname = SSL_get_servername(ssl, TLSEXT_NAMETYPE_host_name)))
2986 return SSL_TLSEXT_ERR_NOACK;
2989 if (!(connection = SSL_get_app_data(ssl)))
2991 return SSL_TLSEXT_ERR_NOACK;
2994 if (!(evhtp = connection->htp))
2996 return SSL_TLSEXT_ERR_NOACK;
3001 SSL_CTX * ctx = SSL_get_SSL_CTX(ssl);
3003 connection->htp = evhtp_vhost;
3007 SSL_set_SSL_CTX(ssl, evhtp_vhost->ssl_ctx);
3008 SSL_set_options(ssl, SSL_CTX_get_options(ctx));
3010 if ((SSL_get_verify_mode(ssl) == SSL_VERIFY_NONE) ||
3011 (SSL_num_renegotiations(ssl) == 0))
3013 SSL_set_verify(ssl, SSL_CTX_get_verify_mode(ctx),
3014 SSL_CTX_get_verify_callback(ctx));
3017 return SSL_TLSEXT_ERR_OK;
3020 return SSL_TLSEXT_ERR_NOACK;
3046 bufferevent_disable(c->bev, EV_READ);
3058 event_active(c->resume_ev, EV_WRITE, 1);
3100 if (!headers || !val)
3110 if (header->val != NULL)
3115 header->vlen = strlen(val);
3122 header->val[header->vlen] =
'\0';
3123 memcpy(header->val, val, header->vlen);
3125 header->val = (
char *)val;
3128 header->v_heaped = val_alloc;
3148 char key_alloc,
char val_alloc)
3155 kv->k_heaped = key_alloc;
3156 kv->v_heaped = val_alloc;
3164 kv->klen = strlen(key);
3177 memcpy(s, key, kv->klen);
3182 kv->key = (
char *)key;
3188 kv->vlen = strlen(val);
3195 memcpy(s, val, kv->vlen);
3198 kv->val = (
char *)val;
3234 TAILQ_REMOVE(kvs, kv, next);
3253 for (kv = TAILQ_FIRST(kvs); kv != NULL; kv = save)
3255 save = TAILQ_NEXT(kv, next);
3257 TAILQ_REMOVE(kvs, kv, next);
3270 if (kvs == NULL || cb == NULL)
3275 TAILQ_FOREACH(kv, kvs, next) {
3278 if ((res =
cb(kv, arg)))
3297 TAILQ_FOREACH(kv, kvs, next) {
3298 if (strcasecmp(kv->key, key) == 0)
3317 TAILQ_FOREACH(kv, kvs, next) {
3318 if (strcasecmp(kv->key, key) == 0)
3335 TAILQ_INSERT_TAIL(kvs, kv, next);
3341 if (dst == NULL || src == NULL)
3348 TAILQ_FOREACH(kv, src, next) {
3405 unsigned char * optr;
3406 unsigned char * sptr;
3419 for (i = 0; i < str_len; i++)
3435 if (ch >=
'0' && ch <=
'9')
3437 d = (
unsigned char)(ch -
'0');
3442 c = (
unsigned char)(ch | 0x20);
3444 if (c >=
'a' && c <=
'f')
3446 d = (
unsigned char)(c -
'a' + 10);
3457 if (ch >=
'0' && ch <=
'9')
3459 ch = (
unsigned char)((d << 4) + ch -
'0');
3465 c = (
unsigned char)(ch | 0x20);
3467 if (c >=
'a' && c <=
'f')
3469 ch = (
unsigned char)((d << 4) + c -
'a' + 10);
3485 query_parser_state state;
3491 if (len > (SIZE_MAX - (len + 2)))
3502 #ifdef EVHTP_HAS_C99 3503 char key_buf[len + 1];
3504 char val_buf[len + 1];
3516 for (i = 0; i <
len; i++)
3520 if (key_idx >= len || val_idx >= len)
3541 key_buf[key_idx++] = ch;
3542 key_buf[key_idx] =
'\0';
3553 key_buf[key_idx++] = ch;
3554 key_buf[key_idx] =
'\0';
3580 key_buf[key_idx++] = ch;
3581 key_buf[key_idx] =
'\0';
3589 if ((key_idx + 2) >= len)
3595 key_buf[key_idx - 1] =
'%';
3596 key_buf[key_idx++] = ch;
3597 key_buf[key_idx] =
'\0';
3603 key_buf[key_idx++] = ch;
3604 key_buf[key_idx] =
'\0';
3614 key_buf[key_idx++] = ch;
3615 key_buf[key_idx] =
'\0';
3624 val_buf[val_idx++] = ch;
3625 val_buf[val_idx] =
'\0';
3640 val_buf[val_idx++] = ch;
3641 val_buf[val_idx] =
'\0';
3650 val_buf[val_idx++] = ch;
3651 val_buf[val_idx] =
'\0';
3660 if ((val_idx + 2) >= len)
3671 val_buf[val_idx - 1] =
'%';
3672 val_buf[val_idx++] = ch;
3673 val_buf[val_idx] =
'\0';
3679 val_buf[val_idx++] = ch;
3680 val_buf[val_idx] =
'\0';
3690 val_buf[val_idx++] = ch;
3691 val_buf[val_idx] =
'\0';
3730 #ifndef EVHTP_HAS_C99 3737 #ifndef EVHTP_HAS_C99 3757 evhtp_connection_t * c;
3758 struct evbuffer * reply_buf;
3769 bufferevent_write_buffer(c->bev, reply_buf);
3770 evbuffer_drain(reply_buf, -1);
3776 evhtp_connection_t * c;
3780 bufferevent_write_buffer(c->bev, buf);
3792 evhtp_connection_t * c;
3793 struct evbuffer * reply_buf;
3794 struct bufferevent * bev;
3809 bufferevent_lock(bev);
3811 bufferevent_write_buffer(bev, reply_buf);
3813 bufferevent_unlock(bev);
3815 evbuffer_drain(reply_buf, -1);
3821 return code != EVHTP_RES_NOCONTENT &&
3822 code != EVHTP_RES_NOTMOD &&
3823 (code < 100 || code >= 200) &&
3824 method != htp_method_HEAD;
3836 switch (request->proto) {
3875 if (evbuffer_get_length(request->buffer_out) > 0)
3880 sres = snprintf(lstr,
sizeof(lstr),
"%x\r\n",
3881 (
unsigned)evbuffer_get_length(request->buffer_out));
3883 if (sres >=
sizeof(lstr) || sres < 0)
3890 evbuffer_prepend(request->buffer_out, lstr, strlen(lstr));
3891 evbuffer_add(request->buffer_out,
"\r\n", 2);
3902 struct evbuffer * output;
3904 if (evbuffer_get_length(buf) == 0)
3909 output = bufferevent_get_output(request->conn->bev);
3913 evbuffer_add_printf(output,
"%x\r\n",
3914 (
unsigned)evbuffer_get_length(buf));
3921 evbuffer_add(output,
"\r\n", 2);
3924 bufferevent_flush(request->conn->bev, EV_WRITE, BEV_FLUSH);
3942 if (htp == NULL || htp->server == NULL)
3956 if (htp == NULL || sock == -1)
3962 #if defined SO_REUSEPORT 3965 if (setsockopt(sock, SOL_SOCKET, SO_REUSEPORT, (
void *)&on,
sizeof(on)) == -1)
3967 if (errno != EOPNOTSUPP) {
3971 log_warn(
"SO_REUSEPORT not supported for this socket.. Skipping");
3976 #if defined TCP_NODELAY 3979 if (setsockopt(sock, IPPROTO_TCP, TCP_NODELAY, (
void *)&on,
sizeof(on)) == -1)
3981 if (errno != EOPNOTSUPP) {
3985 log_warn(
"TCP_NODELAY not supported for this socket.. Skipping");
3990 #if defined TCP_DEFER_ACCEPT 3993 if (setsockopt(sock, IPPROTO_TCP, TCP_DEFER_ACCEPT, (
void *)&on,
sizeof(on)) == -1)
3995 if (errno != EOPNOTSUPP) {
3999 log_warn(
"TCP_DEFER_ACCEPT not supported for this socket.. Skipping");
4005 LEV_OPT_CLOSE_ON_FREE | LEV_OPT_REUSEABLE,
4008 if (htp->server == NULL)
4013 #ifndef EVHTP_DISABLE_SSL 4014 if (htp->ssl_ctx != NULL)
4021 if (TAILQ_FIRST(&htp->vhosts) != NULL)
4023 SSL_CTX_set_tlsext_servername_callback(htp->ssl_ctx,
4033 if (htp->server != NULL)
4047 evutil_socket_t fd = -1;
4058 signal(SIGPIPE, SIG_IGN);
4062 if ((fd = socket(sa->sa_family, SOCK_STREAM, 0)) == -1)
4068 evutil_make_socket_closeonexec(fd);
4069 evutil_make_socket_nonblocking(fd);
4071 if (setsockopt(fd, SOL_SOCKET, SO_KEEPALIVE, (
void *)&on,
sizeof(on)) == -1)
4076 if (setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, (
void *)&on,
sizeof(on)) == -1)
4081 if (sa->sa_family == AF_INET6)
4083 if (setsockopt(fd, IPPROTO_IPV6, IPV6_V6ONLY, &on,
sizeof(on)) == -1)
4089 if (bind(fd, sa, sin_len) == -1)
4102 evutil_closesocket(fd);
4113 evutil_closesocket(fd);
4125 struct sockaddr_un sockun = { 0 };
4127 struct sockaddr * sa;
4128 struct sockaddr_in6 sin6 = { 0 };
4129 struct sockaddr_in sin = { 0 };
4132 if (!strncmp(baddr,
"ipv6:", 5))
4135 sin_len =
sizeof(
struct sockaddr_in6);
4136 sin6.sin6_port = htons(port);
4137 sin6.sin6_family = AF_INET6;
4139 evutil_inet_pton(AF_INET6, baddr, &sin6.sin6_addr);
4140 sa = (
struct sockaddr *)&sin6;
4141 }
else if (!strncmp(baddr,
"unix:", 5))
4146 if (strlen(baddr) >=
sizeof(sockun.sun_path))
4151 sin_len =
sizeof(
struct sockaddr_un);
4152 sockun.sun_family = AF_UNIX;
4154 strncpy(sockun.sun_path, baddr, strlen(baddr));
4156 sa = (
struct sockaddr *)&sockun;
4162 if (!strncmp(baddr,
"ipv4:", 5))
4167 sin_len =
sizeof(
struct sockaddr_in);
4168 sin.sin_family = AF_INET;
4169 sin.sin_port = htons(port);
4170 sin.sin_addr.s_addr = inet_addr(baddr);
4172 sa = (
struct sockaddr *)&sin;
4181 evhtp_callback_t * callback;
4182 evhtp_callback_t * tmp;
4184 if (callbacks == NULL)
4190 TAILQ_REMOVE(callbacks, callback, next);
4201 evhtp_callback_t * hcb;
4209 hcb->len = strlen(path);
4216 #ifndef EVHTP_DISABLE_REGEX 4221 if (regcomp(hcb->val.regex, (
char *)path, REG_EXTENDED) != 0)
4246 if (callback == NULL)
4251 switch (callback->type) {
4258 #ifndef EVHTP_DISABLE_REGEX 4260 regfree(callback->val.regex);
4266 if (callback->hooks)
4279 TAILQ_INSERT_TAIL(cbs, cb, next);
4289 if (!(*hooks =
htp__calloc_(
sizeof(evhtp_hooks_t), 1)))
4298 (*hooks)->on_headers_start_arg = arg;
4302 (*hooks)->on_header_arg = arg;
4306 (*hooks)->on_headers_arg = arg;
4310 (*hooks)->on_path_arg = arg;
4314 (*hooks)->on_read_arg = arg;
4318 (*hooks)->on_request_fini_arg = arg;
4322 (*hooks)->on_connection_fini_arg = arg;
4326 (*hooks)->on_connection_error_arg = arg;
4330 (*hooks)->on_error_arg = arg;
4334 (*hooks)->on_new_chunk_arg = arg;
4338 (*hooks)->on_chunk_fini_arg = arg;
4342 (*hooks)->on_chunks_fini_arg = arg;
4346 (*hooks)->on_hostname_arg = arg;
4350 (*hooks)->on_write_arg = arg;
4354 (*hooks)->on_event_arg = arg;
4430 if (hooks == NULL) {
4434 for (i = 0; hooklist_[i].type != -1; i++) {
4486 evhtp_callback_t * hcb;
4490 if (htp->callbacks == NULL)
4499 TAILQ_INIT(htp->callbacks);
4525 evhtp_callback_t * callback;
4534 TAILQ_FOREACH(callback, htp->callbacks, next) {
4535 if (strcmp(callback->val.path, path) == 0)
4544 #ifndef EVHTP_DISABLE_EVTHR 4548 evhtp_t * htp = (evhtp_t *)arg;
4550 if (htp->thread_init_cb)
4552 htp->thread_init_cb(htp, thr, htp->thread_cbarg);
4559 evhtp_t * htp = (evhtp_t *)arg;
4561 if (htp->thread_exit_cb)
4563 htp->thread_exit_cb(htp, thr, htp->thread_cbarg);
4571 int nthreads,
void * arg)
4578 htp->thread_cbarg = arg;
4579 htp->thread_init_cb = init_cb;
4580 htp->thread_exit_cb = exit_cb;
4582 #ifndef EVHTP_DISABLE_SSL 4600 int nthreads,
void * arg)
4609 int nthreads,
void * arg)
4616 #ifndef EVHTP_DISABLE_EVTHR 4625 if (!(htp->lock =
htp__malloc_(
sizeof(pthread_mutex_t))))
4630 return pthread_mutex_init(htp->lock, NULL);
4635 #ifndef EVHTP_DISABLE_REGEX 4639 evhtp_callback_t * hcb;
4643 if (htp->callbacks == NULL)
4652 TAILQ_INIT(htp->callbacks);
4680 evhtp_callback_t * hcb;
4684 if (htp->callbacks == NULL)
4693 TAILQ_INIT(htp->callbacks);
4719 htp->defaults.cb =
cb;
4720 htp->defaults.cbarg = arg;
4726 htp->defaults.pre_accept =
cb;
4727 htp->defaults.pre_accept_cbarg = arg;
4733 htp->defaults.post_accept =
cb;
4734 htp->defaults.post_accept_cbarg = arg;
4737 #ifndef EVHTP_DISABLE_SSL 4738 #ifndef EVHTP_DISABLE_EVTHR 4744 if (ssl_locks_initialized == 1)
4749 ssl_locks_initialized = 1;
4750 ssl_num_locks = CRYPTO_num_locks();
4760 pthread_mutex_init(&(ssl_locks[i]), NULL);
4777 if (cfg == NULL || htp == NULL || cfg->pemfile == NULL)
4782 #if OPENSSL_VERSION_NUMBER < 0x10100000L 4784 ERR_load_crypto_strings();
4785 SSL_load_error_strings();
4786 OpenSSL_add_all_algorithms();
4804 if (RAND_poll() != 1) {
4809 if (RAND_bytes(&c, 1) != 1) {
4814 #if OPENSSL_VERSION_NUMBER < 0x10000000L 4815 STACK_OF(SSL_COMP) * comp_methods = SSL_COMP_get_compression_methods();
4816 sk_SSL_COMP_zero(comp_methods);
4820 #if OPENSSL_VERSION_NUMBER < 0x10100000L 4821 htp->ssl_ctx = SSL_CTX_new(SSLv23_server_method());
4823 htp->ssl_ctx = SSL_CTX_new(TLS_server_method());
4828 #if OPENSSL_VERSION_NUMBER >= 0x10000000L 4829 SSL_CTX_set_options(htp->ssl_ctx, SSL_MODE_RELEASE_BUFFERS | SSL_OP_NO_COMPRESSION);
4830 SSL_CTX_set_timeout(htp->ssl_ctx, cfg->ssl_ctx_timeout);
4833 SSL_CTX_set_options(htp->ssl_ctx, cfg->ssl_opts);
4835 #ifndef OPENSSL_NO_ECDH 4836 if (cfg->named_curve != NULL) {
4837 EC_KEY * ecdh = NULL;
4840 nid = OBJ_sn2nid(cfg->named_curve);
4843 log_error(
"ECDH initialization failed: unknown curve %s", cfg->named_curve);
4846 ecdh = EC_KEY_new_by_curve_name(nid);
4849 log_error(
"ECDH initialization failed for curve %s", cfg->named_curve);
4852 SSL_CTX_set_tmp_ecdh(htp->ssl_ctx, ecdh);
4856 #ifndef OPENSSL_NO_DH 4857 if (cfg->dhparams != NULL)
4862 fh = fopen(cfg->dhparams,
"r");
4866 dh = PEM_read_DHparams(fh, NULL, NULL, NULL);
4869 SSL_CTX_set_tmp_dh(htp->ssl_ctx, dh);
4872 log_error(
"DH initialization failed: unable to parse file %s", cfg->dhparams);
4877 log_error(
"DH initialization failed: unable to open file %s", cfg->dhparams);
4882 if (cfg->ciphers != NULL) {
4883 if (SSL_CTX_set_cipher_list(htp->ssl_ctx, cfg->ciphers) == 0) {
4889 SSL_CTX_load_verify_locations(htp->ssl_ctx, cfg->cafile, cfg->capath);
4890 X509_STORE_set_flags(SSL_CTX_get_cert_store(htp->ssl_ctx), cfg->store_flags);
4891 SSL_CTX_set_verify(htp->ssl_ctx, cfg->verify_peer, cfg->x509_verify_cb);
4893 if (cfg->x509_chk_issued_cb != NULL) {
4894 #if OPENSSL_VERSION_NUMBER < 0x10100000L 4895 htp->ssl_ctx->cert_store->check_issued = cfg->x509_chk_issued_cb;
4897 X509_STORE_set_check_issued(SSL_CTX_get_cert_store(htp->ssl_ctx), cfg->x509_chk_issued_cb);
4901 if (cfg->verify_depth) {
4902 SSL_CTX_set_verify_depth(htp->ssl_ctx, cfg->verify_depth);
4905 switch (cfg->scache_type) {
4907 cache_mode = SSL_SESS_CACHE_OFF;
4910 cache_mode = SSL_SESS_CACHE_SERVER;
4914 SSL_CTX_use_certificate_chain_file(htp->ssl_ctx, cfg->pemfile);
4916 char *
const key = cfg->privfile ? cfg->privfile : cfg->pemfile;
4918 if (cfg->decrypt_cb != NULL)
4920 EVP_PKEY * pkey = cfg->decrypt_cb(key);
4927 SSL_CTX_use_PrivateKey(htp->ssl_ctx, pkey);
4930 EVP_PKEY_free(pkey);
4932 SSL_CTX_use_PrivateKey_file(htp->ssl_ctx, key, SSL_FILETYPE_PEM);
4935 SSL_CTX_set_session_id_context(htp->ssl_ctx,
4936 (
void *)&session_id_context,
4937 sizeof(session_id_context));
4939 SSL_CTX_set_app_data(htp->ssl_ctx, htp);
4940 SSL_CTX_set_session_cache_mode(htp->ssl_ctx, cache_mode);
4942 if (cache_mode != SSL_SESS_CACHE_OFF)
4944 SSL_CTX_sess_set_cache_size(htp->ssl_ctx,
4945 cfg->scache_size ? cfg->scache_size : 1024);
4954 if (cfg->scache_init)
4956 cfg->args = (cfg->scache_init)(htp);
4966 struct bufferevent *
4968 return connection->bev;
4971 struct bufferevent *
4975 if (connection->hooks)
4980 if (connection->request && connection->request->hooks)
4992 bufferevent_disable(bev, EV_READ);
4993 bufferevent_setcb(bev, NULL, NULL, NULL, NULL);
4998 struct bufferevent *
5003 struct bufferevent *
5029 evhtp_connection_t *
5032 return request->conn;
5038 return request->proto;
5043 const struct timeval * rtimeo,
5044 const struct timeval * wtimeo)
5052 bufferevent_set_timeouts(c->bev, rtimeo, wtimeo);
5060 c->max_body_size = c->htp->max_body_size;
5062 c->max_body_size =
len;
5088 if (connection->resume_ev)
5093 if (connection->bev)
5095 #ifdef LIBEVENT_HAS_SHUTDOWN 5096 bufferevent_shutdown(connection->bev, htp__shutdown_eventcb_);
5098 #ifndef EVHTP_DISABLE_SSL 5099 if (connection->ssl != NULL)
5101 SSL_set_shutdown(connection->ssl, SSL_RECEIVED_SHUTDOWN);
5102 SSL_shutdown(connection->ssl);
5105 bufferevent_free(connection->bev);
5121 if (r_timeo != NULL)
5123 htp->recv_timeo = *r_timeo;
5126 if (w_timeo != NULL)
5128 htp->send_timeo = *w_timeo;
5135 htp->max_keepalive_requests = num;
5141 htp->bev_flags = flags;
5147 htp->max_body_size =
len;
5159 htp->parser_flags = flags;
5162 #define HTP_FLAG_FNGEN(NAME, TYPE) void \ 5163 evhtp ## NAME ## _enable_flag(TYPE v, int flag) { \ 5164 HTP_FLAG_ON(v, flag); \ 5168 evhtp ## NAME ## _disable_flag(TYPE v, int flag) { \ 5169 HTP_FLAG_OFF(v, flag); \ 5173 evhtp ## NAME ## _get_flags(TYPE v) { \ 5188 evhtp_alias_t * alias;
5200 log_debug(
"Adding %s to aliases", name);
5205 TAILQ_INSERT_TAIL(&evhtp->aliases, alias, next);
5219 va_start(argp, name);
5223 while ((p = va_arg(argp,
const char *)) != NULL) {
5238 if (evhtp == NULL || name == NULL || vhost == NULL)
5243 if (TAILQ_FIRST(&vhost->vhosts) != NULL)
5260 vhost->parent = evhtp;
5263 vhost->bev_flags = evhtp->bev_flags;
5264 vhost->max_body_size = evhtp->max_body_size;
5265 vhost->max_keepalive_requests = evhtp->max_keepalive_requests;
5266 vhost->recv_timeo = evhtp->recv_timeo;
5267 vhost->send_timeo = evhtp->send_timeo;
5269 TAILQ_INSERT_TAIL(&evhtp->vhosts, vhost, next_vhost);
5303 htp->evbase = evbase;
5305 htp->bev_flags = BEV_OPT_CLOSE_ON_FREE;
5311 TAILQ_INIT(&htp->vhosts);
5312 TAILQ_INIT(&htp->aliases);
5341 evhtp_alias_t * evhtp_alias, * tmp;
5348 #ifndef EVHTP_DISABLE_EVTHR 5349 if (evhtp->thr_pool)
5356 #ifndef EVHTP_DISABLE_SSL 5363 if (evhtp->server_name)
5368 if (evhtp->callbacks)
5374 if (evhtp_alias->alias != NULL)
5379 TAILQ_REMOVE(&evhtp->aliases, evhtp_alias, next);
5390 evhtp_connection_t *
5396 evhtp_connection_t *
5398 const char * addr, uint16_t port)
5400 evhtp_connection_t * conn;
5411 conn->evbase = evbase;
5412 conn->bev = bufferevent_socket_new(evbase, -1, BEV_OPT_CLOSE_ON_FREE);
5414 if (conn->bev == NULL)
5421 bufferevent_enable(conn->bev, EV_READ);
5422 bufferevent_setcb(conn->bev, NULL, NULL,
5425 if (dns_base != NULL)
5427 err = bufferevent_socket_connect_hostname(conn->bev, dns_base,
5428 AF_UNSPEC, addr, port);
5430 struct sockaddr_in sin4;
5431 struct sockaddr_in6 sin6;
5432 struct sockaddr * sin;
5435 if (inet_pton(AF_INET, addr, &sin4.sin_addr))
5437 sin4.sin_family = AF_INET;
5438 sin4.sin_port = htons(port);
5439 sin = (
struct sockaddr *)&sin4;
5440 salen =
sizeof(sin4);
5441 }
else if (inet_pton(AF_INET6, addr, &sin6.sin6_addr))
5443 sin6.sin6_family = AF_INET6;
5444 sin6.sin6_port = htons(port);
5445 sin = (
struct sockaddr *)&sin6;
5446 salen =
sizeof(sin6);
5454 err = bufferevent_socket_connect(conn->bev, sin, salen);
5468 #ifndef EVHTP_DISABLE_SSL 5470 #define ssl_sk_new_ bufferevent_openssl_socket_new 5471 #define ssl_sk_connect_ bufferevent_socket_connect 5473 evhtp_connection_t *
5479 evhtp_connection_t * conn;
5480 struct sockaddr_in sin;
5481 const char * errstr;
5492 conn->evbase = evbase;
5496 if ((conn->ssl = SSL_new(ctx)) == NULL) {
5497 errstr =
"unable to allocate SSL context";
5502 if ((conn->bev =
ssl_sk_new_(evbase, -1, conn->ssl,
5503 BUFFEREVENT_SSL_CONNECTING,
5504 BEV_OPT_CLOSE_ON_FREE)) == NULL) {
5505 errstr =
"unable to allocate bev context";
5509 if (bufferevent_enable(conn->bev, EV_READ) == -1) {
5510 errstr =
"unable to enable reading";
5515 bufferevent_setcb(conn->bev, NULL, NULL,
5519 sin.sin_family = AF_INET;
5520 sin.sin_addr.s_addr = inet_addr(addr);
5521 sin.sin_port = htons(port);
5524 (
struct sockaddr *)&sin,
5525 sizeof(sin)) == -1) {
5526 errstr =
"sk_connect_ failure";
5532 if (errstr != NULL) {
5549 evhtp_request_t * r;
5563 htp_method meth,
const char * uri)
5565 struct evbuffer * obuf;
5568 obuf = bufferevent_get_output(c->bev);
5582 evbuffer_add_printf(obuf,
"%s %s HTTP/%s\r\n",
5586 evbuffer_add_reference(obuf,
"\r\n", 2, NULL, NULL);
5588 if (evbuffer_get_length(r->buffer_out))
5590 evbuffer_add_buffer(obuf, r->buffer_out);
void evhtp_request_set_keepalive(evhtp_request_t *request, int val)
int evhtp_callbacks_add_callback(evhtp_callbacks_t *cbs, evhtp_callback_t *cb)
Adds a evhtp_callback_t to the evhtp_callbacks_t list.
void(* evhtp_thread_init_cb)(evhtp_t *htp, evthr_t *thr, void *arg)
evhtp_res(* evhtp_hook_write_cb)(evhtp_connection_t *conn, void *arg)
static evhtp_t * htp__request_find_vhost_(evhtp_t *evhtp, const char *name)
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 evthr_pool_start(evthr_pool_t *pool)
evthr_pool_t * evthr_pool_wexit_new(int nthreads, evthr_init_cb init_cb, evthr_exit_cb exit_cb, void *shared)
htp_scheme htparser_get_scheme(htparser *p)
static evhtp_res htp__hook_headers_start_(evhtp_request_t *request)
Runs the user defined on_headers_start hook.
int evhtp_connection_unset_hook(evhtp_connection_t *conn, evhtp_hook_type type)
type which defines to hook whenever an error occurs
static int htp__request_parse_fini_(htparser *p)
static htparse_hooks request_psets
callback definitions for request processing from libhtparse
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.
#define EVHTP_PARSE_QUERY_FLAG_DEFAULT
evhtp_res(* evhtp_hook_hostname_cb)(evhtp_request_t *r, const char *hostname, void *arg)
static int htp__uri_new_(evhtp_uri_t **out)
create an overlay URI structure
void evhtp_set_max_keepalive_requests(evhtp_t *htp, uint64_t num)
sets a maximum number of requests that a single connection can make.
unsigned char evhtp_ssl_data_t
static void htp__connection_readcb_(struct bufferevent *bev, void *arg)
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 evhtp_headers_find_header
static void htp__ssl_delete_scache_ent_(evhtp_ssl_ctx_t *ctx, evhtp_ssl_sess_t *sess)
static evhtp_res htp__hook_chunks_fini_(evhtp_request_t *request)
Runs the user defined on chunk_finis hook.
#define EVHTP_FLAG_ENABLE_100_CONT
struct bufferevent * evhtp_request_get_bev(evhtp_request_t *request)
returns the underlying requests bufferevent
void evhtp_set_mem_functions(void *(*mallocfn_)(size_t len), void *(*reallocfn_)(void *p, size_t sz), void(*freefn_)(void *p))
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.
void evhtp_disable_100_continue(evhtp_t *htp)
static void htp__connection_eventcb_(struct bufferevent *bev, short events, void *arg)
struct evhtp_callbacks_s evhtp_callbacks_t
#define EVHTP_REQ_FLAG_CHUNKED
static int htp__run_pre_accept_(evhtp_t *htp, evhtp_connection_t *conn)
#define evhtp_headers_for_each
evhtp_hooks_t * evhtp_request_get_hooks(evhtp_request_t *r)
returns request hooks
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 char * htp__strndup_(const char *str, size_t len)
implementation of strndup function.
#define EVHTP_FLAG_ENABLE_REUSEPORT
static int htp__request_set_callbacks_(evhtp_request_t *request)
union evhtp_callback_s::@0 val
EVHTP_EXPORT 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_send_reply_end(evhtp_request_t *request)
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
#define EVHTP_PARSE_QUERY_FLAG_ALLOW_EMPTY_VALS
htp_method evhtp_request_get_method(evhtp_request_t *r)
returns the htp_method enum version of the request method.
type which defines to hook once a path has been parsed
static int evhtp_is_hex_query_char(unsigned char ch)
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.
static void * htp__calloc_(size_t nmemb, size_t size)
Wrapper for calloc so that a different calloc can be used if desired.
struct bufferevent * evhtp_connection_get_bev(evhtp_connection_t *connection)
returns the underlying connections 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
static evhtp_connection_t * htp__connection_new_(evhtp_t *htp, evutil_socket_t sock, evhtp_type type)
static void htp__hook_error_(evhtp_request_t *request, evhtp_error_flags errtype)
runs the user-defined hook when a connection error occurs
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.
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
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.
static evhtp_res htp__hook_hostname_(evhtp_request_t *r, const char *hostname)
Runs the user defined hostname processing hook.
evhtp_proto evhtp_request_get_proto(evhtp_request_t *request)
evhtp_res(* evhtp_hook_conn_err_cb)(evhtp_connection_t *connection, evhtp_error_flags errtype, void *arg)
#define HOOK_REQUEST_RUN(request, hook_name,...)
evbase_t * evthr_get_base(evthr_t *thr)
static evhtp_res htp__hook_header_(evhtp_request_t *request, evhtp_header_t *header)
runs the user-defined on_header hook for a request
const char * htparser_get_methodstr_m(htp_method meth)
unsigned char htparser_get_multipart(htparser *p)
evhtp_hooks_t * evhtp_connection_get_hooks(evhtp_connection_t *c)
void evhtp_request_pause(evhtp_request_t *request)
Wrapper around evhtp_connection_pause.
#define HOOK_REQUEST_RUN_NARGS(__request, hook_name)
#define EVHTP_PARSE_QUERY_FLAG_TREAT_SEMICOLON_AS_SEP
int evhtp_ssl_init(evhtp_t *htp, evhtp_ssl_cfg_t *cfg)
static evhtp_res htp__hook_connection_error_(evhtp_connection_t *connection, evhtp_error_flags errtype)
runs the user-defined hook when a connection error occurs
evhtp_connection_t * evhtp_request_get_connection(evhtp_request_t *request)
returns the underlying evhtp_connection_t structure from a request
struct bufferevent * evhtp_request_take_ownership(evhtp_request_t *request)
pthread_mutex_t evhtp_mutex_t
evhtp_hooks_t * hooks
per-callback hooks
#define evhtp_request_content_len(r)
int evhtp_add_aliases(evhtp_t *htp, const char *name,...)
set a variable number of aliases in one call evhtp_add_alias
evhtp_hook_type
types associated with where a developer can hook into during the request processing cycle...
evhtp_res(* evhtp_hook_path_cb)(evhtp_request_t *req, evhtp_path_t *path, void *arg)
evhtp_connection_t * evhtp_connection_ssl_new(struct event_base *evbase, const char *addr, uint16_t port, evhtp_ssl_ctx_t *ctx)
static void htp__default_request_cb_(evhtp_request_t *request, void *arg)
void evhtp_connection_set_bev(evhtp_connection_t *conn, struct bufferevent *bev)
Sets the connections underlying bufferevent.
#define EVHTP_PARSE_QUERY_FLAG_IGNORE_HEX
static void(* free_)(void *d)
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'
static evhtp_res htp__hook_path_(evhtp_request_t *request, evhtp_path_t *path)
runs the user-defined on_path hook for a request
evhtp_res(* evhtp_hook_request_fini_cb)(evhtp_request_t *req, void *arg)
static int htp__request_parse_body_(htparser *p, const char *data, size_t len)
static int htp__request_parse_args_(htparser *p, const char *data, size_t len)
parses http request arguments
void htparser_set_minor(htparser *p, unsigned char minor)
void evhtp_request_free(evhtp_request_t *request)
void evhtp_kv_free(evhtp_kv_t *kv)
frees resources allocated for a single key/value
#define EVHTP_CONN_FLAG_VHOST_VIA_SNI
set to 1 if the vhost was found via SSL SNI
static int htp__connection_accept_(struct event_base *evbase, evhtp_connection_t *connection)
evhtp_hooks_t * evhtp_callback_get_hooks(evhtp_callback_t *cb)
returns callback hooks
evthr_res evthr_pool_stop(evthr_pool_t *pool)
static evhtp_request_t * htp__request_new_(evhtp_connection_t *c)
Creates a new evhtp_request_t.
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__run_in_thread_(evthr_t *thr, void *arg, void *shared)
#define EVHTP_PARSE_QUERY_FLAG_ALLOW_NULL_VALS
unsigned int evhtp_request_status(evhtp_request_t *r)
type which defines to hook before the request is free'd
static int htp__glob_match_(const char *pattern, size_t plen, const char *string, size_t str_len)
glob/wildcard type pattern matching.
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 .
void evthr_pool_free(evthr_pool_t *pool)
evhtp_res(* evhtp_hook_chunk_fini_cb)(evhtp_request_t *r, void *arg)
void evhtp_unbind_socket(evhtp_t *htp)
stops the listening socket.
static evhtp_mutex_t * ssl_locks
void(* evhtp_hook_err_cb)(evhtp_request_t *req, evhtp_error_flags errtype, void *arg)
evhtp_res(* evhtp_hook_header_cb)(evhtp_request_t *req, evhtp_header_t *hdr, void *arg)
void(* evhtp_thread_exit_cb)(evhtp_t *htp, evthr_t *thr, void *arg)
#define htp__is_http_11_(_major, _minor)
helper macro to determine if http version is HTTP/1.0
uint8_t evhtp_error_flags
htp_method htparser_get_method(htparser *p)
int evhtp_bind_sockaddr(evhtp_t *htp, struct sockaddr *sa, size_t sin_len, int backlog)
bind to an already allocated sockaddr.
evhtp_res(* evhtp_hook)()
static int htp__use_threads_(evhtp_t *htp, evhtp_thread_init_cb init_cb, evhtp_thread_exit_cb exit_cb, int nthreads, void *arg)
evhtp_res(* evhtp_hook_headers_cb)(evhtp_request_t *req, evhtp_headers_t *hdr, void *arg)
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_callback_free(evhtp_callback_t *callback)
safely frees callback structure memory and internals
#define EVHTP_RES_DATA_TOO_LONG
static int htp__request_parse_chunks_fini_(htparser *p)
static void htp__path_free_(evhtp_path_t *path)
Correctly frees the evhtp_path_t ptr that is passed in.
static int session_id_context
size_t htparser_run(htparser *p, htparse_hooks *hooks, const char *data, size_t len)
EVHTP_EXPORT 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
evhtp_request_t * evhtp_request_new(evhtp_callback_cb cb, void *arg)
allocate a new request
#define TAILQ_FOREACH_SAFE(var, head, field, tvar)
void evhtp_request_resume(evhtp_request_t *request)
Wrapper around evhtp_connection_resume.
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
void evhtp_callbacks_free(evhtp_callbacks_t *callbacks)
#define htp__unlock_(h)
Helper macro to unlock htp lock.
evthr_res evthr_pool_defer(evthr_pool_t *pool, evthr_cb cb, void *arg)
int evhtp_callback_set_hook(evhtp_callback_t *callback, evhtp_hook_type type, evhtp_hook cb, void *arg)
evhtp_callback_type type
the type of callback (regex|path)
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.
int evhtp_request_unset_hook(evhtp_request_t *req, evhtp_hook_type type)
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.
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.
structure containing a single callback and configuration
static int htp__request_parse_headers_start_(htparser *p)
static evhtp_res htp__hook_body_(evhtp_request_t *request, struct evbuffer *buf)
runs the user-defined on_body hook for requests containing a body.
void evhtp_request_set_bev(evhtp_request_t *request, struct bufferevent *bev)
sets the underlying bufferevent for a evhtp_request
static int htp__require_uri_(evhtp_connection_t *c)
static int htp__path_new_(evhtp_path_t **out, const char *data, size_t len)
parses the path and file from an input buffer
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...
#define EVHTP_CONN_FLAG_ERROR
static int htp__request_parse_path_(htparser *p, const char *data, size_t len)
evhtp_res(* evhtp_hook_connection_fini_cb)(evhtp_connection_t *connection, void *arg)
static void htp__free_(void *ptr)
Wrapper for free so that a different free can be used if desired.
static void htp__connection_resumecb_(int fd, short events, void *arg)
void evhtp_send_reply_start(evhtp_request_t *request, evhtp_res code)
type which defines to hook after all headers have been parsed
static evhtp_res htp__hook_connection_fini_(evhtp_connection_t *connection)
runs the user-definedhook called just prior to a connection being closed
static evhtp_res htp__hook_chunk_new_(evhtp_request_t *request, uint64_t len)
Runs the user defined request hook.
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
static int htp__request_parse_hostname_(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.
evhtp_t * evhtp_new(struct event_base *evbase, void *arg)
creates a new evhtp_t instance
#define evhtp_safe_free(_var, _freefn)
struct evhtp_kvs_s evhtp_kvs_t
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 ...
void evhtp_send_reply_body(evhtp_request_t *request, struct evbuffer *buf)
static void * htp__realloc_(void *ptr, size_t size)
Wrapper for realloc so that a different realloc can be used if desired.
static void htp__uri_free_(evhtp_uri_t *uri)
frees an overlay URI structure
static int htp__request_parse_chunk_new_(htparser *p)
EVHTP_EXPORT 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
static int htp__request_parse_header_key_(htparser *p, const char *data, size_t len)
void evhtp_set_bev_flags(evhtp_t *htp, int flags)
bufferevent flags which will be used for bev sockets.
static int ssl_locks_initialized
void * cbarg
user-defind arguments passed to the cb
static int htp__request_parse_port_(htparser *p, const char *data, size_t len)
#define htp__lock_(h)
Helper macro to lock htp structure.
evhtp_callback_cb cb
the actual callback function
evhtp_res(* evhtp_pre_accept_cb)(evhtp_connection_t *conn, void *arg)
void htparser_init(htparser *p, htp_type type)
#define htp__is_http_10_(_major, _minor)
helper function to determine if http version is HTTP/1.1
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.
unsigned char htparser_get_major(htparser *p)
#define EVHTP_FLAG_ENABLE_NODELAY
int(* evhtp_kvs_iterator)(evhtp_kv_t *kv, void *arg)
#define EVHTP_REQ_FLAG_ERROR
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
void evhtp_kvs_free(evhtp_kvs_t *kvs)
frees a the list of key/values, and all underlying entries
static int htp__unset_hook_(evhtp_hooks_t **hooks, evhtp_hook_type type)
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.
#define EVHTP_REQ_FLAG_KEEPALIVE
void evhtp_kvs_add_kv(evhtp_kvs_t *kvs, evhtp_kv_t *kv)
appends a key/val structure to a evhtp_kvs_t tailq
#define evhtp_modp_uchartoa(_val)
static void htp__thread_init_(evthr_t *thr, void *arg)
static int htp__set_hook_(evhtp_hooks_t **hooks, evhtp_hook_type type, evhtp_hook cb, void *arg)
int evhtp_add_alias(evhtp_t *evhtp, const char *name)
Add an alias hostname for a virtual-host specific evhtp_t.
type which defines to hook whenever the parser recieves data in a body
type which defines to hook whenever a connection error occurs
void evhtp_send_reply_chunk(evhtp_request_t *request, struct evbuffer *buf)
send a chunk reply.
static unsigned long htp__ssl_get_thread_id_(void)
evhtp_res(* evhtp_hook_headers_start_cb)(evhtp_request_t *r, void *arg)
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.
#define EVHTP_PARSE_QUERY_FLAG_STRICT
#define EVHTP_CONN_FLAG_FREE_CONN
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__request_parse_host_(htparser *p, const char *data, size_t len)
evhtp_connection_t * evhtp_connection_new(struct event_base *evbase, const char *addr, uint16_t port)
allocate a new connection
SSL_SESSION evhtp_ssl_sess_t
static int htp__request_parse_chunk_fini_(htparser *p)
static void htp__authority_free_(evhtp_authority_t *authority)
frees an authority structure
void evhtp_send_reply_chunk_start(evhtp_request_t *request, evhtp_res code)
start a chunked response.
evhtp_res(* evhtp_post_accept_cb)(evhtp_connection_t *conn, void *arg)
static void htp__request_free_(evhtp_request_t *request)
frees all data in an evhtp_request_t along with calling finished hooks
#define EVHTP_CONN_FLAG_WAITING
used to make sure resuming happens AFTER sending a reply
static void htp__connection_writecb_(struct bufferevent *bev, void *arg)
static int htp__request_parse_headers_(htparser *p)
static void * htp__malloc_(size_t size)
Wrapper for malloc so that a different malloc can be used if desired.
#define HTP_FLAG_OFF(PRE, FLAG)
static int htp__run_post_accept_(evhtp_t *htp, evhtp_connection_t *connection)
EVHTP_EXPORT size_t evhtp_modp_u32toa(uint32_t value, char *str)
converts uint32_t value to string
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...
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...
#define EVHTP_PARSE_QUERY_FLAG_IGNORE_FRAGMENTS
static struct evbuffer * htp__create_reply_(evhtp_request_t *request, evhtp_res code)
void htparser_set_userdata(htparser *p, void *ud)
static int htp__ssl_servername_(evhtp_ssl_t *ssl, int *unused, void *arg)
evhtp_callback_t * evhtp_get_cb(evhtp_t *htp, const char *path)
attempts to find the callback matching the exact string 'needle'.
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_hook_event_cb)(evhtp_connection_t *conn, short events, void *arg)
static evhtp_res htp__hook_chunk_fini_(evhtp_request_t *request)
Runs the user defined on_chunk_fini hook.
void * htparser_get_userdata(htparser *p)
static evhtp_res htp__hook_request_fini_(evhtp_request_t *request)
runs the user-defined hook called just prior to a request been free()'d
int evhtp_ssl_use_threads(void)
htpparse_error htparser_get_error(htparser *p)
void evhtp_connection_pause(evhtp_connection_t *c)
pauses a connection (disables reading)
static int evhtp__new_(evhtp_t **out, struct event_base *evbase, void *arg)
Allocates new evhtp_t structure.
static void htp__accept_cb_(struct evconnlistener *serv, int fd, struct sockaddr *s, int sl, void *arg)
static evhtp_res htp__hook_connection_write_(evhtp_connection_t *connection)
Runs the user defined on_write hook.
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
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 int htp__ssl_add_scache_ent_(evhtp_ssl_t *ssl, evhtp_ssl_sess_t *sess)
#define EVHTP_CONN_FLAG_OWNER
set to 1 if this structure owns the bufferevent
static void htp__ssl_thread_lock_(int mode, int type, const char *file, int line)
evhtp_res(* evhtp_hook_read_cb)(evhtp_request_t *req, struct evbuffer *buf, void *arg)
#define EVHTP_CONN_FLAG_CONNECTED
client specific - set after successful connection
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_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__thread_exit_(evthr_t *thr, void *arg)
static void *(* malloc_)(size_t sz)
int evhtp_unset_all_hooks(evhtp_hooks_t **hooks)
removes all hooks.
htparser * htparser_new(void)
unsigned int htparser_get_status(htparser *p)
const char * evhtp_kv_find(evhtp_kvs_t *kvs, const char *key)
find the string value of 'key' from the key/value list 'kvs'
uint64_t htparser_get_content_length(htparser *p)
void(* evhtp_callback_cb)(evhtp_request_t *req, void *arg)
static int htp__authority_new_(evhtp_authority_t **out)
create an authority structure
unsigned char htparser_get_minor(htparser *p)
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...
evhtp_res(* evhtp_hook_chunk_new_cb)(evhtp_request_t *r, uint64_t len, void *arg)
static int htp__create_headers_(evhtp_header_t *header, void *arg)
int evhtp_make_request(evhtp_connection_t *c, evhtp_request_t *r, htp_method meth, const char *uri)
make a client request
int evhtp_response_needs_body(const evhtp_res code, const htp_method method)
Determine if a response should have a body.
#define EVHTP_FLAG_ENABLE_DEFER_ACCEPT
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 char * htp__strdup_(const char *str)
implementation of strdup function.
evhtp_res(* evhtp_hook_chunks_fini_cb)(evhtp_request_t *r, void *arg)
#define EVHTP_FLAG_DEFAULTS
static int htp__should_parse_query_body_(evhtp_request_t *req)
determines if the request body contains the query arguments.
#define EVHTP_CONN_FLAG_KEEPALIVE
set to 1 after the first request has been processed and the connection is kept open ...
evhtp_kv_t * evhtp_kv_new(const char *key, const char *val, char key_alloc, char val_alloc)
Allocates a new key/value structure.
TAILQ_HEAD(evhtp_callbacks_s, evhtp_callback_s)
#define EVHTP_REQ_FLAG_FINISHED
int evhtp_callback_unset_hook(evhtp_callback_t *callback, evhtp_hook_type type)
#define EVHTP_CONN_FLAG_PAUSED
this connection has been marked as paused
#define evhtp_unlikely(x)
evhtp_kvs_t * evhtp_kvs_new(void)
creates an empty list of key/values
static const char * status_code_to_str(evhtp_res code)
returns string status code from enum code
static void *(* realloc_)(void *d, size_t sz)
static int htp__request_parse_start_(htparser *p)
Starts the parser for the connection associated with the parser struct.
type which defines to hook after one header has been parsed
static int htp__request_parse_header_val_(htparser *p, const char *data, size_t len)
int htparser_should_keep_alive(htparser *p)
int evhtp_request_set_hook(evhtp_request_t *req, evhtp_hook_type type, evhtp_hook cb, void *arg)
static evhtp_res htp__hook_headers_(evhtp_request_t *request, evhtp_headers_t *headers)
runs the user-defined on_Headers hook for a request after all headers have been parsed.
void evhtp_free(evhtp_t *evhtp)
Frees evhtp_t structure; will stop and free threads associated with the structure, and free the ssl context as well (if applicable).
#define HTP_FLAG_ON(PRE, FLAG)
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 htparser_set_major(htparser *p, unsigned char major)
#define evhtp_alloc_assert(x)
static evhtp_proto htp__protocol_(const char major, const char minor)
returns the HTTP protocol version
#define HTP_FLAG_FNGEN(NAME, TYPE)