10 #include <sys/socket.h>
11 #include <netinet/in.h>
12 #include <netinet/tcp.h>
13 #include <arpa/inet.h>
24 #include <event2/dns.h>
26 #include "evhtp-internal.h"
27 #include "evhtp_numtoa.h"
62 #define HOOK_AVAIL(var, hook_name) (var->hooks && var->hooks->hook_name)
63 #define HOOK_FUNC(var, hook_name) (var->hooks->hook_name)
64 #define HOOK_ARGS(var, hook_name) var->hooks->hook_name ## _arg
66 #define HOOK_REQUEST_RUN(request, hook_name, ...) do { \
67 if (HOOK_AVAIL(request, hook_name)) { \
68 return HOOK_FUNC(request, hook_name) (request, __VA_ARGS__, \
69 HOOK_ARGS(request, hook_name)); \
72 if (HOOK_AVAIL(evhtp_request_get_connection(request), hook_name)) { \
73 return HOOK_FUNC(request->conn, hook_name) (request, __VA_ARGS__, \
74 HOOK_ARGS(request->conn, hook_name)); \
78 #define HOOK_REQUEST_RUN_NARGS(request, hook_name) do { \
79 if (HOOK_AVAIL(request, hook_name)) { \
80 return HOOK_FUNC(request, hook_name) (request, \
81 HOOK_ARGS(request, hook_name)); \
84 if (HOOK_AVAIL(request->conn, hook_name)) { \
85 return HOOK_FUNC(request->conn, hook_name) (request, \
86 HOOK_ARGS(request->conn, hook_name)); \
90 #define HOOK_CONN_RUN(conn, hook_name, ...) do { \
91 if (conn->request) { \
92 evhtp_request_t * request = conn->request; \
93 if (HOOK_AVAIL(request, hook_name)) { \
94 return HOOK_FUNC(conn, hook_name) (conn, __VA_ARGS__, \
95 HOOK_ARGS(conn, hook_name)); \
99 if (HOOK_AVAIL(conn, hook_name)) { \
100 return HOOK_FUNC(conn, hook_name) (conn, __VA_ARGS__, \
101 HOOK_ARGS(conn, hook_name)); \
105 #ifndef EVHTP_DISABLE_EVTHR
106 #define _evhtp_lock(h) do { \
108 pthread_mutex_lock(h->lock); \
112 #define _evhtp_unlock(h) do { \
114 pthread_mutex_unlock(h->lock); \
118 #define _evhtp_lock(h) do {} while (0)
119 #define _evhtp_unlock(h) do {} while (0)
122 #ifndef TAILQ_FOREACH_SAFE
123 #define TAILQ_FOREACH_SAFE(var, head, field, tvar) \
124 for ((var) = TAILQ_FIRST((head)); \
125 (var) && ((tvar) = TAILQ_NEXT((var), field), 1); \
137 return "Bad Request";
141 return "Internal Server Error";
147 return "Switching Protocols";
149 return "Moved Permanently";
153 return "URI Too Long";
159 return "No Auth Info";
163 return "Reset Content";
165 return "Partial Content";
167 return "Multi-Status";
175 return "Not Modified";
179 return "Switch Proxy";
181 return "Temporary Redirect";
183 return "Unauthorized";
185 return "Payment Required";
187 return "Not Allowed";
189 return "Not Acceptable";
191 return "Proxy Authentication Required";
193 return "Request Timeout";
199 return "Length Required";
201 return "Precondition Failed";
203 return "Entity Too Large";
205 return "Request-URI Too Long";
207 return "Unsupported Media Type";
209 return "Requested Range Not Satisfiable";
211 return "Expectation Failed";
213 return "I'm a teapot";
215 return "Not Implemented";
217 return "Bad Gateway";
219 return "Service Unavailable";
221 return "Gateway Timeout";
223 return "HTTP Version Not Supported";
225 return "Bandwidth Limit Exceeded";
255 #ifndef EVHTP_DISABLE_SSL
257 #ifndef EVHTP_DISABLE_EVTHR
270 strnlen(
const char * s,
size_t maxlen) {
274 for (e = s, n = 0; *e && n < maxlen; e++, n++) {
285 strndup(
const char * s,
size_t n) {
286 size_t len = strnlen(s, n);
314 static inline unsigned int
318 for (; *str; str++) {
335 #define _evhtp_is_http_11(_major, _minor) \
336 (_major >= 1 && _minor >= 1)
346 #define _evhtp_is_http_10(_major, _minor) \
347 (_major >= 1 && _minor <= 0)
547 const char *
string,
size_t str_len) {
549 switch (pattern[0]) {
551 while (pattern[1] ==
'*') {
572 if (pattern[0] !=
string[0]) {
585 while (*pattern ==
'*') {
594 if (plen == 0 && str_len == 0) {
613 if (!pattern || !
string) {
618 pat_len = strlen(pattern);
622 str_len = strlen(
string);
630 if (pattern[0] ==
'*') {
631 while (pattern[1] ==
'*') {
651 if (pattern[0] !=
string[0]) {
663 while (*pattern ==
'*') {
671 if (pat_len == 0 && str_len == 0) {
682 unsigned int * start_offset,
683 unsigned int * end_offset) {
684 #ifndef EVHTP_DISABLE_REGEX
685 regmatch_t pmatch[28];
693 TAILQ_FOREACH(callback, cbs, next) {
694 switch (callback->
type) {
696 if (strcmp(callback->
val.
path, path) == 0) {
698 *end_offset = (
unsigned int)strlen(path);
703 #ifndef EVHTP_DISABLE_REGEX
705 if (regexec(callback->
val.
regex, path, callback->
val.
regex->re_nsub + 1, pmatch, 0) == 0) {
706 *start_offset = pmatch[callback->
val.
regex->re_nsub].rm_so;
707 *end_offset = pmatch[callback->
val.
regex->re_nsub].rm_eo;
716 size_t path_len = strlen(path);
717 size_t glob_len = strlen(callback->
val.
glob);
720 path, path_len) == 1) {
722 *end_offset = (
unsigned int)path_len;
753 req->
htp = c ? c->
htp : NULL;
757 if (!(req->
buffer_in = evbuffer_new())) {
795 if (request == NULL) {
817 free(request->
hooks);
852 if (authority == NULL) {
872 if (!(authority = calloc(1,
sizeof(*authority)))) {
918 const char * data_end = (
const char *)(data + len);
931 }
else if (*data !=
'/') {
936 file = strndup(data, len);
938 if (data[len - 1] !=
'/') {
945 for (i = (len - 1); i != 0; i--) {
946 if (data[i] ==
'/') {
954 path_len = (size_t)(&data[i] - data) + 1;
955 file_len = (size_t)(data_end - &data[i + 1]);
958 if ((
const char *)(data + path_len) > data_end) {
965 if ((
const char *)(&data[i + 1] + file_len) > data_end) {
971 path = strndup(data, path_len);
972 file = strndup(&data[i + 1], file_len);
978 if (i == 0 && data[i] ==
'/' && !file && !path) {
983 file = strndup((
const char *)(data + 1), len);
988 path = strndup(data, len);
993 req_path->
full = strndup(data, len);
995 req_path->
full = strdup(
"/");
998 req_path->
path = path;
999 req_path->
file = file;
1051 const char * fragment;
1052 int ignore_fragment;
1069 if (!ignore_fragment && (fragment = memchr(data,
'#', len))) {
1076 ptrdiff_t frag_offset;
1078 frag_offset = fragment - data;
1080 if (frag_offset < len) {
1086 fraglen = len - frag_offset;
1088 if (!(uri->
fragment = malloc(fraglen + 1))) {
1094 memcpy(uri->
fragment, fragment, fraglen);
1134 key_s = malloc(len + 1);
1136 memcpy(key_s, data, len);
1155 val_s = malloc(len + 1);
1157 memcpy(val_s, data, len);
1166 header->v_heaped = 1;
1180 TAILQ_FOREACH(evhtp_vhost, &evhtp->vhosts, next_vhost) {
1189 TAILQ_FOREACH(evhtp_alias, &evhtp_vhost->aliases, next) {
1190 if (evhtp_alias->
alias == NULL) {
1214 if (request == NULL) {
1218 if ((evhtp = request->
htp) == NULL) {
1222 if ((conn = request->
conn) == NULL) {
1226 if ((uri = request->
uri) == NULL) {
1230 if ((path = uri->
path) == NULL) {
1243 cbarg = callback->
cbarg;
1244 hooks = callback->
hooks;
1249 cbarg = callback->
cbarg;
1250 hooks = callback->
hooks;
1282 if (hooks != NULL) {
1283 if (request->
hooks == NULL) {
1291 request->
cbarg = cbarg;
1302 #ifndef EVHTP_DISABLE_SSL
1307 host = SSL_get_servername(c->
ssl, TLSEXT_NAMETYPE_host_name);
1331 c->
htp = evhtp_vhost;
1371 authority->
hostname = strndup(data, len);
1394 port = strtoul(data, &endptr, 10);
1396 if (endptr - data != len || port > 65535) {
1402 authority->
port = port;
1460 evbuffer_add_printf(bufferevent_get_output(c->
bev),
1461 "HTTP/%c.%c 100 Continue\r\n\r\n",
1462 evhtp_modp_uchartoa(htparser_get_major(p)),
1463 evhtp_modp_uchartoa(htparser_get_minor(p)));
1482 buf = evbuffer_new();
1483 evbuffer_add(buf, data, len);
1489 if (evbuffer_get_length(buf)) {
1546 const char * content_type;
1552 if (req->
uri == NULL || req->
uri->
query != NULL) {
1567 if (content_type == NULL) {
1571 if (strncasecmp(content_type,
"application/x-www-form-urlencoded", 33)) {
1598 body_len = evbuffer_get_length(buf_in);
1599 body = (
const char *)evbuffer_pullup(buf_in, body_len);
1601 uri->
query_raw = calloc(body_len + 1, 1);
1629 evbuffer_expand(buf, header->klen + 2 + header->vlen + 2);
1630 evbuffer_add(buf, header->key, header->klen);
1631 evbuffer_add(buf,
": ", 2);
1632 evbuffer_add(buf, header->val, header->vlen);
1633 evbuffer_add(buf,
"\r\n", 2);
1641 const char * content_type;
1645 unsigned char major;
1646 unsigned char minor;
1651 out_len = evbuffer_get_length(request->
buffer_out);
1652 buf = evbuffer_new();
1654 if (htparser_get_multipart(request->
conn->
parser) == 1) {
1658 if (out_len && request->
chunked == 0) {
1665 evhtp_modp_sizetoa(out_len, out_buf);
1671 if (!content_type) {
1678 "transfer-encoding");
1680 if (!chunked || !strstr(chunked,
"chunked")) {
1689 switch (request->
proto) {
1707 htparser_set_major(request->
conn->
parser, 1);
1708 htparser_set_minor(request->
conn->
parser, 0);
1719 major = evhtp_modp_uchartoa(htparser_get_major(request->
conn->
parser));
1720 minor = evhtp_modp_uchartoa(htparser_get_minor(request->
conn->
parser));
1722 evhtp_modp_u32toa((uint32_t)code, out_buf);
1724 sres = snprintf(res_buf,
sizeof(res_buf),
"HTTP/%c.%c %s %s\r\n",
1727 if (sres >=
sizeof(res_buf) || sres < 0) {
1731 evbuffer_add_printf(buf,
"HTTP/%c.%c %d %s\r\n",
1736 evbuffer_add(buf, res_buf, sres);
1741 evbuffer_add(buf,
"\r\n", 2);
1743 if (evbuffer_get_length(request->
buffer_out)) {
1744 evbuffer_add_buffer(buf, request->
buffer_out);
1773 if (evbuffer_get_length(bufferevent_get_output(c->
bev))) {
1774 bufferevent_enable(c->
bev, EV_WRITE);
1777 bufferevent_enable(c->
bev, EV_READ | EV_WRITE);
1789 avail = evbuffer_get_length(bufferevent_get_input(bev));
1803 buf = evbuffer_pullup(bufferevent_get_input(bev), avail);
1807 if (c->
owner != 1) {
1812 evbuffer_drain(bufferevent_get_input(bev), nread);
1830 evbuffer_drain(bufferevent_get_input(bev), nread);
1834 }
else if (htparser_get_error(c->
parser) != htparse_error_none) {
1856 bufferevent_enable(bev, EV_READ);
1858 if (evbuffer_get_length(bufferevent_get_input(bev))) {
1865 if (c->
request->
finished == 0 || evbuffer_get_length(bufferevent_get_output(bev))) {
1899 htparser_init(c->
parser, htp_type_request);
1902 htparser_set_userdata(c->
parser, c);
1922 if ((events & BEV_EVENT_CONNECTED)) {
1925 bufferevent_setcb(bev,
1934 #ifndef EVHTP_DISABLE_SSL
1935 if (c->
ssl && !(events & BEV_EVENT_EOF)) {
1945 if (events == (BEV_EVENT_EOF | BEV_EVENT_READING)) {
1946 if (errno == EAGAIN) {
1955 bufferevent_enable(bev, EV_READ);
1995 struct timeval * c_recv_timeo;
1996 struct timeval * c_send_timeo;
1999 evutil_closesocket(connection->
sock);
2004 #ifndef EVHTP_DISABLE_SSL
2007 connection->
bev = bufferevent_openssl_socket_new(evbase,
2010 BUFFEREVENT_SSL_ACCEPTING,
2012 SSL_set_app_data(connection->
ssl, connection);
2017 connection->
bev = bufferevent_socket_new(evbase,
2020 #ifndef EVHTP_DISABLE_SSL
2030 c_recv_timeo = NULL;
2039 c_send_timeo = NULL;
2044 connection->
resume_ev = event_new(evbase, -1, EV_READ | EV_PERSIST,
2048 bufferevent_enable(connection->
bev, EV_READ);
2049 bufferevent_setcb(connection->
bev,
2069 ptype = htp_type_response;
2072 ptype = htp_type_request;
2083 connection->
error = 0;
2084 connection->
owner = 1;
2087 connection->
sock = sock;
2088 connection->
htp = htp;
2089 connection->
type = type;
2090 connection->
parser = htparser_new();
2092 if (!connection->
parser) {
2093 evhtp_safe_free(connection, free);
2098 htparser_init(connection->
parser, ptype);
2099 htparser_set_userdata(connection->
parser, connection);
2101 #ifdef EVHTP_FUTURE_USE
2102 TAILQ_INIT(&connection->pending);
2108 #ifdef LIBEVENT_HAS_SHUTDOWN
2109 #ifndef EVHTP_DISABLE_SSL
2111 _evhtp_shutdown_eventcb(
evbev_t * bev,
short events,
void * arg) {
2136 #ifndef EVHTP_DISABLE_EVTHR
2142 connection->
evbase = evthr_get_base(thr);
2143 connection->
thread = thr;
2169 connection->
saddr = malloc(sl);
2170 memcpy(connection->
saddr, s, sl);
2172 #ifndef EVHTP_DISABLE_EVTHR
2175 evutil_closesocket(connection->
sock);
2199 #ifndef EVHTP_DISABLE_SSL
2200 #ifndef EVHTP_DISABLE_EVTHR
2201 static unsigned long
2205 return (
unsigned long)pthread_self();
2208 return (
unsigned long)(pthread_self().p);
2215 if (mode & CRYPTO_LOCK) {
2218 pthread_mutex_unlock(&(
ssl_locks[type]));
2228 unsigned char * sid;
2231 htp = (
evhtp_t *)SSL_CTX_get_app_data(ctx);
2234 sid = sess->session_id;
2235 slen = sess->session_id_length;
2246 unsigned char * sid;
2252 sid = sess->session_id;
2253 slen = sess->session_id_length;
2258 return (cfg->
scache_add)(connection, sid, slen, sess);
2275 sess = (cfg->
scache_get)(connection, sid, sid_len);
2290 if (!(sname = SSL_get_servername(ssl, TLSEXT_NAMETYPE_host_name))) {
2291 return SSL_TLSEXT_ERR_NOACK;
2294 if (!(connection = SSL_get_app_data(ssl))) {
2295 return SSL_TLSEXT_ERR_NOACK;
2298 if (!(evhtp = connection->
htp)) {
2299 return SSL_TLSEXT_ERR_NOACK;
2303 connection->
htp = evhtp_vhost;
2306 SSL_set_SSL_CTX(ssl, evhtp_vhost->
ssl_ctx);
2307 SSL_set_options(ssl, SSL_CTX_get_options(ssl->ctx));
2309 if ((SSL_get_verify_mode(ssl) == SSL_VERIFY_NONE) ||
2310 (SSL_num_renegotiations(ssl) == 0)) {
2311 SSL_set_verify(ssl, SSL_CTX_get_verify_mode(ssl->ctx),
2312 SSL_CTX_get_verify_callback(ssl->ctx));
2315 return SSL_TLSEXT_ERR_OK;
2318 return SSL_TLSEXT_ERR_NOACK;
2341 bufferevent_disable(c->
bev, EV_READ | EV_WRITE);
2355 event_active(c->
resume_ev, EV_WRITE, 1);
2402 if (!headers || !val) {
2410 if (header->val != NULL) {
2414 header->vlen = strlen(val);
2417 header->val = malloc(header->vlen + 1);
2418 header->val[header->vlen] =
'\0';
2419 memcpy(header->val, val, header->vlen);
2421 header->val = (
char *)val;
2424 header->v_heaped = valloc;
2439 evhtp_kv_new(
const char * key,
const char * val,
char kalloc,
char valloc) {
2454 kv->
klen = strlen(key);
2459 if (!(s = malloc(kv->
klen + 1))) {
2460 evhtp_safe_free(kv, free);
2465 memcpy(s, key, kv->
klen);
2470 kv->
key = (
char *)key;
2475 kv->
vlen = strlen(val);
2478 char * s = malloc(kv->
vlen + 1);
2481 memcpy(s, val, kv->
vlen);
2484 kv->
val = (
char *)val;
2498 evhtp_safe_free(kv->
key, free);
2502 evhtp_safe_free(kv->
val, free);
2505 evhtp_safe_free(kv, free);
2510 if (kvs == NULL || kv == NULL) {
2514 TAILQ_REMOVE(kvs, kv, next);
2528 for (kv = TAILQ_FIRST(kvs); kv != NULL; kv = save) {
2529 save = TAILQ_NEXT(kv, next);
2531 TAILQ_REMOVE(kvs, kv, next);
2536 evhtp_safe_free(kvs, free);
2543 if (kvs == NULL || cb == NULL) {
2547 TAILQ_FOREACH(kv, kvs, next) {
2550 if ((res = cb(kv, arg))) {
2562 if (kvs == NULL || key == NULL) {
2566 TAILQ_FOREACH(kv, kvs, next) {
2567 if (strcasecmp(kv->
key, key) == 0) {
2579 if (kvs == NULL || key == NULL) {
2583 TAILQ_FOREACH(kv, kvs, next) {
2584 if (strcasecmp(kv->
key, key) == 0) {
2594 if (kvs == NULL || kv == NULL) {
2598 TAILQ_INSERT_TAIL(kvs, kv, next);
2603 if (dst == NULL || src == NULL) {
2609 TAILQ_FOREACH(kv, src, next) {
2661 unsigned char * optr;
2662 unsigned char * sptr;
2669 if (out == NULL || *out == NULL) {
2678 for (i = 0; i < str_len; i++) {
2692 if (ch >=
'0' && ch <=
'9') {
2693 d = (
unsigned char)(ch -
'0');
2698 c = (
unsigned char)(ch | 0x20);
2700 if (c >=
'a' && c <=
'f') {
2701 d = (
unsigned char)(c -
'a' + 10);
2712 if (ch >=
'0' && ch <=
'9') {
2713 ch = (
unsigned char)((d << 4) + ch -
'0');
2719 c = (
unsigned char)(ch | 0x20);
2721 if (c >=
'a' && c <=
'f') {
2722 ch = (
unsigned char)((d << 4) + c -
'a' + 10);
2744 if (len > (SIZE_MAX - (len + 2))) {
2754 #ifdef EVHTP_HAS_C99
2755 char key_buf[len + 1];
2756 char val_buf[len + 1];
2761 if (!(key_buf = malloc(len + 1))) {
2765 if (!(val_buf = malloc(len + 1))) {
2766 evhtp_safe_free(key_buf, free);
2772 for (i = 0; i < len; i++) {
2775 if (key_idx >= len || val_idx >= len) {
2795 key_buf[key_idx++] = ch;
2796 key_buf[key_idx] =
'\0';
2805 key_buf[key_idx++] = ch;
2806 key_buf[key_idx] =
'\0';
2831 key_buf[key_idx++] = ch;
2832 key_buf[key_idx] =
'\0';
2839 if ((key_idx + 2) >= len) {
2844 key_buf[key_idx - 1] =
'%';
2845 key_buf[key_idx++] = ch;
2846 key_buf[key_idx] =
'\0';
2852 key_buf[key_idx++] = ch;
2853 key_buf[key_idx] =
'\0';
2862 key_buf[key_idx++] = ch;
2863 key_buf[key_idx] =
'\0';
2871 val_buf[val_idx++] = ch;
2872 val_buf[val_idx] =
'\0';
2887 val_buf[val_idx++] = ch;
2888 val_buf[val_idx] =
'\0';
2896 val_buf[val_idx++] = ch;
2897 val_buf[val_idx] =
'\0';
2905 if ((val_idx + 2) >= len) {
2914 val_buf[val_idx - 1] =
'%';
2915 val_buf[val_idx++] = ch;
2916 val_buf[val_idx] =
'\0';
2922 val_buf[val_idx++] = ch;
2923 val_buf[val_idx] =
'\0';
2932 val_buf[val_idx++] = ch;
2933 val_buf[val_idx] =
'\0';
2967 #ifndef EVHTP_HAS_C99
2968 evhtp_safe_free(key_buf, free);
2969 evhtp_safe_free(val_buf, free);
2974 #ifndef EVHTP_HAS_C99
2975 evhtp_safe_free(key_buf, free);
2976 evhtp_safe_free(val_buf, free);
3000 bufferevent_write_buffer(c->
bev, reply_buf);
3001 evbuffer_free(reply_buf);
3010 bufferevent_write_buffer(c->
bev, buf);
3033 evbuffer_free(reply_buf);
3040 (code < 100 || code >= 200) &&
3041 method != htp_method_HEAD;
3051 switch (request->
proto) {
3091 if (evbuffer_get_length(request->
buffer_out) > 0) {
3095 sres = snprintf(lstr,
sizeof(lstr),
"%x\r\n",
3096 (
unsigned)evbuffer_get_length(request->
buffer_out));
3098 if (sres >=
sizeof(lstr) || sres < 0) {
3104 evbuffer_prepend(request->
buffer_out, lstr, strlen(lstr));
3105 evbuffer_add(request->
buffer_out,
"\r\n", 2);
3117 output = bufferevent_get_output(request->
conn->
bev);
3119 if (evbuffer_get_length(buf) == 0) {
3124 evbuffer_add_printf(output,
"%x\r\n",
3125 (
unsigned)evbuffer_get_length(buf));
3131 evbuffer_add(output,
"\r\n", 2);
3134 bufferevent_flush(request->
conn->
bev, EV_WRITE, BEV_FLUSH);
3149 evconnlistener_free(htp->
server);
3156 signal(SIGPIPE, SIG_IGN);
3160 LEV_OPT_THREADSAFE | LEV_OPT_CLOSE_ON_FREE | LEV_OPT_REUSEABLE,
3161 backlog, sa, sin_len);
3166 #ifdef USE_DEFER_ACCEPT
3168 evutil_socket_t sock;
3171 sock = evconnlistener_get_fd(htp->
server);
3173 setsockopt(sock, IPPROTO_TCP, TCP_DEFER_ACCEPT, &one, (ev_socklen_t)
sizeof(one));
3174 setsockopt(sock, IPPROTO_TCP, TCP_NODELAY, &one, (ev_socklen_t)
sizeof(one));
3178 #ifndef EVHTP_DISABLE_SSL
3185 if (TAILQ_FIRST(&htp->vhosts) != NULL) {
3186 SSL_CTX_set_tlsext_servername_callback(htp->
ssl_ctx,
3198 struct sockaddr_un sun;
3200 struct sockaddr_in6 sin6;
3201 struct sockaddr_in sin;
3202 struct sockaddr * sa;
3205 memset(&sin, 0,
sizeof(sin));
3207 if (!strncmp(baddr,
"ipv6:", 5)) {
3208 memset(&sin6, 0,
sizeof(sin6));
3211 sin_len =
sizeof(
struct sockaddr_in6);
3212 sin6.sin6_port = htons(port);
3213 sin6.sin6_family = AF_INET6;
3215 evutil_inet_pton(AF_INET6, baddr, &sin6.sin6_addr);
3216 sa = (
struct sockaddr *)&sin6;
3217 }
else if (!strncmp(baddr,
"unix:", 5)) {
3221 if (strlen(baddr) >=
sizeof(sun.sun_path)) {
3225 memset(&sun, 0,
sizeof(sun));
3227 sin_len =
sizeof(
struct sockaddr_un);
3228 sun.sun_family = AF_UNIX;
3230 strncpy(sun.sun_path, baddr, strlen(baddr));
3232 sa = (
struct sockaddr *)&sun;
3238 if (!strncmp(baddr,
"ipv4:", 5)) {
3242 sin_len =
sizeof(
struct sockaddr_in);
3244 sin.sin_family = AF_INET;
3245 sin.sin_port = htons(port);
3246 sin.sin_addr.s_addr = inet_addr(baddr);
3248 sa = (
struct sockaddr *)&sin;
3259 if (callbacks == NULL) {
3263 TAILQ_FOREACH_SAFE(callback, callbacks, next, tmp) {
3264 TAILQ_REMOVE(callbacks, callback, next);
3269 evhtp_safe_free(callbacks, free);
3289 #ifndef EVHTP_DISABLE_REGEX
3291 hcb->
val.
regex = malloc(
sizeof(regex_t));
3293 if (regcomp(hcb->
val.
regex, (
char *)path, REG_EXTENDED) != 0) {
3294 evhtp_safe_free(hcb->
val.
regex, free);
3295 evhtp_safe_free(hcb, free);
3305 evhtp_safe_free(hcb, free);
3315 if (callback == NULL) {
3319 switch (callback->
type) {
3324 evhtp_safe_free(callback->
val.
glob, free);
3326 #ifndef EVHTP_DISABLE_REGEX
3334 if (callback->
hooks) {
3335 evhtp_safe_free(callback->
hooks, free);
3338 evhtp_safe_free(callback, free);
3345 TAILQ_INSERT_TAIL(cbs, cb, next);
3352 if (*hooks == NULL) {
3361 (*hooks)->on_headers_start_arg = arg;
3365 (*hooks)->on_header_arg = arg;
3369 (*hooks)->on_headers_arg = arg;
3373 (*hooks)->on_path_arg = arg;
3377 (*hooks)->on_read_arg = arg;
3381 (*hooks)->on_request_fini_arg = arg;
3385 (*hooks)->on_connection_fini_arg = arg;
3389 (*hooks)->on_connection_error_arg = arg;
3393 (*hooks)->on_error_arg = arg;
3397 (*hooks)->on_new_chunk_arg = arg;
3401 (*hooks)->on_chunk_fini_arg = arg;
3405 (*hooks)->on_chunks_fini_arg = arg;
3409 (*hooks)->on_hostname_arg = arg;
3413 (*hooks)->on_write_arg = arg;
3417 (*hooks)->on_event_arg = arg;
3533 #ifndef EVHTP_DISABLE_EVTHR
3548 #ifndef EVHTP_DISABLE_SSL
3563 #ifndef EVHTP_DISABLE_EVTHR
3570 if (!(htp->
lock = malloc(
sizeof(pthread_mutex_t)))) {
3574 return pthread_mutex_init(htp->
lock, NULL);
3579 #ifndef EVHTP_DISABLE_REGEX
3668 #ifndef EVHTP_DISABLE_SSL
3669 #ifndef EVHTP_DISABLE_EVTHR
3684 pthread_mutex_init(&(
ssl_locks[i]), NULL);
3697 #ifdef EVHTP_ENABLE_FUTURE_STUFF
3705 if (cfg == NULL || htp == NULL || cfg->
pemfile == NULL) {
3710 SSL_load_error_strings();
3713 #if OPENSSL_VERSION_NUMBER < 0x10000000L
3714 STACK_OF(SSL_COMP) * comp_methods = SSL_COMP_get_compression_methods();
3715 sk_SSL_COMP_zero(comp_methods);
3719 htp->
ssl_ctx = SSL_CTX_new(SSLv23_server_method());
3721 #if OPENSSL_VERSION_NUMBER >= 0x10000000L
3722 SSL_CTX_set_options(htp->
ssl_ctx, SSL_MODE_RELEASE_BUFFERS | SSL_OP_NO_COMPRESSION);
3728 #ifndef OPENSSL_NO_ECDH
3730 EC_KEY * ecdh = NULL;
3735 fprintf(stderr,
"ECDH initialization failed: unknown curve %s\n", cfg->
named_curve);
3737 ecdh = EC_KEY_new_by_curve_name(nid);
3739 fprintf(stderr,
"ECDH initialization failed for curve %s\n", cfg->
named_curve);
3741 SSL_CTX_set_tmp_ecdh(htp->
ssl_ctx, ecdh);
3745 #ifndef OPENSSL_NO_DH
3752 dh = PEM_read_DHparams(fh, NULL, NULL, NULL);
3754 SSL_CTX_set_tmp_dh(htp->
ssl_ctx, dh);
3757 fprintf(stderr,
"DH initialization failed: unable to parse file %s\n", cfg->
dhparams);
3761 fprintf(stderr,
"DH initialization failed: unable to open file %s\n", cfg->
dhparams);
3784 cache_mode = SSL_SESS_CACHE_OFF;
3786 #ifdef EVHTP_ENABLE_FUTURE_STUFF
3788 cache_mode = SSL_SESS_CACHE_SERVER |
3789 SSL_SESS_CACHE_NO_INTERNAL |
3790 SSL_SESS_CACHE_NO_INTERNAL_LOOKUP;
3798 cache_mode = SSL_SESS_CACHE_SERVER |
3799 SSL_SESS_CACHE_NO_INTERNAL |
3800 SSL_SESS_CACHE_NO_INTERNAL_LOOKUP;
3802 init_cb = _evhtp_ssl_builtin_init;
3803 add_cb = _evhtp_ssl_builtin_add;
3804 get_cb = _evhtp_ssl_builtin_get;
3805 del_cb = _evhtp_ssl_builtin_del;
3810 cache_mode = SSL_SESS_CACHE_SERVER;
3814 SSL_CTX_use_certificate_file(htp->
ssl_ctx, cfg->
pemfile, SSL_FILETYPE_PEM);
3815 SSL_CTX_use_PrivateKey_file(htp->
ssl_ctx,
3818 SSL_CTX_set_session_id_context(htp->
ssl_ctx,
3822 SSL_CTX_set_app_data(htp->
ssl_ctx, htp);
3823 SSL_CTX_set_session_cache_mode(htp->
ssl_ctx, cache_mode);
3825 if (cache_mode != SSL_SESS_CACHE_OFF) {
3826 SSL_CTX_sess_set_cache_size(htp->
ssl_ctx,
3848 return connection->
bev;
3855 if (connection->
hooks) {
3865 connection->
owner = 0;
3867 bufferevent_disable(bev, EV_READ);
3868 bufferevent_setcb(bev, NULL, NULL, NULL, NULL);
3895 return request->
conn;
3900 const struct timeval * rtimeo,
3901 const struct timeval * wtimeo) {
3906 if (rtimeo || wtimeo) {
3907 bufferevent_set_timeouts(c->
bev, rtimeo, wtimeo);
3927 if (connection == NULL) {
3934 evhtp_safe_free(connection->
parser, free);
3935 evhtp_safe_free(connection->
hooks, free);
3936 evhtp_safe_free(connection->
saddr, free);
3939 evhtp_safe_free(connection->
resume_ev, event_free);
3942 if (connection->
bev) {
3943 #ifdef LIBEVENT_HAS_SHUTDOWN
3944 bufferevent_shutdown(connection->
bev, _evhtp_shutdown_eventcb);
3946 #ifndef EVHTP_DISABLE_SSL
3947 if (connection->
ssl != NULL) {
3948 SSL_set_shutdown(connection->
ssl, SSL_RECEIVED_SHUTDOWN);
3949 SSL_shutdown(connection->
ssl);
3952 bufferevent_free(connection->
bev);
3960 evhtp_safe_free(connection, free);
3970 if (r_timeo != NULL) {
3974 if (w_timeo != NULL) {
4014 if (evhtp == NULL || name == NULL) {
4022 alias->
alias = strdup(name);
4024 TAILQ_INSERT_TAIL(&evhtp->aliases, alias, next);
4047 if (evhtp == NULL || name == NULL || vhost == NULL) {
4051 if (TAILQ_FIRST(&vhost->vhosts) != NULL) {
4075 TAILQ_INSERT_TAIL(&evhtp->vhosts, vhost, next_vhost);
4084 if (evbase == NULL) {
4088 if (!(htp = calloc(
sizeof(
evhtp_t), 1))) {
4096 TAILQ_INIT(&htp->vhosts);
4097 TAILQ_INIT(&htp->aliases);
4108 if (evhtp == NULL) {
4112 #ifndef EVHTP_DISABLE_EVTHR
4119 #ifndef EVHTP_DISABLE_SSL
4133 TAILQ_FOREACH_SAFE(evhtp_alias, &evhtp->aliases, next, tmp) {
4134 if (evhtp_alias->
alias != NULL) {
4135 free(evhtp_alias->
alias);
4137 TAILQ_REMOVE(&evhtp->aliases, evhtp_alias, next);
4141 #ifndef EVHTP_DISABLE_SSL
4152 size_t read_rate,
size_t read_burst,
4153 size_t write_rate,
size_t write_burst,
4154 const struct timeval * tick) {
4155 struct ev_token_bucket_cfg * tcfg;
4157 if (conn == NULL || conn->
bev == NULL) {
4161 tcfg = ev_token_bucket_cfg_new(read_rate, read_burst,
4162 write_rate, write_burst, tick);
4170 return bufferevent_set_rate_limit(conn->
bev, tcfg);
4184 const char * addr, uint16_t port) {
4188 if (evbase == NULL) {
4197 conn->
bev = bufferevent_socket_new(evbase, -1, BEV_OPT_CLOSE_ON_FREE);
4199 if (conn->
bev == NULL) {
4205 bufferevent_enable(conn->
bev, EV_READ);
4206 bufferevent_setcb(conn->
bev, NULL, NULL,
4209 if (dns_base != NULL) {
4210 err = bufferevent_socket_connect_hostname(conn->
bev, dns_base,
4211 AF_UNSPEC, addr, port);
4213 struct sockaddr_in sin4;
4214 struct sockaddr_in6 sin6;
4215 struct sockaddr * sin;
4218 if (inet_pton(AF_INET, addr, &sin4.sin_addr)) {
4219 sin4.sin_family = AF_INET;
4220 sin4.sin_port = htons(port);
4221 sin = (
struct sockaddr *)&sin4;
4222 salen =
sizeof(sin4);
4223 }
else if (inet_pton(AF_INET6, addr, &sin6.sin6_addr)) {
4224 sin6.sin6_family = AF_INET6;
4225 sin6.sin6_port = htons(port);
4226 sin = (
struct sockaddr *)&sin6;
4227 salen =
sizeof(sin6);
4235 err = bufferevent_socket_connect(conn->
bev, sin, salen);
4248 #ifndef EVHTP_DISABLE_SSL
4252 struct sockaddr_in sin;
4254 if (evbase == NULL) {
4262 sin.sin_family = AF_INET;
4263 sin.sin_addr.s_addr = inet_addr(addr);
4264 sin.sin_port = htons(port);
4266 conn->
ssl = SSL_new(ctx);
4268 conn->
bev = bufferevent_openssl_socket_new(evbase, -1, conn->
ssl, BUFFEREVENT_SSL_CONNECTING, BEV_OPT_CLOSE_ON_FREE);
4270 bufferevent_enable(conn->
bev, EV_READ);
4272 bufferevent_setcb(conn->
bev, NULL, NULL,
4275 bufferevent_socket_connect(conn->
bev,
4276 (
struct sockaddr *)&sin,
sizeof(sin));
4302 htp_method meth,
const char * uri) {
4306 obuf = bufferevent_get_output(c->
bev);
4320 evbuffer_add_printf(obuf,
"%s %s HTTP/%s\r\n",
4321 htparser_get_methodstr_m(meth), uri, proto);
4324 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.
evhtp_query_t * evhtp_parse_query_wflags(const char *query, size_t len, int flags)
Parses the query portion of the uri into a set of key/values.
#define EVHTP_PARSE_QUERY_FLAG_ALLOW_EMPTY_VALS
#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...
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
static evhtp_res _evhtp_header_hook(evhtp_request_t *request, evhtp_header_t *header)
runs the user-defined on_header hook for a request
#define EVHTP_PARSE_QUERY_FLAG_IGNORE_FRAGMENTS
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)
Enable thread-pool support for an evhtp_t context. Connectios are distributed across 'nthreads'...
static unsigned int _evhtp_quick_hash(const char *str)
a weak hash function
#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.
#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
#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 int _evhtp_request_parser_host(htparser *p, const char *data, size_t len)
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
evhtp_connection_t * evhtp_connection_ssl_new(evbase_t *evbase, const char *addr, uint16_t port, evhtp_ssl_ctx_t *ctx)
void evhtp_send_reply_end(evhtp_request_t *request)
evhtp_hook_write_cb on_write
evhtp_ssl_cfg_t * ssl_cfg
#define EVHTP_PARSE_QUERY_FLAG_ALLOW_NULL_VALS
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
#define _evhtp_is_http_10(_major, _minor)
helper function to determine if http version is HTTP/1.1
#define EVHTP_PARSE_QUERY_FLAG_STRICT
static int _evhtp_request_parser_path(htparser *p, const char *data, size_t len)
evhtp_res(* evhtp_hook_headers_start_cb)(evhtp_request_t *r, void *arg)
static int _evhtp_request_parser_port(htparser *p, const char *data, size_t len)
evhtp_res(* evhtp_hook_chunk_fini_cb)(evhtp_request_t *r, void *arg)
main structure containing all configuration information
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. When the timeout expires your error hook will be call...
#define EVHTP_PARSE_QUERY_FLAG_TREAT_SEMICOLON_AS_SEP
#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_connection_t * evhtp_request_get_connection(evhtp_request_t *request)
returns the underlying evhtp_connection_t structure from a request
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.
evhtp_res(* evhtp_hook_write_cb)(evhtp_connection_t *conn, 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)
callback iterator which executes 'cb' for every entry in 'kvs'
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)
frees resources allocated for a single key/value
struct ev_token_bucket_cfg * ratelimit_cfg
void(* evhtp_hook_err_cb)(evhtp_request_t *req, evhtp_error_flags errtype, void *arg)
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...
#define EVHTP_RES_MOVEDPERM
#define HOOK_CONN_RUN(conn, hook_name,...)
unsigned int evhtp_request_status(evhtp_request_t *r)
#define EVHTP_RES_MSTATUS
evhtp_connection_t * evhtp_connection_new(evbase_t *evbase, const char *addr, uint16_t port)
allocate a new connection
#define _evhtp_is_http_11(_major, _minor)
helper macro to determine if http version is HTTP/1.0
struct evhtp_kvs_s evhtp_kvs_t
static void _evhtp_error_hook(evhtp_request_t *request, evhtp_error_flags errtype)
runs the user-defined hook when a connection error occurs
static evhtp_res _evhtp_chunk_fini_hook(evhtp_request_t *request)
static int _evhtp_request_parser_chunk_fini(htparser *p)
uint8_t evhtp_error_flags
#define EVHTP_RES_NAUTHINFO
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_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_pre_accept_cb)(evhtp_connection_t *conn, 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.
evhtp_res(* evhtp_hook_chunk_new_cb)(evhtp_request_t *r, uint64_t len, 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}'.
struct timeval send_timeo
void evhtp_callback_free(evhtp_callback_t *callback)
frees information associated with a ainflwx callback.
static int session_id_context
evhtp_request_t * evhtp_request_new(evhtp_callback_cb cb, void *arg)
allocate a new request
#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_res(* evhtp_post_accept_cb)(evhtp_connection_t *conn, void *arg)
evhtp_hook_type
types associated with where a developer can hook into during the request processing cycle...
static int _evhtp_glob_match(const char *pattern, size_t pat_len, const char *string, size_t str_len)
glob/wildcard type pattern matching.
union evhtp_callback_s::@0 val
evhtp_pre_accept_cb pre_accept
#define EVHTP_RES_PROXYAUTHREQ
evhtp_res(* evhtp_hook_read_cb)(evhtp_request_t *req, evbuf_t *buf, void *arg)
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)
evhtp_res(* evhtp_hook_request_fini_cb)(evhtp_request_t *req, void *arg)
static evhtp_authority_t * _evhtp_authority_new(void)
create an authority structure
void evhtp_set_pre_accept_cb(evhtp_t *htp, evhtp_pre_accept_cb cb, void *arg)
structure containing a single callback and configuration
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_RES_RANGENOTSC
#define EVHTP_PARSE_QUERY_FLAG_IGNORE_HEX
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)
void(* evhtp_thread_init_cb)(evhtp_t *htp, evthr_t *thr, void *arg)
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 evhtp_res _evhtp_connection_error_hook(evhtp_connection_t *connection, evhtp_error_flags errtype)
runs the user-defined hook when a connection error occurs
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...
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
void(* evhtp_callback_cb)(evhtp_request_t *req, void *arg)
evbev_t * evhtp_request_get_bev(evhtp_request_t *request)
returns the underlying requests bufferevent
evhtp_res(* evhtp_hook_connection_fini_cb)(evhtp_connection_t *connection, void *arg)
#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
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 *)
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)
frees a the list of key/values, and all underlying entries
pthread_mutex_t evhtp_mutex_t
evhtp_res(* evhtp_hook)()
#define EVHTP_RES_FORBIDDEN
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)
static evhtp_res _evhtp_connection_fini_hook(evhtp_connection_t *connection)
runs the user-definedhook called just prior to a connection being closed
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_ssl_scache_init)(evhtp_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
void(* evhtp_hook_event_cb)(evhtp_connection_t *conn, short events, void *arg)
int(* evhtp_kvs_iterator)(evhtp_kv_t *kv, void *arg)
#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
static evhtp_res _evhtp_chunk_new_hook(evhtp_request_t *request, uint64_t len)
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 ...
evhtp_res(* evhtp_hook_conn_err_cb)(evhtp_connection_t *connection, evhtp_error_flags errtype, void *arg)
struct timeval recv_timeo
static int _evhtp_glob_match2(const char *pattern, size_t plen, const char *string, size_t str_len)
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
evhtp_res(* evhtp_hook_chunks_fini_cb)(evhtp_request_t *r, void *arg)
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
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)
free's resources associated with 'kv' if ONLY found within the key/value list
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_hook_event_cb on_event
void(* evhtp_ssl_scache_del)(evhtp_t *htp, unsigned char *sid, int sid_len)
evhtp_res(* evhtp_hook_headers_cb)(evhtp_request_t *req, evhtp_headers_t *hdr, 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)
find the evhtp_kv_t reference 'key' from the k/val list 'kvs'
int evhtp_unset_all_hooks(evhtp_hooks_t **hooks)
removes all hooks.
#define evhtp_headers_free
evhtp_res(* evhtp_hook_path_cb)(evhtp_request_t *req, evhtp_path_t *path, void *arg)
#define EVHTP_RES_BWEXEED
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 max_keepalive_requests
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
evhtp_ssl_sess_t *(* evhtp_ssl_scache_get)(evhtp_connection_t *connection, unsigned char *sid, int sid_len)
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
static int _evhtp_require_uri(evhtp_connection_t *c)
static void _evhtp_authority_free(evhtp_authority_t *authority)
frees an authority structure
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 in a strict manner.
static int _evhtp_request_parser_headers_start(htparser *p)
evhtp_res(* evhtp_hook_header_cb)(evhtp_request_t *req, evhtp_header_t *hdr, void *arg)
#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.
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_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
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)
creates an empty list of key/values
static const char * status_code_to_str(evhtp_res code)
#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
evhtp_connection_t * evhtp_connection_new_dns(evbase_t *evbase, struct evdns_base *dns_base, const char *addr, uint16_t port)
allocate a new connection
evhtp_res(* evhtp_hook_hostname_cb)(evhtp_request_t *r, const char *hostname, void *arg)
void evhtp_kvs_add_kvs(evhtp_kvs_t *dst, evhtp_kvs_t *src)
appends all key/val structures from src tailq onto dst tailq
structure which represents authority information in a URI
evhtp_t * evhtp_new(evbase_t *evbase, void *arg)
creates a new evhtp_t instance
int(* evhtp_ssl_scache_add)(evhtp_connection_t *connection, unsigned char *sid, int sid_len, evhtp_ssl_sess_t *sess)
evhtp_authority_t * authority
#define evhtp_request_content_len(r)
#define EVHTP_RES_USEPROXY
#define EVHTP_RES_URI_TOOLONG