10 #include <sys/socket.h>
11 #include <netinet/in.h>
12 #include <netinet/tcp.h>
13 #include <arpa/inet.h>
51 #define HOOK_AVAIL(var, hook_name) (var->hooks && var->hooks->hook_name)
52 #define HOOK_FUNC(var, hook_name) (var->hooks->hook_name)
53 #define HOOK_ARGS(var, hook_name) var->hooks->hook_name ## _arg
55 #define HOOK_REQUEST_RUN(request, hook_name, ...) do { \
56 if (HOOK_AVAIL(request, hook_name)) { \
57 return HOOK_FUNC(request, hook_name) (request, __VA_ARGS__, \
58 HOOK_ARGS(request, hook_name)); \
61 if (HOOK_AVAIL(evhtp_request_get_connection(request), hook_name)) { \
62 return HOOK_FUNC(request->conn, hook_name) (request, __VA_ARGS__, \
63 HOOK_ARGS(request->conn, hook_name)); \
67 #define HOOK_REQUEST_RUN_NARGS(request, hook_name) do { \
68 if (HOOK_AVAIL(request, hook_name)) { \
69 return HOOK_FUNC(request, hook_name) (request, \
70 HOOK_ARGS(request, hook_name)); \
73 if (HOOK_AVAIL(request->conn, hook_name)) { \
74 return HOOK_FUNC(request->conn, hook_name) (request, \
75 HOOK_ARGS(request->conn, hook_name)); \
79 #ifndef EVHTP_DISABLE_EVTHR
80 #define _evhtp_lock(h) do { \
82 pthread_mutex_lock(h->lock); \
86 #define _evhtp_unlock(h) do { \
88 pthread_mutex_unlock(h->lock); \
92 #define _evhtp_lock(h) do {} while (0)
93 #define _evhtp_unlock(h) do {} while (0)
96 #ifndef TAILQ_FOREACH_SAFE
97 #define TAILQ_FOREACH_SAFE(var, head, field, tvar) \
98 for ((var) = TAILQ_FIRST((head)); \
99 (var) && ((tvar) = TAILQ_NEXT((var), field), 1); \
127 #define scode_add(scode, cstr) do { \
128 struct status_code * c = malloc(sizeof(struct status_code)); \
133 RB_INSERT(status_code_tree, &status_code_head, c); \
137 status_code_init(
void) {
205 struct status_code c;
206 struct status_code * found;
210 if (!(found = RB_FIND(status_code_tree, &status_code_head, &c))) {
241 #ifndef EVHTP_DISABLE_SSL
243 #ifndef EVHTP_DISABLE_EVTHR
256 strnlen(
const char * s,
size_t maxlen) {
260 for (e = s, n = 0; *e && n < maxlen; e++, n++) {
271 strndup(
const char * s,
size_t n) {
272 size_t len = strnlen(s, n);
299 static inline unsigned int
303 for (; *
str; str++) {
320 if (major >= 1 && minor <= 0) {
337 if (major >= 1 && minor >= 1) {
524 if (!pattern || !
string) {
528 pat_len = strlen(pattern);
529 str_len = strlen(
string);
532 if (pattern[0] ==
'*') {
533 while (pattern[1] ==
'*') {
553 if (pattern[0] !=
string[0]) {
565 while (*pattern ==
'*') {
573 if (pat_len == 0 && str_len == 0) {
583 unsigned int * start_offset,
584 unsigned int * end_offset) {
585 #ifndef EVHTP_DISABLE_REGEX
586 regmatch_t pmatch[28];
594 TAILQ_FOREACH(callback, cbs, next) {
595 switch (callback->
type) {
597 if (strcmp(callback->
val.
path, path) == 0) {
599 *end_offset = (
unsigned int)strlen(path);
603 #ifndef EVHTP_DISABLE_REGEX
605 if (regexec(callback->
val.
regex, path, callback->
val.
regex->re_nsub + 1, pmatch, 0) == 0) {
606 *start_offset = pmatch[callback->
val.
regex->re_nsub].rm_so;
607 *end_offset = pmatch[callback->
val.
regex->re_nsub].rm_eo;
617 *end_offset = (
unsigned int)strlen(path);
644 req->
htp = c ? c->
htp : NULL;
664 if (request == NULL) {
683 free(request->
hooks);
740 const char * data_end = (
const char *)(data + len);
753 }
else if (*data !=
'/') {
758 file = strndup(data, len);
760 if (data[len - 1] !=
'/') {
767 for (i = (len - 1); i != 0; i--) {
768 if (data[i] ==
'/') {
776 path_len = (size_t)(&data[i] - data) + 1;
777 file_len = (size_t)(data_end - &data[i + 1]);
780 if ((
const char *)(data + path_len) > data_end) {
781 fprintf(stderr,
"PATH Corrupted.. (path_len > len)\n");
787 if ((
const char *)(&data[i + 1] + file_len) > data_end) {
788 fprintf(stderr,
"FILE Corrupted.. (file_len > len)\n");
793 path = strndup(data, path_len);
794 file = strndup(&data[i + 1], file_len);
800 if (i == 0 && data[i] ==
'/' && !file && !path) {
805 file = strndup((
const char *)(data + 1), len);
810 path = strndup(data, len);
815 req_path->
full = strndup(data, len);
818 req_path->
path = path;
819 req_path->
file = file;
907 key_s = malloc(len + 1);
909 memcpy(key_s, data, len);
926 val_s = malloc(len + 1);
928 memcpy(val_s, data, len);
936 header->v_heaped = 1;
950 TAILQ_FOREACH(evhtp_vhost, &evhtp->vhosts, next_vhost) {
959 TAILQ_FOREACH(evhtp_alias, &evhtp_vhost->aliases, next) {
960 if (evhtp_alias->
alias == NULL) {
984 if (request == NULL) {
988 if ((evhtp = request->
htp) == NULL) {
992 if ((conn = request->
conn) == NULL) {
996 if ((uri = request->
uri) == NULL) {
1000 if ((path = uri->
path) == NULL) {
1013 cbarg = callback->
cbarg;
1014 hooks = callback->
hooks;
1019 cbarg = callback->
cbarg;
1020 hooks = callback->
hooks;
1050 if (hooks != NULL) {
1051 if (request->
hooks == NULL) {
1059 request->
cbarg = cbarg;
1070 #ifndef EVHTP_DISABLE_SSL
1075 host = SSL_get_servername(c->
ssl, TLSEXT_NAMETYPE_host_name);
1099 c->
htp = evhtp_vhost;
1134 uri->
scheme = htparser_get_scheme(p);
1173 evbuffer_add_printf(bufferevent_get_output(c->
bev),
1174 "HTTP/%d.%d 100 Continue\r\n\r\n",
1175 htparser_get_major(p),
1176 htparser_get_minor(p));
1195 buf = evbuffer_new();
1196 evbuffer_add(buf, data, len);
1202 if (evbuffer_get_length(buf)) {
1259 const char * content_type;
1265 if (req->
uri == NULL || req->
uri->
query != NULL) {
1280 if (content_type == NULL) {
1284 if (strncasecmp(content_type,
"application/x-www-form-urlencoded", 33)) {
1307 body_len = evbuffer_get_length(buf_in);
1308 body = (
const char *)evbuffer_pullup(buf_in, body_len);
1310 uri->
query_raw = calloc(body_len + 1, 1);
1334 evbuffer_add(buf, header->key, header->klen);
1335 evbuffer_add(buf,
": ", 2);
1336 evbuffer_add(buf, header->val, header->vlen);
1337 evbuffer_add(buf,
"\r\n", 2);
1343 evbuf_t * buf = evbuffer_new();
1346 if (htparser_get_multipart(request->
conn->
parser) == 1) {
1357 sres = snprintf(lstr,
sizeof(lstr),
"%zu",
1359 sres = snprintf(lstr,
sizeof(lstr),
"%u",
1363 if (sres >=
sizeof(lstr) || sres < 0) {
1374 if (!content_type) {
1381 "transfer-encoding");
1383 if (!chunked || !strstr(chunked,
"chunked")) {
1392 switch (request->
proto) {
1410 htparser_set_major(request->
conn->
parser, 1);
1411 htparser_set_minor(request->
conn->
parser, 0);
1416 evbuffer_add_printf(buf,
"HTTP/%d.%d %d %s\r\n",
1422 evbuffer_add(buf,
"\r\n", 2);
1424 if (evbuffer_get_length(request->
buffer_out)) {
1425 evbuffer_add_buffer(buf, request->
buffer_out);
1437 bufferevent_enable(c->
bev, EV_READ);
1458 avail = evbuffer_get_length(bufferevent_get_input(bev));
1468 buf = evbuffer_pullup(bufferevent_get_input(bev), avail);
1470 bufferevent_disable(bev, EV_WRITE);
1474 bufferevent_enable(bev, EV_WRITE);
1476 if (c->
owner != 1) {
1481 evbuffer_drain(bufferevent_get_input(bev), nread);
1499 evbuffer_drain(bufferevent_get_input(bev), nread);
1503 }
else if (avail != nread) {
1522 if (c->
request->
finished == 0 || evbuffer_get_length(bufferevent_get_output(bev))) {
1554 htparser_init(c->
parser, htp_type_request);
1557 htparser_set_userdata(c->
parser, c);
1571 if ((events & BEV_EVENT_CONNECTED)) {
1573 bufferevent_setcb(bev,
1582 if (c->
ssl && !(events & BEV_EVENT_EOF)) {
1591 if (events == (BEV_EVENT_EOF | BEV_EVENT_READING)) {
1592 if (errno == EAGAIN) {
1601 bufferevent_enable(bev, EV_READ);
1643 struct timeval * c_recv_timeo;
1644 struct timeval * c_send_timeo;
1647 evutil_closesocket(connection->
sock);
1651 #ifndef EVHTP_DISABLE_SSL
1654 connection->
bev = bufferevent_openssl_socket_new(evbase,
1657 BUFFEREVENT_SSL_ACCEPTING,
1659 SSL_set_app_data(connection->
ssl, connection);
1664 connection->
bev = bufferevent_socket_new(evbase,
1667 #ifndef EVHTP_DISABLE_SSL
1677 c_recv_timeo = NULL;
1686 c_send_timeo = NULL;
1691 connection->
resume_ev = event_new(evbase, -1, EV_READ | EV_PERSIST,
1695 bufferevent_enable(connection->
bev, EV_READ);
1696 bufferevent_setcb(connection->
bev,
1716 ptype = htp_type_response;
1719 ptype = htp_type_request;
1729 connection->
error = 0;
1730 connection->
owner = 1;
1732 connection->
sock = sock;
1733 connection->
htp = htp;
1734 connection->
type = type;
1735 connection->
parser = htparser_new();
1737 htparser_init(connection->
parser, ptype);
1738 htparser_set_userdata(connection->
parser, connection);
1740 TAILQ_INIT(&connection->pending);
1745 #ifdef LIBEVENT_HAS_SHUTDOWN
1746 #ifndef EVHTP_DISABLE_SSL
1748 _evhtp_shutdown_eventcb(
evbev_t * bev,
short events,
void * arg) {
1773 #ifndef EVHTP_DISABLE_EVTHR
1779 connection->
evbase = evthr_get_base(thr);
1780 connection->
thread = thr;
1782 evthr_inc_backlog(connection->
thread);
1806 connection->
saddr = malloc(sl);
1807 memcpy(connection->
saddr, s, sl);
1809 #ifndef EVHTP_DISABLE_EVTHR
1812 evutil_closesocket(connection->
sock);
1832 #ifndef EVHTP_DISABLE_SSL
1833 #ifndef EVHTP_DISABLE_EVTHR
1834 static unsigned long
1837 return (
unsigned long)pthread_self();
1839 return (
unsigned long)(pthread_self().p);
1846 if (mode & CRYPTO_LOCK) {
1849 pthread_mutex_unlock(&(
ssl_locks[type]));
1859 unsigned char * sid;
1862 htp = (
evhtp_t *)SSL_CTX_get_app_data(ctx);
1865 sid = sess->session_id;
1866 slen = sess->session_id_length;
1877 unsigned char * sid;
1883 sid = sess->session_id;
1884 slen = sess->session_id_length;
1889 return (cfg->
scache_add)(connection, sid, slen, sess);
1906 sess = (cfg->
scache_get)(connection, sid, sid_len);
1921 if (!(sname = SSL_get_servername(ssl, TLSEXT_NAMETYPE_host_name))) {
1922 return SSL_TLSEXT_ERR_NOACK;
1925 if (!(connection = SSL_get_app_data(ssl))) {
1926 return SSL_TLSEXT_ERR_NOACK;
1929 if (!(evhtp = connection->
htp)) {
1930 return SSL_TLSEXT_ERR_NOACK;
1934 connection->
htp = evhtp_vhost;
1937 SSL_set_SSL_CTX(ssl, evhtp_vhost->
ssl_ctx);
1938 SSL_set_options(ssl, SSL_CTX_get_options(ssl->ctx));
1940 if ((SSL_get_verify_mode(ssl) == SSL_VERIFY_NONE) ||
1941 (SSL_num_renegotiations(ssl) == 0)) {
1942 SSL_set_verify(ssl, SSL_CTX_get_verify_mode(ssl->ctx),
1943 SSL_CTX_get_verify_callback(ssl->ctx));
1946 return SSL_TLSEXT_ERR_OK;
1949 return SSL_TLSEXT_ERR_NOACK;
1970 if ((bufferevent_get_enabled(c->
bev) & EV_READ)) {
1972 bufferevent_disable(c->
bev, EV_READ);
1983 if (!(bufferevent_get_enabled(c->
bev) & EV_READ)) {
1986 event_active(c->
resume_ev, EV_WRITE, 1);
2032 if (!headers || !val) {
2040 if (header->val != NULL) {
2044 header->vlen = strlen(val);
2047 header->val = malloc(header->vlen + 1);
2048 header->val[header->vlen] =
'\0';
2049 memcpy(header->val, val, header->vlen);
2051 header->val = (
char *)val;
2054 header->v_heaped = valloc;
2068 evhtp_kv_new(
const char * key,
const char * val,
char kalloc,
char valloc) {
2083 kv->
klen = strlen(key);
2086 char * s = malloc(kv->
klen + 1);
2089 memcpy(s, key, kv->
klen);
2092 kv->
key = (
char *)key;
2097 kv->
vlen = strlen(val);
2100 char * s = malloc(kv->
vlen + 1);
2103 memcpy(s, val, kv->
vlen);
2106 kv->
val = (
char *)val;
2132 if (kvs == NULL || kv == NULL) {
2136 TAILQ_REMOVE(kvs, kv, next);
2150 for (kv = TAILQ_FIRST(kvs); kv != NULL; kv = save) {
2151 save = TAILQ_NEXT(kv, next);
2153 TAILQ_REMOVE(kvs, kv, next);
2165 if (kvs == NULL || cb == NULL) {
2169 TAILQ_FOREACH(kv, kvs, next) {
2172 if ((res = cb(kv, arg))) {
2184 if (kvs == NULL || key == NULL) {
2188 TAILQ_FOREACH(kv, kvs, next) {
2189 if (strcasecmp(kv->
key, key) == 0) {
2201 if (kvs == NULL || key == NULL) {
2205 TAILQ_FOREACH(kv, kvs, next) {
2206 if (strcasecmp(kv->
key, key) == 0) {
2216 if (kvs == NULL || kv == NULL) {
2220 TAILQ_INSERT_TAIL(kvs, kv, next);
2225 if (dst == NULL || src == NULL) {
2231 TAILQ_FOREACH(kv, src, next) {
2282 unsigned char * optr;
2283 unsigned char * sptr;
2290 if (out == NULL || *out == NULL) {
2299 for (i = 0; i < str_len; i++) {
2313 if (ch >=
'0' && ch <=
'9') {
2314 d = (
unsigned char)(ch -
'0');
2319 c = (
unsigned char)(ch | 0x20);
2321 if (c >=
'a' && c <=
'f') {
2322 d = (
unsigned char)(c -
'a' + 10);
2333 if (ch >=
'0' && ch <=
'9') {
2334 ch = (
unsigned char)((d << 4) + ch -
'0');
2340 c = (
unsigned char)(ch | 0x20);
2342 if (c >=
'a' && c <=
'f') {
2343 ch = (
unsigned char)((d << 4) + c -
'a' + 10);
2359 char * key_buf = NULL;
2360 char * val_buf = NULL;
2368 if (!(key_buf = malloc(len + 1))) {
2372 if (!(val_buf = malloc(len + 1))) {
2380 for (i = 0; i < len; i++) {
2383 if (key_idx >= len || val_idx >= len) {
2389 memset(key_buf, 0, len);
2390 memset(val_buf, 0, len);
2427 key_buf[key_idx++] = ch;
2428 key_buf[key_idx] =
'\0';
2432 key_buf[key_idx++] = ch;
2433 key_buf[key_idx] =
'\0';
2440 if ((key_idx + 2) >= len) {
2445 key_buf[key_idx - 1] =
'%';
2446 key_buf[key_idx++] = ch;
2447 key_buf[key_idx] =
'\0';
2452 key_buf[key_idx++] = ch;
2453 key_buf[key_idx] =
'\0';
2462 key_buf[key_idx++] = ch;
2463 key_buf[key_idx] =
'\0';
2473 memset(key_buf, 0, len);
2474 memset(val_buf, 0, len);
2483 val_buf[val_idx++] = ch;
2484 val_buf[val_idx] =
'\0';
2489 val_buf[val_idx++] = ch;
2490 val_buf[val_idx] =
'\0';
2498 if ((val_idx + 2) >= len) {
2504 val_buf[val_idx - 1] =
'%';
2505 val_buf[val_idx++] = ch;
2506 val_buf[val_idx] =
'\0';
2512 val_buf[val_idx++] = ch;
2513 val_buf[val_idx] =
'\0';
2522 val_buf[val_idx++] = ch;
2523 val_buf[val_idx] =
'\0';
2533 if (key_idx && val_idx) {
2560 bufferevent_write_buffer(c->
bev, reply_buf);
2561 evbuffer_free(reply_buf);
2570 bufferevent_write_buffer(c->
bev, buf);
2595 evbuffer_free(reply_buf);
2602 (code < 100 || code >= 200) &&
2603 method != htp_method_HEAD;
2613 switch (request->
proto) {
2653 if (evbuffer_get_length(request->
buffer_out) > 0) {
2657 sres = snprintf(lstr,
sizeof(lstr),
"%x\r\n",
2658 (
unsigned)evbuffer_get_length(request->
buffer_out));
2660 if (sres >=
sizeof(lstr) || sres < 0) {
2666 evbuffer_prepend(request->
buffer_out, lstr, strlen(lstr));
2667 evbuffer_add(request->
buffer_out,
"\r\n", 2);
2679 output = bufferevent_get_output(request->
conn->
bev);
2681 if (evbuffer_get_length(buf) == 0) {
2685 evbuffer_add_printf(output,
"%x\r\n",
2686 (
unsigned)evbuffer_get_length(buf));
2690 evbuffer_add(output,
"\r\n", 2);
2692 bufferevent_flush(request->
conn->
bev, EV_WRITE, BEV_FLUSH);
2707 evconnlistener_free(htp->
server);
2714 signal(SIGPIPE, SIG_IGN);
2718 LEV_OPT_THREADSAFE | LEV_OPT_CLOSE_ON_FREE | LEV_OPT_REUSEABLE,
2719 backlog, sa, sin_len);
2724 #ifdef USE_DEFER_ACCEPT
2726 evutil_socket_t sock;
2729 sock = evconnlistener_get_fd(htp->
server);
2731 setsockopt(sock, IPPROTO_TCP, TCP_DEFER_ACCEPT, &one, (ev_socklen_t)
sizeof(one));
2732 setsockopt(sock, IPPROTO_TCP, TCP_NODELAY, &one, (ev_socklen_t)
sizeof(one));
2736 #ifndef EVHTP_DISABLE_SSL
2743 if (TAILQ_FIRST(&htp->vhosts) != NULL) {
2744 SSL_CTX_set_tlsext_servername_callback(htp->
ssl_ctx,
2755 struct sockaddr_in sin;
2756 struct sockaddr_in6 sin6;
2759 struct sockaddr_un sun;
2761 struct sockaddr * sa;
2764 memset(&sin, 0,
sizeof(sin));
2766 if (!strncmp(baddr,
"ipv6:", 5)) {
2767 memset(&sin6, 0,
sizeof(sin6));
2770 sin_len =
sizeof(
struct sockaddr_in6);
2771 sin6.sin6_port = htons(port);
2772 sin6.sin6_family = AF_INET6;
2774 evutil_inet_pton(AF_INET6, baddr, &sin6.sin6_addr);
2775 sa = (
struct sockaddr *)&sin6;
2776 }
else if (!strncmp(baddr,
"unix:", 5)) {
2780 if (strlen(baddr) >=
sizeof(sun.sun_path)) {
2784 memset(&sun, 0,
sizeof(sun));
2786 sin_len =
sizeof(
struct sockaddr_un);
2787 sun.sun_family = AF_UNIX;
2789 strncpy(sun.sun_path, baddr, strlen(baddr));
2791 sa = (
struct sockaddr *)&sun;
2793 fprintf(stderr,
"System does not support AF_UNIX sockets\n");
2797 if (!strncmp(baddr,
"ipv4:", 5)) {
2801 sin_len =
sizeof(
struct sockaddr_in);
2803 sin.sin_family = AF_INET;
2804 sin.sin_port = htons(port);
2805 sin.sin_addr.s_addr = inet_addr(baddr);
2807 sa = (
struct sockaddr *)&sin;
2818 if (callbacks == NULL) {
2823 TAILQ_REMOVE(callbacks, callback, next);
2848 #ifndef EVHTP_DISABLE_REGEX
2850 hcb->
val.
regex = malloc(
sizeof(regex_t));
2852 if (regcomp(hcb->
val.
regex, (
char *)path, REG_EXTENDED) != 0) {
2872 if (callback == NULL) {
2876 switch (callback->
type) {
2883 #ifndef EVHTP_DISABLE_REGEX
2891 if (callback->
hooks) {
2892 free(callback->
hooks);
2902 TAILQ_INSERT_TAIL(cbs, cb, next);
2909 if (*hooks == NULL) {
2918 (*hooks)->on_headers_start_arg = arg;
2922 (*hooks)->on_header_arg = arg;
2926 (*hooks)->on_headers_arg = arg;
2930 (*hooks)->on_path_arg = arg;
2934 (*hooks)->on_read_arg = arg;
2938 (*hooks)->on_request_fini_arg = arg;
2942 (*hooks)->on_connection_fini_arg = arg;
2946 (*hooks)->on_error_arg = arg;
2950 (*hooks)->on_new_chunk_arg = arg;
2954 (*hooks)->on_chunk_fini_arg = arg;
2958 (*hooks)->on_chunks_fini_arg = arg;
2962 (*hooks)->on_hostname_arg = arg;
2966 (*hooks)->on_write_arg = arg;
3069 #ifndef EVHTP_DISABLE_EVTHR
3084 #ifndef EVHTP_DISABLE_SSL
3098 #ifndef EVHTP_DISABLE_EVTHR
3105 if (!(htp->
lock = malloc(
sizeof(pthread_mutex_t)))) {
3109 return pthread_mutex_init(htp->
lock, NULL);
3114 #ifndef EVHTP_DISABLE_REGEX
3195 #ifndef EVHTP_DISABLE_SSL
3196 #ifndef EVHTP_DISABLE_EVTHR
3211 pthread_mutex_init(&(
ssl_locks[i]), NULL);
3230 if (cfg == NULL || htp == NULL || cfg->
pemfile == NULL) {
3235 SSL_load_error_strings();
3238 #if OPENSSL_VERSION_NUMBER < 0x10000000L
3239 STACK_OF(SSL_COMP) * comp_methods = SSL_COMP_get_compression_methods();
3240 sk_SSL_COMP_zero(comp_methods);
3244 htp->
ssl_ctx = SSL_CTX_new(SSLv23_server_method());
3246 #if OPENSSL_VERSION_NUMBER >= 0x10000000L
3247 SSL_CTX_set_options(htp->
ssl_ctx, SSL_MODE_RELEASE_BUFFERS | SSL_OP_NO_COMPRESSION);
3254 #ifndef OPENSSL_NO_ECDH
3256 EC_KEY * ecdh = NULL;
3261 fprintf(stderr,
"ECDH initialization failed: unknown curve %s\n", cfg->
named_curve);
3263 ecdh = EC_KEY_new_by_curve_name(nid);
3265 fprintf(stderr,
"ECDH initialization failed for curve %s\n", cfg->
named_curve);
3267 SSL_CTX_set_tmp_ecdh(htp->
ssl_ctx, ecdh);
3271 #ifndef OPENSSL_NO_DH
3278 dh = PEM_read_DHparams(fh, NULL, NULL, NULL);
3280 SSL_CTX_set_tmp_dh(htp->
ssl_ctx, dh);
3283 fprintf(stderr,
"DH initialization failed: unable to parse file %s\n", cfg->
dhparams);
3287 fprintf(stderr,
"DH initialization failed: unable to open file %s\n", cfg->
dhparams);
3310 cache_mode = SSL_SESS_CACHE_OFF;
3313 cache_mode = SSL_SESS_CACHE_SERVER |
3314 SSL_SESS_CACHE_NO_INTERNAL |
3315 SSL_SESS_CACHE_NO_INTERNAL_LOOKUP;
3323 cache_mode = SSL_SESS_CACHE_SERVER |
3324 SSL_SESS_CACHE_NO_INTERNAL |
3325 SSL_SESS_CACHE_NO_INTERNAL_LOOKUP;
3328 init_cb = _evhtp_ssl_builtin_init;
3329 add_cb = _evhtp_ssl_builtin_add;
3330 get_cb = _evhtp_ssl_builtin_get;
3331 del_cb = _evhtp_ssl_builtin_del;
3336 cache_mode = SSL_SESS_CACHE_SERVER;
3340 SSL_CTX_use_certificate_file(htp->
ssl_ctx, cfg->
pemfile, SSL_FILETYPE_PEM);
3341 SSL_CTX_use_PrivateKey_file(htp->
ssl_ctx,
3344 SSL_CTX_set_session_id_context(htp->
ssl_ctx,
3348 SSL_CTX_set_app_data(htp->
ssl_ctx, htp);
3349 SSL_CTX_set_session_cache_mode(htp->
ssl_ctx, cache_mode);
3351 if (cache_mode != SSL_SESS_CACHE_OFF) {
3352 SSL_CTX_sess_set_cache_size(htp->
ssl_ctx,
3374 return connection->
bev;
3381 if (connection->
hooks) {
3391 connection->
owner = 0;
3393 bufferevent_disable(bev, EV_READ);
3394 bufferevent_setcb(bev, NULL, NULL, NULL, NULL);
3421 return request->
conn;
3426 const struct timeval * rtimeo,
3427 const struct timeval * wtimeo) {
3432 bufferevent_set_timeouts(c->
bev, rtimeo, wtimeo);
3451 if (connection == NULL) {
3458 free(connection->
parser);
3459 free(connection->
hooks);
3460 free(connection->
saddr);
3466 if (connection->
bev) {
3467 #ifdef LIBEVENT_HAS_SHUTDOWN
3468 bufferevent_shutdown(connection->
bev, _evhtp_shutdown_eventcb);
3470 #ifndef EVHTP_DISABLE_SSL
3471 if (connection->
ssl != NULL) {
3472 SSL_set_shutdown(connection->
ssl, SSL_RECEIVED_SHUTDOWN);
3473 SSL_shutdown(connection->
ssl);
3476 bufferevent_free(connection->
bev);
3480 #ifndef EVHTP_DISABLE_EVTHR
3482 evthr_dec_backlog(connection->
thread);
3500 if (r_timeo != NULL) {
3504 if (w_timeo != NULL) {
3539 if (evhtp == NULL || name == NULL) {
3547 alias->
alias = strdup(name);
3549 TAILQ_INSERT_TAIL(&evhtp->aliases, alias, next);
3572 if (evhtp == NULL || name == NULL || vhost == NULL) {
3576 if (TAILQ_FIRST(&vhost->vhosts) != NULL) {
3600 TAILQ_INSERT_TAIL(&evhtp->vhosts, vhost, next_vhost);
3609 if (evbase == NULL) {
3613 if (!(htp = calloc(
sizeof(
evhtp_t), 1))) {
3623 TAILQ_INIT(&htp->vhosts);
3624 TAILQ_INIT(&htp->aliases);
3635 if (evhtp == NULL) {
3639 #ifndef EVHTP_DISABLE_EVTHR
3655 if (evhtp_alias->
alias != NULL) {
3656 free(evhtp_alias->
alias);
3658 TAILQ_REMOVE(&evhtp->aliases, evhtp_alias, next);
3662 #ifndef EVHTP_DISABLE_SSL
3673 size_t read_rate,
size_t read_burst,
3674 size_t write_rate,
size_t write_burst,
3675 const struct timeval * tick) {
3676 struct ev_token_bucket_cfg * tcfg;
3678 if (conn == NULL || conn->
bev == NULL) {
3682 tcfg = ev_token_bucket_cfg_new(read_rate, read_burst,
3683 write_rate, write_burst, tick);
3691 return bufferevent_set_rate_limit(conn->
bev, tcfg);
3701 struct sockaddr_in sin;
3703 if (evbase == NULL) {
3711 sin.sin_family = AF_INET;
3712 sin.sin_addr.s_addr = inet_addr(addr);
3713 sin.sin_port = htons(port);
3716 conn->
bev = bufferevent_socket_new(evbase, -1, BEV_OPT_CLOSE_ON_FREE);
3718 bufferevent_enable(conn->
bev, EV_READ);
3720 bufferevent_setcb(conn->
bev, NULL, NULL,
3723 bufferevent_socket_connect(conn->
bev,
3724 (
struct sockaddr *)&sin,
sizeof(sin));
3746 htp_method meth,
const char * uri) {
3750 obuf = bufferevent_get_output(c->
bev);
3764 evbuffer_add_printf(obuf,
"%s %s HTTP/%s\r\n",
3765 htparser_get_methodstr_m(meth), uri, proto);
3768 evbuffer_add_reference(obuf,
"\r\n", 2, NULL, NULL);
evhtp_callbacks_t * callbacks
#define EVHTP_RES_SWITCHPROXY
int evhtp_callbacks_add_callback(evhtp_callbacks_t *cbs, evhtp_callback_t *cb)
Adds a evhtp_callback_t to the evhtp_callbacks_t list.
#define EVHTP_RES_SERVUNAVAIL
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. The addr can be defined as on...
static evhtp_res _evhtp_header_hook(evhtp_request_t *request, evhtp_header_t *header)
runs the user-defined on_header hook for a request
void(* evhtp_ssl_scache_del)(evhtp_t *htp, unsigned char *sid, int sid_len)
evhtp_res(* evhtp_hook_header_cb)(evhtp_request_t *req, evhtp_header_t *hdr, void *arg)
static int _evhtp_glob_match(const char *pattern, const char *string)
glob/wildcard type pattern matching.
evhtp_ssl_scache_init scache_init
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)
static unsigned int _evhtp_quick_hash(const char *str)
a weak hash function
evhtp_ssl_sess_t *(* evhtp_ssl_scache_get)(evhtp_connection_t *connection, unsigned char *sid, int sid_len)
#define EVHTP_RES_METHNALLOWED
void evhtp_set_max_keepalive_requests(evhtp_t *htp, uint64_t num)
sets a maximum number of requests that a single connection can make.
evhtp_ssl_scache_del scache_del
void * on_connection_fini_arg
int evhtp_add_vhost(evhtp_t *evhtp, const char *name, evhtp_t *vhost)
add a virtual host.
int(* evhtp_ssl_scache_add)(evhtp_connection_t *connection, unsigned char *sid, int sid_len, evhtp_ssl_sess_t *sess)
#define EVHTP_RES_ENTOOLARGE
evhtp_ssl_chk_issued_cb x509_chk_issued_cb
evhtp_header_t * evhtp_header_val_add(evhtp_headers_t *headers, const char *val, char valloc)
finds the last header in the headers tailq and adds the value
const char * status_code_to_str(evhtp_res code)
#define EVHTP_RES_SWITCH_PROTO
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. This will add the last 0CRLFC...
void evhtp_disable_100_continue(evhtp_t *htp)
when a client sends an Expect: 100-continue, if this is function is called, evhtp will not send a HTT...
evbev_t * evhtp_connection_take_ownership(evhtp_connection_t *connection)
let a user take ownership of the underlying bufferevent and free all other underlying resources...
static evhtp_res _evhtp_connection_write_hook(evhtp_connection_t *connection)
#define EVHTP_RES_IAMATEAPOT
#define EVHTP_RES_BADGATEWAY
#define EVHTP_RES_TMPREDIR
static int _evhtp_request_parser_hostname(htparser *p, const char *data, size_t len)
#define EVHTP_RES_PRECONDFAIL
static evhtp_connection_t * _evhtp_connection_new(evhtp_t *htp, evutil_socket_t sock, evhtp_type type)
int evhtp_unset_hook(evhtp_hooks_t **hooks, evhtp_hook_type type)
remove a specific hook from being called.
void evhtp_send_reply_chunk(evhtp_request_t *request, evbuf_t *buf)
send a chunk reply.
unsigned char * query_raw
evhtp_thread_init_cb thread_init_cb
int evhtp_use_callback_locks(evhtp_t *htp)
creates a lock around callbacks and hooks, allowing for threaded applications to add/remove/modify ho...
evhtp_ssl_verify_cb x509_verify_cb
#define EVHTP_RES_SERVERR
void evhtp_send_reply_end(evhtp_request_t *request)
evhtp_hook_write_cb on_write
evhtp_ssl_cfg_t * ssl_cfg
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
htp_method evhtp_request_get_method(evhtp_request_t *r)
returns the htp_method enum version of the request method.
static int _evhtp_request_parser_chunk_new(htparser *p)
static int evhtp_is_hex_query_char(unsigned char ch)
evhtp_defaults_t defaults
static int _evhtp_is_http_11(const char major, const char minor)
helper function to determine if http version is HTTP/1.1
void(* evhtp_callback_cb)(evhtp_request_t *req, void *arg)
static int _evhtp_request_parser_path(htparser *p, const char *data, size_t len)
main structure containing all configuration information
evhtp_res(* evhtp_hook)()
void evhtp_send_reply(evhtp_request_t *request, evhtp_res code)
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. When the timeout expires your error hook will be call...
#define HOOK_REQUEST_RUN(request, hook_name,...)
static int _evhtp_request_set_callbacks(evhtp_request_t *request)
void evhtp_request_pause(evhtp_request_t *request)
Wrapper around evhtp_connection_pause.
int evhtp_ssl_init(evhtp_t *htp, evhtp_ssl_cfg_t *cfg)
evhtp_request_t * request
evhtp_res(* evhtp_hook_chunks_fini_cb)(evhtp_request_t *r, void *arg)
evhtp_connection_t * evhtp_request_get_connection(evhtp_request_t *request)
returns the underlying evhtp_connection_t structure from a request
#define TAILQ_FOREACH_SAFE(var, head, field, tvar)
static int _evhtp_run_pre_accept(evhtp_t *htp, evhtp_connection_t *conn)
#define EVHTP_RES_UNSUPPORTED
void evhtp_connection_set_bev(evhtp_connection_t *conn, evbev_t *bev)
Sets the connections underlying bufferevent.
void(* evhtp_hook_err_cb)(evhtp_request_t *req, evhtp_error_flags errtype, void *arg)
struct evhtp_callbacks_s evhtp_callbacks_t
static evhtp_uri_t * _evhtp_uri_new(void)
create an overlay URI structure
#define EVHTP_RES_GWTIMEOUT
#define EVHTP_RES_SEEOTHER
static evhtp_t * _evhtp_request_find_vhost(evhtp_t *evhtp, const char *name)
static evhtp_res _evhtp_hostname_hook(evhtp_request_t *r, const char *hostname)
static int _evhtp_ssl_add_scache_ent(evhtp_ssl_t *ssl, evhtp_ssl_sess_t *sess)
int evhtp_connection_set_rate_limit(evhtp_connection_t *conn, size_t read_rate, size_t read_burst, size_t write_rate, size_t write_burst, const struct timeval *tick)
int evhtp_kvs_for_each(evhtp_kvs_t *kvs, evhtp_kvs_iterator cb, void *arg)
SSL_SESSION evhtp_ssl_sess_t
evhtp_headers_t * headers_in
#define EVHTP_RES_EXPECTFAIL
void evhtp_request_free(evhtp_request_t *request)
evhtp_ssl_scache_type scache_type
#define EVHTP_RES_CREATED
void evhtp_kv_free(evhtp_kv_t *kv)
struct ev_token_bucket_cfg * ratelimit_cfg
#define EVHTP_RES_MOVEDPERM
unsigned int evhtp_request_status(evhtp_request_t *r)
evhtp_res(* evhtp_hook_headers_start_cb)(evhtp_request_t *r, void *arg)
#define EVHTP_RES_MSTATUS
evhtp_connection_t * evhtp_connection_new(evbase_t *evbase, const char *addr, uint16_t port)
allocate a new connection
struct evhtp_kvs_s evhtp_kvs_t
static evhtp_res _evhtp_chunk_fini_hook(evhtp_request_t *request)
static int _evhtp_request_parser_chunk_fini(htparser *p)
#define EVHTP_RES_NAUTHINFO
void evhtp_unbind_socket(evhtp_t *htp)
stops the listening socket.
static evhtp_mutex_t * ssl_locks
evhtp_headers_t * headers_out
#define EVHTP_RES_DATA_TOO_LONG
static int _evhtp_create_headers(evhtp_header_t *header, void *arg)
evhtp_res(* evhtp_hook_chunk_new_cb)(evhtp_request_t *r, uint64_t len, void *arg)
int evhtp_bind_sockaddr(evhtp_t *htp, struct sockaddr *sa, size_t sin_len, int backlog)
bind to an already allocated sockaddr.
a generic key/value structure
a structure containing all information for a http request.
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}'.
struct timeval send_timeo
void evhtp_callback_free(evhtp_callback_t *callback)
void(* evhtp_thread_init_cb)(evhtp_t *htp, evthr_t *thr, void *arg)
static int session_id_context
evhtp_res(* evhtp_hook_headers_cb)(evhtp_request_t *req, evhtp_headers_t *hdr, void *arg)
evhtp_request_t * evhtp_request_new(evhtp_callback_cb cb, void *arg)
allocate a new request
#define scode_add(scode, cstr)
#define evhtp_headers_find_header
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 EVHTP_RES_NOCONTENT
evhtp_hook_type
types associated with where a developer can hook into during the request processing cycle...
union evhtp_callback_s::@0 val
evhtp_pre_accept_cb pre_accept
#define EVHTP_RES_PROXYAUTHREQ
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.
static evhtp_ssl_sess_t * _evhtp_ssl_get_scache_ent(evhtp_ssl_t *ssl, unsigned char *sid, int sid_len, int *copy)
void evhtp_set_pre_accept_cb(evhtp_t *htp, evhtp_pre_accept_cb cb, void *arg)
structure containing a single callback and configuration
evhtp_res(* evhtp_hook_read_cb)(evhtp_request_t *req, evbuf_t *buf, void *arg)
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...
int(* evhtp_kvs_iterator)(evhtp_kv_t *kv, void *arg)
#define EVHTP_RES_RANGENOTSC
void evhtp_free(evhtp_t *evhtp)
void evhtp_send_reply_start(evhtp_request_t *request, evhtp_res code)
evhtp_post_accept_cb post_accept
static void _evhtp_thread_init(evthr_t *thr, void *arg)
static int _evhtp_request_parser_headers(htparser *p)
static int _evhtp_request_parser_header_key(htparser *p, const char *data, size_t len)
evhtp_ssl_ctx_t * ssl_ctx
void evhtp_connection_resume(evhtp_connection_t *c)
resumes a connection (enables reading) and activates resume event.
static void _evhtp_run_in_thread(evthr_t *thr, void *arg, void *shared)
int evhtp_set_hook(evhtp_hooks_t **hooks, evhtp_hook_type type, evhtp_hook cb, void *arg)
sets a callback hook for either a connection or a path/regex .
static int _evhtp_run_post_accept(evhtp_t *htp, evhtp_connection_t *connection)
static int _evhtp_request_parser_start(htparser *p)
#define EVHTP_RES_CONFLICT
static void _evhtp_connection_eventcb(evbev_t *bev, short events, void *arg)
static int _evhtp_connection_accept(evbase_t *evbase, evhtp_connection_t *connection)
static void _evhtp_connection_resumecb(int fd, short events, void *arg)
static evhtp_path_t * _evhtp_path_new(const char *data, size_t len)
parses the path and file from an input buffer
#define EVHTP_RES_URITOOLARGE
a generic container representing an entire URI strucutre
evhtp_ssl_scache_get scache_get
struct evconnlistener evserv_t
static unsigned long _evhtp_ssl_get_thread_id(void)
static int _evhtp_should_parse_query_body(evhtp_request_t *req)
determines if the request body contains the query arguments. if the query is NULL and the contenet le...
evhtp_res(* evhtp_hook_chunk_fini_cb)(evhtp_request_t *r, void *arg)
void evhtp_set_bev_flags(evhtp_t *htp, int flags)
set bufferevent flags, defaults to BEV_OPT_CLOSE_ON_FREE
#define EVHTP_RES_TIMEOUT
static int ssl_locks_initialized
evbev_t * evhtp_request_get_bev(evhtp_request_t *request)
returns the underlying requests bufferevent
#define EVHTP_RES_PROCESSING
static evhtp_res _evhtp_chunks_fini_hook(evhtp_request_t *request)
evbev_t * evhtp_connection_get_bev(evhtp_connection_t *connection)
returns the underlying connections bufferevent
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 int scode_tree_initialized
static int _evhtp_is_http_10(const char major, const char minor)
helper function to determine if http version is HTTP/1.0
static evhtp_request_t * _evhtp_request_new(evhtp_connection_t *c)
Creates a new evhtp_request_t.
static void _evhtp_request_free(evhtp_request_t *request)
frees all data in an evhtp_request_t along with calling finished hooks
static evbuf_t * _evhtp_create_reply(evhtp_request_t *request, evhtp_res 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
void evhtp_send_reply_body(evhtp_request_t *request, evbuf_t *buf)
static int _evhtp_request_parser_args(htparser *p, const char *data, size_t len)
void evhtp_kvs_free(evhtp_kvs_t *kvs)
evhtp_res(* evhtp_hook_write_cb)(evhtp_connection_t *conn, void *arg)
pthread_mutex_t evhtp_mutex_t
#define EVHTP_RES_FORBIDDEN
evhtp_res(* evhtp_hook_request_fini_cb)(evhtp_request_t *req, void *arg)
evbev_t * evhtp_request_take_ownership(evhtp_request_t *request)
evhtp_connection_t * conn
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 evhtp_res _evhtp_path_hook(evhtp_request_t *request, evhtp_path_t *path)
runs the user-defined on_path hook for a request
static int _evhtp_ssl_servername(evhtp_ssl_t *ssl, int *unused, void *arg)
evhtp_res(* evhtp_hook_hostname_cb)(evhtp_request_t *r, const char *hostname, void *arg)
static evhtp_res _evhtp_connection_fini_hook(evhtp_connection_t *connection)
runs the user-definedhook called just prior to a connection being closed
const char * evhtp_header_find(evhtp_headers_t *headers, const char *key)
finds the value of a key in a evhtp_headers_t structure
int evhtp_add_alias(evhtp_t *evhtp, const char *name)
Add an alias hostname for a virtual-host specific evhtp_t. This avoids having multiple evhtp_t virtua...
#define EVHTP_RES_RSTCONTENT
struct bufferevent evbev_t
void evhtp_set_post_accept_cb(evhtp_t *htp, evhtp_post_accept_cb cb, void *arg)
evhtp_hook_connection_fini_cb on_connection_fini
#define EVHTP_RES_PARTIAL
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 evhtp_res _evhtp_headers_start_hook(evhtp_request_t *request)
struct timeval send_timeo
evhtp_res(* evhtp_pre_accept_cb)(evhtp_connection_t *conn, void *arg)
static evhtp_res _evhtp_chunk_new_hook(evhtp_request_t *request, uint64_t len)
RB_HEAD(status_code_tree, status_code)
void evhtp_send_reply_chunk_start(evhtp_request_t *request, evhtp_res code)
start a chunked response. If data already exists on the output buffer, this will be converted to the ...
An RBTREE entry for the status code -> str matcher.
struct timeval recv_timeo
static evhtp_callback_t * _evhtp_callback_find(evhtp_callbacks_t *cbs, const char *path, unsigned int *start_offset, unsigned int *end_offset)
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 HOOK_REQUEST_RUN_NARGS(request, hook_name)
static void _evhtp_connection_writecb(evbev_t *bev, void *arg)
static evhtp_res _evhtp_headers_hook(evhtp_request_t *request, evhtp_headers_t *headers)
runs the user-defined on_Headers hook for a request after all headers have been parsed.
static void _evhtp_path_free(evhtp_path_t *path)
unsigned int matched_soff
unsigned int matched_eoff
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.
#define EVHTP_RES_NOTFOUND
static void _evhtp_ssl_thread_lock(int mode, int type, const char *file, int line)
evhtp_hook_err_cb on_error
static int status_code_cmp(void *_a, void *_b)
int evhtp_ssl_use_threads(void)
#define evhtp_headers_for_each
void evhtp_connection_pause(evhtp_connection_t *c)
pauses a connection (disables reading)
void evhtp_kv_rm_and_free(evhtp_kvs_t *kvs, evhtp_kv_t *kv)
static void _evhtp_connection_readcb(evbev_t *bev, void *arg)
static evhtp_res _evhtp_body_hook(evhtp_request_t *request, evbuf_t *buf)
runs the user-defined on_body hook for requests containing a body. the data is stored in the request-...
#define EVHTP_RES_NOTIMPL
evhtp_res(* evhtp_hook_connection_fini_cb)(evhtp_connection_t *connection, void *arg)
static void _evhtp_default_request_cb(evhtp_request_t *request, void *arg)
void evhtp_request_set_bev(evhtp_request_t *request, evbev_t *bev)
sets the underlying bufferevent for a evhtp_request
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)
int evhtp_unset_all_hooks(evhtp_hooks_t **hooks)
removes all hooks.
#define evhtp_headers_free
#define EVHTP_RES_BWEXEED
const char * evhtp_kv_find(evhtp_kvs_t *kvs, const char *key)
uint64_t max_keepalive_requests
evhtp_res(* evhtp_post_accept_cb)(evhtp_connection_t *conn, void *arg)
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...
#define EVHTP_RES_NACCEPTABLE
static void _evhtp_uri_free(evhtp_uri_t *uri)
frees an overlay URI structure
static void _evhtp_ssl_delete_scache_ent(evhtp_ssl_ctx_t *ctx, evhtp_ssl_sess_t *sess)
int evhtp_make_request(evhtp_connection_t *c, evhtp_request_t *r, htp_method meth, const char *uri)
make a client request
void *(* evhtp_ssl_scache_init)(evhtp_t *)
int evhtp_response_needs_body(const evhtp_res code, const htp_method method)
Determine if a response should have a body. Follows the rules in RFC 2616 section 4...
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.
static int _evhtp_request_parser_headers_start(htparser *p)
#define EVHTP_RES_VERNSUPPORT
evhtp_header_t * evhtp_header_key_add(evhtp_headers_t *headers, const char *key, char kalloc)
creates a new evhtp_header_t, sets only the key, and adds to the evhtp_headers TAILQ ...
#define EVHTP_RES_CONTINUE
static void _evhtp_accept_cb(evserv_t *serv, int fd, struct sockaddr *s, int sl, void *arg)
static int _evhtp_request_parser_chunks_fini(htparser *p)
evhtp_kv_t * evhtp_kv_new(const char *key, const char *val, char kalloc, char valloc)
Allocates a new key/value structure.
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 _evhtp_request_parser_fini(htparser *p)
static evhtp_res _evhtp_request_fini_hook(evhtp_request_t *request)
runs the user-defined hook called just prior to a request been free()'d
static int _evhtp_request_parser_body(htparser *p, const char *data, size_t len)
evhtp_ssl_scache_add scache_add
struct timeval recv_timeo
static evhtp_proto _evhtp_protocol(const char major, const char minor)
returns the HTTP protocol version
evhtp_kvs_t * evhtp_kvs_new(void)
#define EVHTP_RES_ACCEPTED
static int _evhtp_request_parser_header_val(htparser *p, const char *data, size_t len)
structure which represents a URI path and or file
void evhtp_kvs_add_kvs(evhtp_kvs_t *dst, evhtp_kvs_t *src)
appends all key/val structures from src tailq onto dst tailq
evhtp_t * evhtp_new(evbase_t *evbase, void *arg)
creates a new evhtp_t instance
evhtp_res(* evhtp_hook_path_cb)(evhtp_request_t *req, evhtp_path_t *path, void *arg)
#define evhtp_request_content_len(r)
#define EVHTP_RES_USEPROXY
#define EVHTP_RES_URI_TOOLONG