Libevhtp 1.2.13
evhtp.c
Go to the documentation of this file.
1
7#include <stdlib.h>
8#include <string.h>
9#include <stdint.h>
10#include <errno.h>
11#include <signal.h>
12#include <strings.h>
13#include <inttypes.h>
14#include <stdbool.h>
15#ifndef WIN32
16#include <sys/socket.h>
17#include <netinet/in.h>
18#include <netinet/tcp.h>
19#include <arpa/inet.h>
20#else
21#define WINVER 0x0501
22#include <winsock2.h>
23#include <ws2tcpip.h>
24#endif
25#ifndef NO_SYS_UN
26#include <sys/un.h>
27#endif
28
29#include <limits.h>
30#include <event2/dns.h>
31
32#include "evhtp/config.h"
33#include "internal.h"
34#include "numtoa.h"
35#include "evhtp/evhtp.h"
36
54 void * cbarg;
55 evhtp_hooks_t * hooks;
56 size_t len;
57
58 union {
59 char * path;
60 char * glob;
61#ifndef EVHTP_DISABLE_REGEX
62 regex_t * regex;
63#endif
64 } val;
65
66 TAILQ_ENTRY(evhtp_callback) next;
67};
68
69TAILQ_HEAD(evhtp_callbacks, evhtp_callback);
70
71#define SET_BIT(VAR, FLAG) VAR |= FLAG
72#define UNSET_BIT(VAR, FLAG) VAR &= ~FLAG
73
74#define HTP_FLAG_ON(PRE, FLAG) SET_BIT(PRE->flags, FLAG)
75#define HTP_FLAG_OFF(PRE, FLAG) UNSET_BIT(PRE->flags, FLAG)
76
77#define HTP_IS_READING(b) ((bufferevent_get_enabled(b) & \
78 EV_READ) ? true : false)
79#define HTP_IS_WRITING(b) ((bufferevent_get_enabled(b) & \
80 EV_WRITE) ? true : false)
81
82#define HTP_LEN_OUTPUT(b) (evbuffer_get_length(bufferevent_get_output(b)))
83#define HTP_LEN_INPUT(b) (evbuffer_get_length(bufferevent_get_input(b)))
84
85#define HOOK_AVAIL(var, hook_name) (var->hooks && var->hooks->hook_name)
86#define HOOK_FUNC(var, hook_name) (var->hooks->hook_name)
87#define HOOK_ARGS(var, hook_name) var->hooks->hook_name ## _arg
88
89#define HOOK_REQUEST_RUN(request, hook_name, ...) do { \
90 if (HOOK_AVAIL(request, hook_name)) { \
91 return HOOK_FUNC(request, hook_name) (request, __VA_ARGS__, \
92 HOOK_ARGS(request, hook_name)); \
93 } \
94 if (request->conn && HOOK_AVAIL(request->conn, hook_name)) { \
95 return HOOK_FUNC(request->conn, hook_name) (request, __VA_ARGS__, \
96 HOOK_ARGS(request->conn, hook_name)); \
97 } \
98} while (0)
99
100#define HOOK_REQUEST_RUN_NARGS(__request, hook_name) do { \
101 if (HOOK_AVAIL(__request, hook_name)) { \
102 return HOOK_FUNC(__request, hook_name) (__request, \
103 HOOK_ARGS(__request, hook_name)); \
104 } \
105 if (__request->conn && HOOK_AVAIL(__request->conn, hook_name)) { \
106 return HOOK_FUNC(__request->conn, hook_name) (request, \
107 HOOK_ARGS(__request->conn, hook_name)); \
108 } \
109} while (0);
110
111#ifndef EVHTP_DISABLE_EVTHR
117#define htp__lock_(h) do { \
118 if (h->lock) { \
119 pthread_mutex_lock(h->lock); \
120 } \
121} while (0)
122
128#define htp__unlock_(h) do { \
129 if (h->lock) { \
130 pthread_mutex_unlock(h->lock); \
131 } \
132} while (0)
133#else
134#define htp__lock_(h) do { \
135} while (0)
136#define htp__unlock_(h) do { \
137} while (0)
138#endif
139
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); \
144 (var) = (tvar))
145#endif
146
147/* rc == request->conn. Just little things to make life easier */
148#define rc_scratch conn->scratch_buf
149#define rc_parser conn->parser
150
151/* ch_ == conn->hooks->on_... */
152#define ch_fini_arg hooks->on_connection_fini_arg
153#define ch_fini hooks->on_connection_fini
154
155/* cr_ == conn->request */
156#define cr_status request->status
157#define cr_flags request->flags
158#define cr_proto request->proto
159
160/* rh_ == request->hooks->on_ */
161#define rh_err hooks->on_error
162#define rh_err_arg hooks->on_error_arg
163
164#ifndef EVHTP_DISABLE_MEMFUNCTIONS
165
166static void * (*malloc_)(size_t sz) = malloc;
167static void * (* realloc_)(void * d, size_t sz) = realloc;
168static void (* free_)(void * d) = free;
169
180static void *
181htp__malloc_(size_t size)
182{
183 return malloc_(size);
184}
185
197static void *
198htp__realloc_(void * ptr, size_t size)
199{
200 return realloc_(ptr, size);
201}
202
212static void
213htp__free_(void * ptr)
214{
215 if (ptr == NULL) {
216 return;
217 }
218
220}
221
233static void *
234htp__calloc_(size_t nmemb, size_t size)
235{
236 if (malloc_ != malloc) {
237 size_t len = nmemb * size;
238 void * p;
239
240 if ((p = malloc_(len)) == NULL) {
241 return NULL;
242 }
243
244 memset(p, 0, len);
245
246 return p;
247 }
248
249 return calloc(nmemb, size);
250}
251
260static char *
261htp__strdup_(const char * str)
262{
263 if (malloc_ != malloc) {
264 size_t len;
265 void * p;
266
267 len = strlen(str);
268
269 if ((p = malloc_(len + 1)) == NULL) {
270 return NULL;
271 }
272
273 memcpy(p, str, len + 1);
274
275 return p;
276 }
277
278 return strdup(str);
279}
280
290static char *
291htp__strndup_(const char * str, size_t len)
292{
293 if (malloc_ != malloc) {
294 char * p;
295
296 if ((p = malloc_(len + 1)) != NULL) {
297 memcpy(p, str, len + 1);
298 } else {
299 return NULL;
300 }
301
302 p[len] = '\0';
303
304 return p;
305 }
306
307 return strndup(str, len);
308}
309
310#else
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)
317#endif
318
319
320void
321evhtp_set_mem_functions(void *(*mallocfn_)(size_t len),
322 void *(*reallocfn_)(void * p, size_t sz),
323 void (*freefn_)(void * p))
324{
325#ifndef EVHTP_DISABLE_MEMFUNCTIONS
326 malloc_ = mallocfn_;
327 realloc_ = reallocfn_;
328 free_ = freefn_;
329
330 return event_set_mem_functions(malloc_, realloc_, free_);
331#endif
332}
333
341static const char *
343{
344 switch (code) {
345 case EVHTP_RES_200:
346 return "OK";
347 case EVHTP_RES_300:
348 return "Redirect";
349 case EVHTP_RES_400:
350 return "Bad Request";
351 case EVHTP_RES_NOTFOUND:
352 return "Not Found";
353 case EVHTP_RES_SERVERR:
354 return "Internal Server Error";
355 case EVHTP_RES_CONTINUE:
356 return "Continue";
357 case EVHTP_RES_FORBIDDEN:
358 return "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:
364 return "Processing";
365 case EVHTP_RES_URI_TOOLONG:
366 return "URI Too Long";
367 case EVHTP_RES_CREATED:
368 return "Created";
369 case EVHTP_RES_ACCEPTED:
370 return "Accepted";
371 case EVHTP_RES_NAUTHINFO:
372 return "No Auth Info";
373 case EVHTP_RES_NOCONTENT:
374 return "No Content";
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:
382 return "IM Used";
383 case EVHTP_RES_FOUND:
384 return "Found";
385 case EVHTP_RES_SEEOTHER:
386 return "See Other";
387 case EVHTP_RES_NOTMOD:
388 return "Not Modified";
389 case EVHTP_RES_USEPROXY:
390 return "Use Proxy";
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:
408 return "Conflict";
409 case EVHTP_RES_GONE:
410 return "Gone";
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";
439 } /* switch */
440
441 return "UNKNOWN";
442} /* status_code_to_str */
443
444#ifndef EVHTP_DISABLE_SSL
445static int session_id_context = 1;
446#ifndef EVHTP_DISABLE_EVTHR
447static int ssl_num_locks;
450#endif
451#endif
452
453/*
454 * COMPAT FUNCTIONS
455 */
456
457#ifdef NO_STRNLEN
467static size_t
468strnlen(const char * s, size_t maxlen)
469{
470 const char * e;
471 size_t n;
472
473 for (e = s, n = 0; *e && n < maxlen; e++, n++) {
474 ;
475 }
476
477 return n;
478}
479
480#endif
481
482#ifdef NO_STRNDUP
492static char *
493strndup(const char * s, size_t n)
494{
495 size_t len = strnlen(s, n);
496 char * ret;
497
498 if (len < n) {
499 return htp__strdup_(s);
500 }
501
502 if ((ret = htp__malloc_(n + 1)) == NULL) {
503 return NULL;
504 }
505
506 ret[n] = '\0';
507
508 memcpy(ret, s, n);
509
510 return ret;
511}
512
513#endif
514
515/*
516 * PRIVATE FUNCTIONS
517 */
518
529#define htp__is_http_11_(_major, _minor) \
530 (_major >= 1 && _minor >= 1)
531
541#define htp__is_http_10_(_major, _minor) \
542 (_major >= 1 && _minor <= 0)
543
544
554static inline evhtp_proto
555htp__protocol_(const char major, const char minor)
556{
557 if (htp__is_http_10_(major, minor)) {
558 return EVHTP_PROTO_10;
559 }
560
561 if (htp__is_http_11_(major, minor)) {
562 return EVHTP_PROTO_11;
563 }
564
565 return EVHTP_PROTO_INVALID;
566}
567
576static inline evhtp_res
577htp__hook_path_(struct evhtp_request * request, struct evhtp_path * path)
578{
579 HOOK_REQUEST_RUN(request, on_path, path);
580
581 return EVHTP_RES_OK;
582}
583
594static inline evhtp_res
595htp__hook_header_(struct evhtp_request * request, evhtp_header_t * header)
596{
597 HOOK_REQUEST_RUN(request, on_header, header);
598
599 return EVHTP_RES_OK;
600}
601
611static inline evhtp_res
613{
614 HOOK_REQUEST_RUN(request, on_headers, headers);
615
616 return EVHTP_RES_OK;
617}
618
629static inline evhtp_res
630htp__hook_body_(struct evhtp_request * request, struct evbuffer * buf)
631{
632 if (request == NULL) {
633 return EVHTP_RES_500;
634 }
635
636 HOOK_REQUEST_RUN(request, on_read, buf);
637
638 return EVHTP_RES_OK;
639}
640
649static inline evhtp_res
651{
652 if (request == NULL) {
653 return EVHTP_RES_500;
654 }
655
656 HOOK_REQUEST_RUN_NARGS(request, on_request_fini);
657
658 return EVHTP_RES_OK;
659}
660
668static inline evhtp_res
669htp__hook_chunk_new_(struct evhtp_request * request, uint64_t len)
670{
671 HOOK_REQUEST_RUN(request, on_new_chunk, len);
672
673 return EVHTP_RES_OK;
674}
675
682static inline evhtp_res
684{
685 HOOK_REQUEST_RUN_NARGS(request, on_chunk_fini);
686
687 return EVHTP_RES_OK;
688}
689
696static inline evhtp_res
698{
699 HOOK_REQUEST_RUN_NARGS(request, on_chunks_fini);
700
701 return EVHTP_RES_OK;
702}
703
710static inline evhtp_res
712{
713 HOOK_REQUEST_RUN_NARGS(request, on_headers_start);
714
715 return EVHTP_RES_OK;
716}
717
726static inline evhtp_res
728{
729 if (evhtp_unlikely(connection == NULL)) {
730 return 500;
731 }
732
733 if (connection->hooks != NULL && connection->ch_fini != NULL) {
734 return (connection->ch_fini)(connection, connection->ch_fini_arg);
735 }
736
737 return EVHTP_RES_OK;
738}
739
746static inline void
748{
749 if (request && request->hooks && request->rh_err) {
750 (*request->rh_err)(request, errtype, request->rh_err_arg);
751 }
752}
753
760static inline evhtp_res
762{
763 if (connection == NULL) {
764 return EVHTP_RES_FATAL;
765 }
766
767 if (connection->request != NULL) {
768 htp__hook_error_(connection->request, errtype);
769 }
770
771 return EVHTP_RES_OK;
772}
773
781static inline evhtp_res
782htp__hook_hostname_(struct evhtp_request * r, const char * hostname)
783{
784 HOOK_REQUEST_RUN(r, on_hostname, hostname);
785
786 return EVHTP_RES_OK;
787}
788
795static inline evhtp_res
797{
798 if (connection->hooks && connection->hooks->on_write) {
799 return (connection->hooks->on_write)(connection,
800 connection->hooks->on_write_arg);
801 }
802
803 return EVHTP_RES_OK;
804}
805
816static int
817htp__glob_match_(const char * pattern, size_t plen,
818 const char * string, size_t str_len)
819{
820 while (plen) {
821 switch (pattern[0]) {
822 case '*':
823 while (pattern[1] == '*') {
824 pattern++;
825 plen--;
826 }
827
828 if (plen == 1) {
829 return 1; /* match */
830 }
831
832 while (str_len) {
833 if (htp__glob_match_(pattern + 1, plen - 1,
834 string, str_len)) {
835 return 1; /* match */
836 }
837
838 string++;
839 str_len--;
840 }
841
842 return 0; /* no match */
843 default:
844 if (pattern[0] != string[0]) {
845 return 0; /* no match */
846 }
847
848 string++;
849 str_len--;
850 break;
851 } /* switch */
852
853 pattern++;
854 plen--;
855
856 if (str_len == 0) {
857 while (*pattern == '*') {
858 pattern++;
859 plen--;
860 }
861
862 break;
863 }
864 }
865
866 if (plen == 0 && str_len == 0) {
867 return 1;
868 }
869
870 return 0;
871} /* htp__glob_match_ */
872
882static evhtp_callback_t *
884 const char * path,
885 unsigned int * start_offset,
886 unsigned int * end_offset)
887{
888 size_t path_len;
889 evhtp_callback_t * callback;
890
891#ifndef EVHTP_DISABLE_REGEX
892 regmatch_t pmatch[28];
893#endif
894
895 if (evhtp_unlikely(cbs == NULL)) {
896 return NULL;
897 }
898
899 path_len = strlen(path);
900
901 TAILQ_FOREACH(callback, cbs, next) {
902 switch (callback->type) {
904 if (strncmp(path, callback->val.path, callback->len) == 0) {
905 *start_offset = 0;
906 *end_offset = path_len;
907
908 return callback;
909 }
910
911 break;
912#ifndef EVHTP_DISABLE_REGEX
914 if (regexec(callback->val.regex,
915 path,
916 callback->val.regex->re_nsub + 1,
917 pmatch, 0) == 0) {
918 *start_offset = pmatch[callback->val.regex->re_nsub].rm_so;
919 *end_offset = pmatch[callback->val.regex->re_nsub].rm_eo;
920
921 return callback;
922 }
923
924 break;
925#endif
927 {
928 size_t glob_len = strlen(callback->val.glob);
929
930 if (htp__glob_match_(callback->val.glob,
931 glob_len,
932 path,
933 path_len) == 1) {
934 *start_offset = 0;
935 *end_offset = path_len;
936
937 return callback;
938 }
939 }
940 default:
941 break;
942 } /* switch */
943 }
944
945 return NULL;
946} /* htp__callback_find_ */
947
952static void
954{
955 if (evhtp_unlikely(path == NULL)) {
956 return;
957 }
958
964
966}
967
984static int
985htp__path_new_(evhtp_path_t ** out, const char * data, size_t len)
986{
987 struct evhtp_path * req_path = NULL;
988 const char * data_end = (const char *)(data + len);
989 char * path = NULL;
990 char * file = NULL;
991
992
993 req_path = htp__calloc_(1, sizeof(*req_path));
994
995#ifndef NDEBUG
996 if (req_path == NULL) {
997 return -1;
998 }
999
1000#endif
1001 *out = NULL;
1002
1003 if (evhtp_unlikely(len == 0)) {
1004 /*
1005 * odd situation here, no preceding "/", so just assume the path is "/"
1006 */
1007 path = htp__strdup_("/");
1008
1009 if (evhtp_unlikely(path == NULL)) {
1010 goto error;
1011 }
1012 } else if (*data != '/') {
1013 /* request like GET stupid HTTP/1.0, treat stupid as the file, and
1014 * assume the path is "/"
1015 */
1016 path = htp__strdup_("/");
1017
1018 if (evhtp_unlikely(path == NULL)) {
1019 goto error;
1020 }
1021
1022 file = htp__strndup_(data, len);
1023
1024 if (evhtp_unlikely(file == NULL)) {
1025 goto error;
1026 }
1027 } else {
1028 if (data[len - 1] != '/') {
1029 /*
1030 * the last character in data is assumed to be a file, not the end of path
1031 * loop through the input data backwards until we find a "/"
1032 */
1033 size_t i;
1034
1035 for (i = (len - 1); i != 0; i--) {
1036 if (data[i] == '/') {
1037 /*
1038 * we have found a "/" representing the start of the file,
1039 * and the end of the path
1040 */
1041 size_t path_len;
1042 size_t file_len;
1043
1044 path_len = (size_t)(&data[i] - data) + 1;
1045 file_len = (size_t)(data_end - &data[i + 1]);
1046
1047 /* check for overflow */
1048 if ((const char *)(data + path_len) > data_end) {
1049 goto error;
1050 }
1051
1052 /* check for overflow */
1053 if ((const char *)(&data[i + 1] + file_len) > data_end) {
1054 goto error;
1055 }
1056
1057 path = htp__strndup_(data, path_len);
1058
1059 if (evhtp_unlikely(path == NULL)) {
1060 goto error;
1061 }
1062
1063 file = htp__strndup_(&data[i + 1], file_len);
1064
1065 if (evhtp_unlikely(file == NULL)) {
1066 goto error;
1067 }
1068
1069 break;
1070 }
1071 }
1072
1073 if (i == 0 && data[i] == '/' && !file && !path) {
1074 /* drops here if the request is something like GET /foo */
1075 path = htp__strdup_("/");
1076
1077 if (evhtp_unlikely(path == NULL)) {
1078 goto error;
1079 }
1080
1081 if (len > 1) {
1082 file = htp__strndup_((const char *)(data + 1), len);
1083
1084 if (evhtp_unlikely(file == NULL)) {
1085 goto error;
1086 }
1087 }
1088 }
1089 } else {
1090 /* the last character is a "/", thus the request is just a path */
1091 path = htp__strndup_(data, len);
1092
1093 if (evhtp_unlikely(path == NULL)) {
1094 goto error;
1095 }
1096 }
1097 }
1098
1099 if (len != 0) {
1100 req_path->full = htp__strndup_(data, len);
1101 } else {
1102 req_path->full = htp__strdup_("/");
1103 }
1104
1105 if (evhtp_unlikely(req_path->full == NULL)) {
1106 goto error;
1107 }
1108
1109 req_path->path = path;
1110 req_path->file = file;
1111
1112 *out = req_path;
1113
1114 return 0;
1115error:
1119
1120 return -1;
1121} /* htp__path_new_ */
1122
1128static int
1129htp__authority_new_(evhtp_authority_t ** out)
1130{
1131 struct evhtp_authority * authority;
1132
1133 if (evhtp_unlikely(out == NULL)) {
1134 return -1;
1135 }
1136
1137 *out = htp__calloc_(1, sizeof(*authority));
1138
1139 return (*out != NULL) ? 0 : -1;
1140}
1141
1147static void
1148htp__authority_free_(evhtp_authority_t * authority)
1149{
1150 if (authority == NULL) {
1151 return;
1152 }
1153
1154 evhtp_safe_free(authority->username, htp__free_);
1155 evhtp_safe_free(authority->password, htp__free_);
1156 evhtp_safe_free(authority->hostname, htp__free_);
1157
1158 evhtp_safe_free(authority, htp__free_);
1159}
1160
1166static void
1167htp__uri_free_(evhtp_uri_t * uri)
1168{
1169 if (evhtp_unlikely(uri == NULL)) {
1170 return;
1171 }
1172
1173 evhtp_safe_free(uri->query, evhtp_query_free);
1174 evhtp_safe_free(uri->path, htp__path_free_);
1175 evhtp_safe_free(uri->authority, htp__authority_free_);
1176
1177 evhtp_safe_free(uri->fragment, htp__free_);
1178 evhtp_safe_free(uri->query_raw, htp__free_);
1179
1181}
1182
1188static int
1189htp__uri_new_(evhtp_uri_t ** out)
1190{
1191 struct evhtp_uri * uri;
1192
1193 *out = NULL;
1194
1195 if ((uri = htp__calloc_(1, sizeof(*uri))) == NULL) {
1196 return -1;
1197 }
1198
1199 uri->authority = NULL;
1200
1201 if (htp__authority_new_(&uri->authority) == -1) {
1203 return -1;
1204 }
1205
1206 *out = uri;
1207
1208 return 0;
1209}
1210
1216static void
1217htp__request_free_(evhtp_request_t * request)
1218{
1219 if (request == NULL) {
1220 return;
1221 }
1222
1223 htp__hook_request_fini_(request);
1224
1225 evhtp_safe_free(request->uri, htp__uri_free_);
1226 evhtp_safe_free(request->headers_in, evhtp_kvs_free);
1227 evhtp_safe_free(request->headers_out, evhtp_kvs_free);
1228
1229 if (request->conn && request->conn->request == request) {
1230 request->conn->request = NULL;
1231 }
1232
1233 if (request->buffer_in != NULL) {
1234 evhtp_safe_free(request->buffer_in, evbuffer_free);
1235 }
1236
1237 if (request->buffer_out != NULL) {
1238 evhtp_safe_free(request->buffer_out, evbuffer_free);
1239 }
1240
1241 evhtp_safe_free(request->hooks, htp__free_);
1242 evhtp_safe_free(request, htp__free_);
1243}
1244
1252static evhtp_request_t *
1253htp__request_new_(evhtp_connection_t * c)
1254{
1255 struct evhtp_request * req;
1256 uint8_t error;
1257
1258 if (evhtp_unlikely(!(req = htp__calloc_(sizeof(*req), 1)))) {
1259 return NULL;
1260 }
1261
1262 error = 1;
1263 req->conn = c;
1264 req->htp = c ? c->htp : NULL;
1265 req->status = EVHTP_RES_OK;
1266
1267 do {
1268 if (!(req->buffer_in = evbuffer_new())) {
1269 break;
1270 }
1271
1272 if (!(req->buffer_out = evbuffer_new())) {
1273 break;
1274 }
1275
1276 if (!(req->headers_in = htp__malloc_(sizeof(*req->headers_in)))) {
1277 break;
1278 }
1279
1280 if (!(req->headers_out = htp__malloc_(sizeof(evhtp_headers_t)))) {
1281 break;
1282 }
1283
1284 TAILQ_INIT(req->headers_in);
1285 TAILQ_INIT(req->headers_out);
1286
1287 error = 0;
1288 } while (0);
1289
1290 if (error == 0) {
1291 return req;
1292 }
1293
1295
1296 return req;
1297} /* htp__request_new_ */
1298
1305static int
1307{
1308 evhtp_connection_t * c;
1309
1310 if (p == NULL) {
1311 return 0;
1312 }
1313
1314 if (!(c = htparser_get_userdata(p))) {
1315 return 0;
1316 }
1317
1318 if (evhtp_unlikely(c->type == evhtp_type_client)) {
1319 return 0;
1320 }
1321
1322 if (c->flags & EVHTP_CONN_FLAG_PAUSED) {
1323 return -1;
1324 }
1325
1326 if (c->request) {
1327 if (c->request->flags & EVHTP_REQ_FLAG_FINISHED) {
1329 } else {
1330 return -1;
1331 }
1332 }
1333
1334 if (((c->request = htp__request_new_(c))) == NULL) {
1335 return -1;
1336 }
1337
1338 return 0;
1339}
1340
1351static int
1352htp__request_parse_args_(htparser * p, const char * data, size_t len)
1353{
1354 evhtp_connection_t * c = htparser_get_userdata(p);
1355 evhtp_uri_t * uri = c->request->uri;
1356 const char * fragment;
1357 int ignore_fragment;
1358
1359 if (c->type == evhtp_type_client) {
1360 /* as a client, technically we should never get here, but just in case
1361 * we return a 0 to the parser to continue.
1362 */
1363 return 0;
1364 }
1365
1366 /* if the parser flags has the IGNORE_FRAGMENTS bit set, skip
1367 * the fragment parsing
1368 */
1369 ignore_fragment = (c->htp->parser_flags &
1371
1372
1373 if (!ignore_fragment && (fragment = memchr(data, '#', len))) {
1374 /* Separate fragment from query according to RFC 3986.
1375 *
1376 * XXX: not happy about using strchr stuff, maybe this functionality
1377 * is more apt as part of evhtp_parse_query()
1378 */
1379
1380 ptrdiff_t frag_offset;
1381
1382 frag_offset = fragment - data;
1383
1384 if (frag_offset < len) {
1385 size_t fraglen;
1386
1387 /* Skip '#'. */
1388 fragment += 1;
1389 frag_offset += 1;
1390 fraglen = len - frag_offset;
1391
1392 uri->fragment = htp__malloc_(fraglen + 1);
1393 evhtp_alloc_assert(uri->fragment);
1394
1395 memcpy(uri->fragment, fragment, fraglen);
1396
1397 uri->fragment[fraglen] = '\0';
1398 len -= fraglen + 1; /* Skip '#' + fragment string. */
1399 }
1400 }
1401
1402 uri->query = evhtp_parse_query_wflags(data, len, c->htp->parser_flags);
1403
1404 if (evhtp_unlikely(!uri->query)) {
1405 c->cr_status = EVHTP_RES_ERROR;
1406
1407 return -1;
1408 }
1409
1410 uri->query_raw = htp__malloc_(len + 1);
1411 evhtp_alloc_assert(uri->query_raw);
1412
1413 memcpy(uri->query_raw, data, len);
1414 uri->query_raw[len] = '\0';
1415
1416 return 0;
1417} /* htp__request_parse_args_ */
1418
1419static int
1421{
1422 evhtp_connection_t * c = htparser_get_userdata(p);
1423
1424 if ((c->cr_status = htp__hook_headers_start_(c->request)) != EVHTP_RES_OK) {
1425 return -1;
1426 }
1427
1428 return 0;
1429}
1430
1431static int
1432htp__request_parse_header_key_(htparser * p, const char * data, size_t len)
1433{
1434 evhtp_connection_t * c = htparser_get_userdata(p);
1435 char * key_s;
1436 evhtp_header_t * hdr;
1437
1438 key_s = htp__malloc_(len + 1);
1439 evhtp_alloc_assert(key_s);
1440
1441 if (key_s == NULL) {
1442 c->cr_status = EVHTP_RES_FATAL;
1443
1444 return -1;
1445 }
1446
1447 key_s[len] = '\0';
1448 memcpy(key_s, data, len);
1449
1450 if ((hdr = evhtp_header_key_add(c->request->headers_in, key_s, 0)) == NULL) {
1451 htp__free_(key_s);
1452
1453 c->cr_status = EVHTP_RES_FATAL;
1454
1455 return -1;
1456 }
1457
1458 hdr->k_heaped = 1;
1459
1460 return 0;
1461}
1462
1463static int
1464htp__request_parse_header_val_(htparser * p, const char * data, size_t len)
1465{
1466 evhtp_connection_t * c = htparser_get_userdata(p);
1467 char * val_s;
1468 evhtp_header_t * header;
1469
1470 val_s = htp__malloc_(len + 1);
1471 evhtp_alloc_assert(val_s);
1472
1473 val_s[len] = '\0';
1474 memcpy(val_s, data, len);
1475
1476 if ((header = evhtp_header_val_add(c->request->headers_in, val_s, 0)) == NULL) {
1478 c->cr_status = EVHTP_RES_FATAL;
1479
1480 return -1;
1481 }
1482
1483 header->v_heaped = 1;
1484
1485 if ((c->cr_status = htp__hook_header_(c->request, header)) != EVHTP_RES_OK) {
1486 return -1;
1487 }
1488
1489 return 0;
1490}
1491
1492static inline evhtp_t *
1493htp__request_find_vhost_(evhtp_t * evhtp, const char * name)
1494{
1495 evhtp_t * evhtp_vhost;
1496 evhtp_alias_t * evhtp_alias;
1497
1498 TAILQ_FOREACH(evhtp_vhost, &evhtp->vhosts, next_vhost) {
1499 if (evhtp_unlikely(evhtp_vhost->server_name == NULL)) {
1500 continue;
1501 }
1502
1503 if (htp__glob_match_(evhtp_vhost->server_name,
1504 strlen(evhtp_vhost->server_name), name,
1505 strlen(name)) == 1) {
1506 return evhtp_vhost;
1507 }
1508
1509 TAILQ_FOREACH(evhtp_alias, &evhtp_vhost->aliases, next) {
1510 if (evhtp_alias->alias == NULL) {
1511 continue;
1512 }
1513
1515 strlen(evhtp_alias->alias), name,
1516 strlen(name)) == 1) {
1517 return evhtp_vhost;
1518 }
1519 }
1520 }
1521
1522 return NULL;
1523}
1524
1525static inline int
1526htp__request_set_callbacks_(evhtp_request_t * request)
1527{
1528 evhtp_t * evhtp;
1529 evhtp_connection_t * conn;
1530 evhtp_uri_t * uri;
1531 evhtp_path_t * path;
1532 evhtp_hooks_t * hooks;
1533 evhtp_callback_t * callback;
1535 void * cbarg;
1536
1537 if (request == NULL) {
1538 return -1;
1539 }
1540
1541 if ((evhtp = request->htp) == NULL) {
1542 return -1;
1543 }
1544
1545 if ((conn = request->conn) == NULL) {
1546 return -1;
1547 }
1548
1549 if ((uri = request->uri) == NULL) {
1550 return -1;
1551 }
1552
1553 if ((path = uri->path) == NULL) {
1554 return -1;
1555 }
1556
1557 hooks = NULL;
1558 callback = NULL;
1559 cb = NULL;
1560 cbarg = NULL;
1561
1562 if ((callback = htp__callback_find_(evhtp->callbacks, path->full,
1563 &path->matched_soff, &path->matched_eoff))) {
1564 /* matched a callback using both path and file (/a/b/c/d) */
1565 cb = callback->cb;
1566 cbarg = callback->cbarg;
1567 hooks = callback->hooks;
1568 } else if ((callback = htp__callback_find_(evhtp->callbacks, path->path,
1569 &path->matched_soff, &path->matched_eoff))) {
1570 /* matched a callback using *just* the path (/a/b/c/) */
1571 cb = callback->cb;
1572 cbarg = callback->cbarg;
1573 hooks = callback->hooks;
1574 } else {
1575 /* no callbacks found for either case, use defaults */
1576 cb = evhtp->defaults.cb;
1577 cbarg = evhtp->defaults.cbarg;
1578
1579 path->matched_soff = 0;
1580 path->matched_eoff = (unsigned int)strlen(path->full);
1581 }
1582
1583 if (path->match_start == NULL) {
1584 path->match_start = htp__calloc_(strlen(path->full) + 1, 1);
1585 evhtp_alloc_assert(path->match_start);
1586 }
1587
1588 if (path->match_end == NULL) {
1589 path->match_end = htp__calloc_(strlen(path->full) + 1, 1);
1590 evhtp_alloc_assert(path->match_end);
1591 }
1592
1593 if (path->matched_soff != UINT_MAX /*ONIG_REGION_NOTPOS*/) {
1594 if (path->matched_eoff - path->matched_soff) {
1595 memcpy(path->match_start, (void *)(path->full + path->matched_soff),
1596 path->matched_eoff - path->matched_soff);
1597 } else {
1598 memcpy(path->match_start, (void *)(path->full + path->matched_soff),
1599 strlen((const char *)(path->full + path->matched_soff)));
1600 }
1601
1602 memcpy(path->match_end,
1603 (void *)(path->full + path->matched_eoff),
1604 strlen(path->full) - path->matched_eoff);
1605 }
1606
1607 if (hooks != NULL) {
1608 if (request->hooks == NULL) {
1609 request->hooks = htp__malloc_(sizeof(evhtp_hooks_t));
1610 evhtp_alloc_assert(request->hooks);
1611 }
1612
1613 memcpy(request->hooks, hooks, sizeof(evhtp_hooks_t));
1614 }
1615
1616 request->cb = cb;
1617 request->cbarg = cbarg;
1618
1619 return 0;
1620} /* htp__request_set_callbacks_ */
1621
1622static int
1623htp__request_parse_hostname_(htparser * p, const char * data, size_t len)
1624{
1625 evhtp_connection_t * c = htparser_get_userdata(p);
1626 evhtp_t * evhtp;
1627 evhtp_t * evhtp_vhost;
1628
1629#ifndef EVHTP_DISABLE_SSL
1630 if ((c->flags & EVHTP_CONN_FLAG_VHOST_VIA_SNI) && c->ssl != NULL) {
1631 /* use the SNI set hostname instead of the header hostname */
1632 const char * host;
1633
1634 host = SSL_get_servername(c->ssl, TLSEXT_NAMETYPE_host_name);
1635
1636 if ((c->cr_status = htp__hook_hostname_(c->request, host)) != EVHTP_RES_OK) {
1637 return -1;
1638 }
1639
1640 return 0;
1641 }
1642
1643#endif
1644
1645 evhtp = c->htp;
1646
1647 /* since this is called after htp__request_parse_path_(), which already
1648 * setup callbacks for the URI, we must now attempt to find callbacks which
1649 * are specific to this host.
1650 */
1652 {
1653 if ((evhtp_vhost = htp__request_find_vhost_(evhtp, data))) {
1654 htp__lock_(evhtp_vhost);
1655 {
1656 /* if we found a match for the host, we must set the htp
1657 * variables for both the connection and the request.
1658 */
1659 c->htp = evhtp_vhost;
1660 c->request->htp = evhtp_vhost;
1661
1662 htp__request_set_callbacks_(c->request);
1663 }
1664 htp__unlock_(evhtp_vhost);
1665 }
1666 }
1668
1669 if ((c->cr_status = htp__hook_hostname_(c->request, data)) != EVHTP_RES_OK) {
1670 return -1;
1671 }
1672
1673 return 0;
1674} /* htp__request_parse_hostname_ */
1675
1676static int
1677htp__require_uri_(evhtp_connection_t * c)
1678{
1679 if (c != NULL && c->request != NULL) {
1680 if (c->request->uri == NULL) {
1681 return htp__uri_new_(&c->request->uri);
1682 }
1683
1684 return 0;
1685 }
1686
1687 return -1;
1688}
1689
1690static int
1691htp__request_parse_host_(htparser * p, const char * data, size_t len)
1692{
1693 evhtp_connection_t * c;
1694 evhtp_authority_t * authority;
1695
1696 if (evhtp_unlikely(p == NULL)) {
1697 return -1;
1698 }
1699
1700 c = htparser_get_userdata(p);
1701
1702 /* all null checks are done in require_uri_,
1703 * no need to check twice
1704 */
1705 if (htp__require_uri_(c) == -1) {
1706 return -1;
1707 }
1708
1709 authority = c->request->uri->authority;
1710 authority->hostname = htp__malloc_(len + 1);
1711 evhtp_alloc_assert(authority->hostname);
1712
1713 if (authority->hostname == NULL) {
1714 c->cr_status = EVHTP_RES_FATAL;
1715
1716 return -1;
1717 }
1718
1719 memcpy(authority->hostname, data, len);
1720 authority->hostname[len] = '\0';
1721
1722 return 0;
1723}
1724
1725static int
1726htp__request_parse_port_(htparser * p, const char * data, size_t len)
1727{
1728 evhtp_connection_t * c = htparser_get_userdata(p);
1729 evhtp_authority_t * authority;
1730 char * endptr;
1731 unsigned long port;
1732
1733 if (htp__require_uri_(c) == -1) {
1734 return -1;
1735 }
1736
1737 authority = c->request->uri->authority;
1738 port = strtoul(data, &endptr, 10);
1739
1740 if (endptr - data != len || port > 65535) {
1741 c->cr_status = EVHTP_RES_FATAL;
1742
1743 return -1;
1744 }
1745
1746 authority->port = port;
1747
1748 return 0;
1749}
1750
1751static int
1752htp__request_parse_path_(htparser * p, const char * data, size_t len)
1753{
1754 evhtp_connection_t * c = htparser_get_userdata(p);
1755 evhtp_path_t * path;
1756
1757 if (evhtp_unlikely(p == NULL || c == NULL)) {
1758 return -1;
1759 }
1760
1761 if (htp__require_uri_(c) == -1) {
1762 return -1;
1763 }
1764
1765 if (htp__path_new_(&path, data, len) == -1) {
1766 c->cr_status = EVHTP_RES_FATAL;
1767
1768 return -1;
1769 }
1770
1771 c->request->uri->path = path;
1772 c->request->uri->scheme = htparser_get_scheme(p);
1773 c->request->method = htparser_get_method(p);
1774
1775 htp__lock_(c->htp);
1776 {
1777 htp__request_set_callbacks_(c->request);
1778 }
1779 htp__unlock_(c->htp);
1780
1781 if ((c->cr_status = htp__hook_path_(c->request, path)) != EVHTP_RES_OK) {
1782 return -1;
1783 }
1784
1785 return 0;
1786} /* htp__request_parse_path_ */
1787
1788static int
1790{
1791 evhtp_connection_t * c;
1792
1793 if ((c = htparser_get_userdata(p)) == NULL) {
1794 return -1;
1795 }
1796
1797 /* XXX proto should be set with htparsers on_hdrs_begin hook */
1798
1799 if (htparser_should_keep_alive(p) == 1) {
1801 }
1802
1804 c->cr_status = htp__hook_headers_(c->request, c->request->headers_in);
1805
1806 if (c->cr_status != EVHTP_RES_OK) {
1807 return -1;
1808 }
1809
1810 if (c->type == evhtp_type_server
1811 && c->htp->flags & EVHTP_FLAG_ENABLE_100_CONT) {
1812 /* only send a 100 continue response if it hasn't been disabled via
1813 * evhtp_disable_100_continue.
1814 */
1815 if (!evhtp_header_find(c->request->headers_in, "Expect")) {
1816 return 0;
1817 }
1818
1819 evbuffer_add_printf(bufferevent_get_output(c->bev),
1820 "HTTP/%c.%c 100 Continue\r\n\r\n",
1823 }
1824
1825 return 0;
1826}
1827
1828static int
1829htp__request_parse_body_(htparser * p, const char * data, size_t len)
1830{
1831 evhtp_connection_t * c = htparser_get_userdata(p);
1832 struct evbuffer * buf;
1833 int res = 0;
1834
1835 if (c->max_body_size > 0 && c->body_bytes_read + len >= c->max_body_size) {
1837 c->cr_status = EVHTP_RES_DATA_TOO_LONG;
1838
1839 return -1;
1840 }
1841
1842 if ((buf = c->scratch_buf) == NULL) {
1843 return -1;
1844 }
1845
1846 evbuffer_add(buf, data, len);
1847
1848 if ((c->cr_status = htp__hook_body_(c->request, buf)) != EVHTP_RES_OK) {
1849 res = -1;
1850 }
1851
1852 if (evbuffer_get_length(buf)) {
1853 evbuffer_add_buffer(c->request->buffer_in, buf);
1854 }
1855
1856 evbuffer_drain(buf, -1);
1857
1858 c->body_bytes_read += len;
1859
1860 return res;
1861}
1862
1863static int
1865{
1866 evhtp_connection_t * c = htparser_get_userdata(p);
1867
1868 if (c == NULL) {
1869 return -1;
1870 }
1871
1872 if ((c->cr_status =
1874 return -1;
1875 }
1876
1877 return 0;
1878}
1879
1880static int
1882{
1883 evhtp_connection_t * c = htparser_get_userdata(p);
1884
1885 if (c == NULL) {
1886 return -1;
1887 }
1888
1889 if ((c->cr_status = htp__hook_chunk_fini_(c->request)) != EVHTP_RES_OK) {
1890 return -1;
1891 }
1892
1893 return 0;
1894}
1895
1896static int
1898{
1899 evhtp_connection_t * c = htparser_get_userdata(p);
1900
1901 if (c == NULL) {
1902 return -1;
1903 }
1904
1905 if ((c->cr_status = htp__hook_chunks_fini_(c->request)) != EVHTP_RES_OK) {
1906 return -1;
1907 }
1908
1909 return 0;
1910}
1911
1922static int
1923htp__should_parse_query_body_(evhtp_request_t * req)
1924{
1925 const char * content_type;
1926
1927 if (req == NULL) {
1928 return 0;
1929 }
1930
1931 if (req->uri == NULL || req->uri->query != NULL) {
1932 return 0;
1933 }
1934
1935 if (evhtp_request_content_len(req) == 0) {
1936 return 0;
1937 }
1938
1939 if (evhtp_request_content_len(req) !=
1940 evbuffer_get_length(req->buffer_in)) {
1941 return 0;
1942 }
1943
1944 content_type = evhtp_kv_find(req->headers_in, "content-type");
1945
1946 if (content_type == NULL) {
1947 return 0;
1948 }
1949
1950 if (strncasecmp(content_type, "application/x-www-form-urlencoded", 33)) {
1951 return 0;
1952 }
1953
1954 return 1;
1955}
1956
1957static int
1959{
1960 evhtp_connection_t * c = htparser_get_userdata(p);
1961
1962 if (c == NULL) {
1963 return -1;
1964 }
1965
1966 if (c->flags & EVHTP_CONN_FLAG_PAUSED) {
1967 return -1;
1968 }
1969
1970 /* check to see if we should use the body of the request as the query
1971 * arguments.
1972 *
1973 * htp__should_parse_query_body_ does all the proper null checks.
1974 */
1975 if (htp__should_parse_query_body_(c->request) == 1) {
1976 const char * body;
1977 size_t body_len;
1978 evhtp_uri_t * uri;
1979 struct evbuffer * buf_in;
1980
1981 uri = c->request->uri;
1982 buf_in = c->request->buffer_in;
1983
1984 body_len = evbuffer_get_length(buf_in);
1985 body = (const char *)evbuffer_pullup(buf_in, body_len);
1986
1987 uri->query_raw = htp__calloc_(body_len + 1, 1);
1988
1989 if (evhtp_unlikely(uri->query_raw == NULL)) {
1990 c->cr_status = EVHTP_RES_FATAL;
1991 return -1;
1992 }
1993
1994 memcpy(uri->query_raw, body, body_len);
1995
1996 uri->query = evhtp_parse_query(body, body_len);
1997 }
1998
1999 /*
2000 * XXX c->request should never be NULL, but we have found some path of
2001 * execution where this actually happens. We will check for now, but the bug
2002 * path needs to be tracked down.
2003 *
2004 */
2005 if (c->request && c->request->cb) {
2006 (c->request->cb)(c->request, c->request->cbarg);
2007 }
2008
2009 if (c->flags & EVHTP_CONN_FLAG_PAUSED) {
2010 return -1;
2011 }
2012
2013 return 0;
2014} /* htp__request_parse_fini_ */
2015
2016static size_t
2017htp__evbuffer_add_iovec_(struct evbuffer * buf, struct evbuffer_iovec * vec, int n_vec)
2018{
2019#if LIBEVENT_VERSION_NUMBER < 0x02010000
2020 int n;
2021 size_t res;
2022 size_t to_alloc;
2023
2024 res = to_alloc = 0;
2025
2026 for (n = 0; n < n_vec; n++) {
2027 to_alloc += vec[n].iov_len;
2028 }
2029
2030 evbuffer_expand(buf, to_alloc);
2031
2032 for (n = 0; n < n_vec; n++) {
2033 evbuffer_add(buf, vec[n].iov_base, vec[n].iov_len);
2034
2035 res += vec[n].iov_len;
2036 }
2037
2038 return res;
2039#else
2040 return evbuffer_add_iovec(buf, vec, n_vec);
2041#endif
2042}
2043
2044static int
2045htp__create_headers_(evhtp_header_t * header, void * arg)
2046{
2047 struct evbuffer * buf = arg;
2048 struct evbuffer_iovec iov[4] = {
2049 { header->key, header->klen },
2050 { ": ", 2 },
2051 { header->val, header->vlen },
2052 { "\r\n", 2 }
2053 };
2054
2055 htp__evbuffer_add_iovec_(buf, iov, 4);
2056
2057 return 0;
2058}
2059
2060static struct evbuffer *
2061htp__create_reply_(evhtp_request_t * request, evhtp_res code)
2062{
2063 struct evbuffer * buf;
2064 const char * content_type;
2065 char res_buf[2048];
2066 int sres;
2067 size_t out_len;
2068 unsigned char major;
2069 unsigned char minor;
2070 char out_buf[64];
2071
2072 evhtp_assert(request
2073 && request->headers_out
2074 && request->buffer_out
2075 && request->conn
2076 && request->rc_parser);
2077
2078 request->status = code;
2079 content_type = evhtp_header_find(request->headers_out, "Content-Type");
2080 out_len = evbuffer_get_length(request->buffer_out);
2081
2082 if ((buf = request->rc_scratch) == NULL) {
2083 request->rc_scratch = evbuffer_new();
2084 evhtp_alloc_assert(request->rc_scratch);
2085 }
2086
2087 evbuffer_drain(buf, -1);
2088
2089 if (htparser_get_multipart(request->rc_parser) == 1) {
2090 goto check_proto;
2091 }
2092
2093 if (out_len && !(request->flags & EVHTP_REQ_FLAG_CHUNKED)) {
2094 /* add extra headers (like content-length/type) if not already present */
2095
2096 if (!evhtp_header_find(request->headers_out, "Content-Length")) {
2097 /* convert the buffer_out length to a string and set
2098 * and add the new Content-Length header.
2099 */
2100 evhtp_modp_sizetoa(out_len, out_buf);
2101
2102 evhtp_headers_add_header(request->headers_out,
2103 evhtp_header_new("Content-Length", out_buf, 0, 1));
2104 }
2105 }
2106
2107check_proto:
2108 /* add the proper keep-alive type headers based on http version */
2109 switch (request->proto) {
2110 case EVHTP_PROTO_11:
2111 if (!(request->flags & EVHTP_REQ_FLAG_KEEPALIVE)) {
2112 /* protocol is HTTP/1.1 but client wanted to close */
2113 evhtp_headers_add_header(request->headers_out,
2114 evhtp_header_new("Connection", "close", 0, 0));
2115 }
2116
2117 if (!evhtp_header_find(request->headers_out, "Content-Length") &&
2118 /* cannot have both chunked and content-length */
2119 !(request->flags & EVHTP_REQ_FLAG_CHUNKED)) {
2120 evhtp_headers_add_header(request->headers_out,
2121 evhtp_header_new("Content-Length", "0", 0, 0));
2122 }
2123
2124 break;
2125 case EVHTP_PROTO_10:
2126 if (request->flags & EVHTP_REQ_FLAG_KEEPALIVE) {
2127 /* protocol is HTTP/1.0 and clients wants to keep established */
2128 evhtp_headers_add_header(request->headers_out,
2129 evhtp_header_new("Connection", "keep-alive", 0, 0));
2130 }
2131
2132 break;
2133 default:
2134 /* this sometimes happens when a response is made but paused before
2135 * the method has been parsed */
2136 htparser_set_major(request->rc_parser, 1);
2137 htparser_set_minor(request->rc_parser, 0);
2138 break;
2139 } /* switch */
2140
2141
2142 if (!content_type) {
2143 evhtp_headers_add_header(request->headers_out,
2144 evhtp_header_new("Content-Type", "text/plain", 0, 0));
2145 }
2146
2147 /* attempt to add the status line into a temporary buffer and then use
2148 * evbuffer_add(). Using plain old snprintf() will be faster than
2149 * evbuffer_add_printf(). If the snprintf() fails, which it rarely should,
2150 * we fallback to using evbuffer_add_printf().
2151 */
2152
2153 major = evhtp_modp_uchartoa(htparser_get_major(request->rc_parser));
2154 minor = evhtp_modp_uchartoa(htparser_get_minor(request->rc_parser));
2155
2156 evhtp_modp_u32toa((uint32_t)code, out_buf);
2157
2158 /* create the initial reply status via scatter-gather io (note: this used to
2159 * be a formatted write which led to some spurrious performance problems.
2160 * This now uses iovec/scatter/gather to create the status reply portion
2161 * of the header.
2162 */
2163 {
2164 const char * status_str = status_code_to_str(code);
2165 struct evbuffer_iovec iov[9] = {
2166 { "HTTP/1", 5 }, /* data == "HTTP/" */
2167 { (void *)&major, 1 }, /* data == "HTTP/X */
2168 { ".", 1 }, /* data == "HTTP/X." */
2169 { (void *)&minor, 1 }, /* data == "HTTP/X.X" */
2170 { " ", 1 }, /* data == "HTTP/X.X " */
2171 { out_buf, strlen(out_buf) }, /* data = "HTTP/X.X YYY" */
2172 { " ", 1 }, /* data = "HTTP/X.X YYY " */
2173 { (void *)status_str, strlen(status_str) }, /* data = "HTTP/X.X YYY ZZZ" */
2174 { "\r\n", 2 }, /* data = "HTTP/X.X YYY ZZZ\r\n" */
2175 };
2176
2177 htp__evbuffer_add_iovec_(buf, iov, 9);
2178 }
2179
2180 evhtp_headers_for_each(request->headers_out, htp__create_headers_, buf);
2181 evbuffer_add(buf, "\r\n", 2);
2182
2183 if (evbuffer_get_length(request->buffer_out)) {
2184 evbuffer_add_buffer(buf, request->buffer_out);
2185 }
2186
2187 return buf;
2188} /* htp__create_reply_ */
2189
2193static htparse_hooks request_psets = {
2194 .on_msg_begin = htp__request_parse_start_,
2195 .method = NULL,
2196 .scheme = NULL,
2201 .uri = NULL,
2202 .on_hdrs_begin = htp__request_parse_headers_start_,
2205 .hostname = htp__request_parse_hostname_,
2206 .on_hdrs_complete = htp__request_parse_headers_,
2207 .on_new_chunk = htp__request_parse_chunk_new_,
2208 .on_chunk_complete = htp__request_parse_chunk_fini_,
2209 .on_chunks_complete = htp__request_parse_chunks_fini_,
2211 .on_msg_complete = htp__request_parse_fini_
2212};
2213
2214static void
2215htp__connection_readcb_(struct bufferevent * bev, void * arg)
2216{
2217 evhtp_connection_t * c = arg;
2218 void * buf;
2219 size_t nread;
2220 size_t avail;
2221
2222 if (evhtp_unlikely(bev == NULL)) {
2223 return;
2224 }
2225
2226 avail = HTP_LEN_INPUT(bev);
2227
2228 if (evhtp_unlikely(avail == 0)) {
2229 return;
2230 }
2231
2232 if (c->flags & EVHTP_CONN_FLAG_PAUSED) {
2233 log_debug("connection is paused, returning");
2234 return;
2235 }
2236
2237 if (c->request) {
2238 c->cr_status = EVHTP_RES_OK;
2239 }
2240
2241 buf = evbuffer_pullup(bufferevent_get_input(bev), avail);
2242
2243 evhtp_assert(buf != NULL);
2244 evhtp_assert(c->parser != NULL);
2245
2246 nread = htparser_run(c->parser, &request_psets, (const char *)buf, avail);
2247
2248 log_debug("nread = %zu", nread);
2249
2250 if (!(c->flags & EVHTP_CONN_FLAG_OWNER)) {
2251 /*
2252 * someone has taken the ownership of this connection, we still need to
2253 * drain the input buffer that had been read up to this point.
2254 */
2255
2256 log_debug("EVHTP_CONN_FLAG_OWNER set, removing contexts");
2257
2258 evbuffer_drain(bufferevent_get_input(bev), nread);
2260
2261 return;
2262 }
2263
2264 if (c->request) {
2265 switch (c->cr_status) {
2268
2270 return;
2271 default:
2272 break;
2273 }
2274 }
2275
2276 evbuffer_drain(bufferevent_get_input(bev), nread);
2277
2278 if (c->request && c->cr_status == EVHTP_RES_PAUSE) {
2279 log_debug("Pausing connection");
2280
2281 evhtp_request_pause(c->request);
2282 } else if (htparser_get_error(c->parser) != htparse_error_none) {
2283 log_debug("error %d, freeing connection",
2284 htparser_get_error(c->parser));
2285
2287 } else if (nread < avail) {
2288 /* we still have more data to read (piped request probably) */
2289 log_debug("Reading more data via resumption");
2290
2292 }
2293} /* htp__connection_readcb_ */
2294
2295static void
2296htp__connection_writecb_(struct bufferevent * bev, void * arg)
2297{
2298 evhtp_connection_t * conn;
2299 uint64_t keepalive_max;
2300 const char * errstr;
2301
2302 evhtp_assert(bev != NULL);
2303
2304 log_debug("writecb");
2305
2306 if (evhtp_unlikely(arg == NULL)) {
2307 log_error("No data associated with the bufferevent %p", bev);
2308
2309 evhtp_safe_free(bev, bufferevent_free);
2310 return;
2311 }
2312
2313 errstr = NULL;
2314 conn = (evhtp_connection_t *)arg;
2315
2316 do {
2317 if (evhtp_unlikely(conn->request == NULL)) {
2318 errstr = "no request associated with connection";
2319 break;
2320 }
2321
2322 if (evhtp_unlikely(conn->parser == NULL)) {
2323 errstr = "no parser registered with connection";
2324 break;
2325 }
2326
2327 if (evhtp_likely(conn->type == evhtp_type_server)) {
2328 if (evhtp_unlikely(conn->htp == NULL)) {
2329 errstr = "no context associated with the server-connection";
2330 break;
2331 }
2332
2333 keepalive_max = conn->htp->max_keepalive_requests;
2334 } else {
2335 keepalive_max = 0;
2336 }
2337 } while (0);
2338
2339 if (evhtp_unlikely(errstr != NULL)) {
2340 log_error("shutting down connection: %s", errstr);
2341
2343 return;
2344 }
2345
2346 /* connection is in a paused state, no further processing yet */
2347 if (conn->flags & EVHTP_CONN_FLAG_PAUSED) {
2348 log_debug("is paused");
2349 return;
2350 }
2351
2352 /* run user-hook for on_write callback before further analysis */
2354
2355 if (conn->flags & EVHTP_CONN_FLAG_WAITING) {
2356 log_debug("Disabling WAIT flag");
2357
2359
2360 if (HTP_IS_READING(bev) == false) {
2361 log_debug("enabling EV_READ");
2362
2363 bufferevent_enable(bev, EV_READ);
2364 }
2365
2366 if (HTP_LEN_INPUT(bev)) {
2367 log_debug("have input data, will travel");
2368
2369 htp__connection_readcb_(bev, arg);
2370 return;
2371 }
2372 }
2373
2374 /* if the connection is not finished, OR there is data ready to output
2375 * (can only happen if a user-defined connection_write hook added data
2376 * manually, since this is called only when all data has been flushed)
2377 * just return and wait.
2378 */
2379 if (!(conn->cr_flags & EVHTP_REQ_FLAG_FINISHED) || HTP_LEN_OUTPUT(bev)) {
2380 log_debug("not finished");
2381 return;
2382 }
2383
2384 /*
2385 * if there is a set maximum number of keepalive requests configured, check
2386 * to make sure we are not over it. If we have gone over the max we set the
2387 * keepalive bit to 0, thus closing the connection.
2388 */
2389 if (keepalive_max > 0) {
2390 if (++conn->num_requests >= keepalive_max) {
2391 HTP_FLAG_OFF(conn->request, EVHTP_REQ_FLAG_KEEPALIVE);
2392 }
2393 }
2394
2395 if (conn->cr_flags & EVHTP_REQ_FLAG_KEEPALIVE) {
2396 htp_type type;
2397
2398 log_debug("keep-alive on");
2399 /* free up the current request, set it to NULL, making
2400 * way for the next request.
2401 */
2402 evhtp_safe_free(conn->request, htp__request_free_);
2403
2404 /* since the request is keep-alive, assure that the connection
2405 * is aware of the same.
2406 */
2408
2409 conn->body_bytes_read = 0;
2410
2411 if (conn->type == evhtp_type_server) {
2412 if (conn->htp->parent != NULL
2413 && !(conn->flags & EVHTP_CONN_FLAG_VHOST_VIA_SNI)) {
2414 /* this request was served by a virtual host evhtp_t structure
2415 * which was *NOT* found via SSL SNI lookup. In this case we want to
2416 * reset our connections evhtp_t structure back to the original so
2417 * that subsequent requests can have a different 'Host' header.
2418 */
2419 conn->htp = conn->htp->parent;
2420 }
2421 }
2422
2423 switch (conn->type) {
2424 case evhtp_type_client:
2425 type = htp_type_response;
2426 break;
2427 case evhtp_type_server:
2428 type = htp_type_request;
2429 break;
2430 default:
2431 log_error("Unknown connection type");
2432
2434 return;
2435 }
2436
2437 htparser_init(conn->parser, type);
2438 htparser_set_userdata(conn->parser, conn);
2439
2440 return;
2441 } else {
2442 log_debug("goodbye connection");
2444
2445 return;
2446 }
2447
2448 return;
2449} /* htp__connection_writecb_ */
2450
2451static void
2452htp__connection_eventcb_(struct bufferevent * bev, short events, void * arg)
2453{
2454 evhtp_connection_t * c = arg;
2455
2456 log_debug("%p %p eventcb %s%s%s%s", arg, (void *)bev,
2457 events & BEV_EVENT_CONNECTED ? "connected" : "",
2458 events & BEV_EVENT_ERROR ? "error" : "",
2459 events & BEV_EVENT_TIMEOUT ? "timeout" : "",
2460 events & BEV_EVENT_EOF ? "eof" : "");
2461
2462 if (c->hooks && c->hooks->on_event) {
2463 (c->hooks->on_event)(c, events, c->hooks->on_event_arg);
2464 }
2465
2466 if ((events & BEV_EVENT_CONNECTED)) {
2467 log_debug("CONNECTED");
2468
2469 if (evhtp_likely(c->type == evhtp_type_client)) {
2471
2472 bufferevent_setcb(bev,
2476 }
2477
2478 return;
2479 }
2480
2481#ifndef EVHTP_DISABLE_SSL
2482 if (c->ssl && !(events & BEV_EVENT_EOF)) {
2483#ifdef EVHTP_DEBUG
2484 unsigned long sslerr;
2485
2486 while ((sslerr = bufferevent_get_openssl_error(bev))) {
2487 log_error("SSL ERROR %lu:%i:%s:%i:%s:%i:%s",
2488 sslerr,
2489 ERR_GET_REASON(sslerr),
2490 ERR_reason_error_string(sslerr),
2491 ERR_GET_LIB(sslerr),
2492 ERR_lib_error_string(sslerr),
2493 ERR_GET_FUNC(sslerr),
2494 ERR_func_error_string(sslerr));
2495 }
2496#endif
2497
2498 /* XXX need to do better error handling for SSL specific errors */
2500
2501 if (c->request) {
2502 HTP_FLAG_ON(c->request, EVHTP_REQ_FLAG_ERROR);
2503 }
2504 }
2505
2506#endif
2507
2508 if (events == (BEV_EVENT_EOF | BEV_EVENT_READING)) {
2509 log_debug("EOF | READING");
2510
2511 if (errno == EAGAIN) {
2512 /* libevent will sometimes recv again when it's not actually ready,
2513 * this results in a 0 return value, and errno will be set to EAGAIN
2514 * (try again). This does not mean there is a hard socket error, but
2515 * simply needs to be read again.
2516 *
2517 * but libevent will disable the read side of the bufferevent
2518 * anyway, so we must re-enable it.
2519 */
2520 log_debug("errno EAGAIN");
2521
2522 if (HTP_IS_READING(bev) == false) {
2523 bufferevent_enable(bev, EV_READ);
2524 }
2525
2526 errno = 0;
2527
2528 return;
2529 }
2530 }
2531
2532 /* set the error mask */
2534
2535 /* unset connected flag */
2537
2538 htp__hook_connection_error_(c, events);
2539
2540 if (c->flags & EVHTP_CONN_FLAG_PAUSED) {
2541 /* we are currently paused, so we don't want to free just yet, let's
2542 * wait till the next loop.
2543 */
2545 } else {
2547 }
2548} /* htp__connection_eventcb_ */
2549
2550static void
2551htp__connection_resumecb_(int fd, short events, void * arg)
2552{
2553 evhtp_connection_t * c = arg;
2554
2555 log_debug("resumecb");
2556
2557 /* unset the pause flag */
2559
2560 if (c->request) {
2561 log_debug("cr status = OK %d", c->cr_status);
2562 c->cr_status = EVHTP_RES_OK;
2563 }
2564
2565 if (c->flags & EVHTP_CONN_FLAG_FREE_CONN) {
2566 log_debug("flags == FREE_CONN");
2568
2569 return;
2570 }
2571
2572 /* XXX this is a hack to show a potential fix for issues/86, the main indea
2573 * is that you call resume AFTER you have sent the reply (not BEFORE).
2574 *
2575 * When it has been decided this is a proper fix, the pause bit should be
2576 * changed to a state-type flag.
2577 */
2578
2579 if (HTP_LEN_OUTPUT(c->bev)) {
2580 log_debug("SET WAITING");
2581
2583
2584 if (HTP_IS_WRITING(c->bev) == false) {
2585 log_debug("ENABLING EV_WRITE");
2586
2587 bufferevent_enable(c->bev, EV_WRITE);
2588 }
2589 } else {
2590 log_debug("SET READING");
2591
2592 if (HTP_IS_READING(c->bev) == false) {
2593 log_debug("ENABLING EV_READ");
2594
2595 bufferevent_enable(c->bev, EV_READ | EV_WRITE);
2596 }
2597
2598 if (HTP_LEN_INPUT(c->bev)) {
2599 log_debug("calling readcb directly");
2600 htp__connection_readcb_(c->bev, c);
2601 }
2602 }
2603} /* htp__connection_resumecb_ */
2604
2605static int
2606htp__run_pre_accept_(evhtp_t * htp, evhtp_connection_t * conn)
2607{
2608 void * args;
2609 evhtp_res res;
2610
2611 if (evhtp_likely(htp->defaults.pre_accept == NULL)) {
2612 return 0;
2613 }
2614
2615 args = htp->defaults.pre_accept_cbarg;
2616 res = htp->defaults.pre_accept(conn, args);
2617
2618 if (res != EVHTP_RES_OK) {
2619 return -1;
2620 }
2621
2622 return 0;
2623}
2624
2625static int
2626htp__connection_accept_(struct event_base * evbase, evhtp_connection_t * connection)
2627{
2628 struct timeval * c_recv_timeo;
2629 struct timeval * c_send_timeo;
2630
2631 if (htp__run_pre_accept_(connection->htp, connection) < 0) {
2632 evutil_closesocket(connection->sock);
2633
2634 return -1;
2635 }
2636
2637#ifndef EVHTP_DISABLE_SSL
2638 if (connection->htp->ssl_ctx != NULL) {
2639 connection->ssl = SSL_new(connection->htp->ssl_ctx);
2640 connection->bev = bufferevent_openssl_socket_new(evbase,
2641 connection->sock,
2642 connection->ssl,
2643 BUFFEREVENT_SSL_ACCEPTING,
2644 connection->htp->bev_flags);
2645 SSL_set_app_data(connection->ssl, connection);
2646 goto end;
2647 }
2648
2649#endif
2650
2651 connection->bev = bufferevent_socket_new(evbase,
2652 connection->sock,
2653 connection->htp->bev_flags);
2654
2655 log_debug("enter sock=%d\n", connection->sock);
2656
2657#ifndef EVHTP_DISABLE_SSL
2658end:
2659#endif
2660
2661 if (connection->recv_timeo.tv_sec || connection->recv_timeo.tv_usec) {
2662 c_recv_timeo = &connection->recv_timeo;
2663 } else if (connection->htp->recv_timeo.tv_sec ||
2664 connection->htp->recv_timeo.tv_usec) {
2665 c_recv_timeo = &connection->htp->recv_timeo;
2666 } else {
2667 c_recv_timeo = NULL;
2668 }
2669
2670 if (connection->send_timeo.tv_sec || connection->send_timeo.tv_usec) {
2671 c_send_timeo = &connection->send_timeo;
2672 } else if (connection->htp->send_timeo.tv_sec ||
2673 connection->htp->send_timeo.tv_usec) {
2674 c_send_timeo = &connection->htp->send_timeo;
2675 } else {
2676 c_send_timeo = NULL;
2677 }
2678
2679 evhtp_connection_set_timeouts(connection, c_recv_timeo, c_send_timeo);
2680
2681 connection->resume_ev = event_new(evbase, -1, EV_READ | EV_PERSIST,
2682 htp__connection_resumecb_, connection);
2683 event_add(connection->resume_ev, NULL);
2684
2685 bufferevent_setcb(connection->bev,
2688 htp__connection_eventcb_, connection);
2689
2690 bufferevent_enable(connection->bev, EV_READ);
2691
2692 return 0;
2693} /* htp__connection_accept_ */
2694
2695static void
2696htp__default_request_cb_(evhtp_request_t * request, void * arg)
2697{
2698 evhtp_headers_add_header(request->headers_out,
2699 evhtp_header_new("Content-Length", "0", 0, 0));
2700 evhtp_send_reply(request, EVHTP_RES_NOTFOUND);
2701}
2702
2703static evhtp_connection_t *
2704htp__connection_new_(evhtp_t * htp, evutil_socket_t sock, evhtp_type type)
2705{
2706 evhtp_connection_t * connection;
2707 htp_type ptype;
2708
2709 switch (type) {
2710 case evhtp_type_client:
2711 ptype = htp_type_response;
2712 break;
2713 case evhtp_type_server:
2714 ptype = htp_type_request;
2715 break;
2716 default:
2717 return NULL;
2718 }
2719
2720 connection = htp__calloc_(sizeof(*connection), 1);
2721
2722 if (evhtp_unlikely(connection == NULL)) {
2723 return NULL;
2724 }
2725
2726 connection->scratch_buf = evbuffer_new();
2727
2728 if (evhtp_unlikely(connection->scratch_buf == NULL)) {
2729 evhtp_safe_free(connection->scratch_buf, htp__free_);
2730
2731 return NULL;
2732 }
2733
2734 if (htp != NULL) {
2735 connection->max_body_size = htp->max_body_size;
2736 }
2737
2738 connection->flags = EVHTP_CONN_FLAG_OWNER;
2739 connection->sock = sock;
2740 connection->htp = htp;
2741 connection->type = type;
2742 connection->parser = htparser_new();
2743
2744 if (evhtp_unlikely(connection->parser == NULL)) {
2746
2747 return NULL;
2748 }
2749
2750 htparser_init(connection->parser, ptype);
2751 htparser_set_userdata(connection->parser, connection);
2752
2753 return connection;
2754} /* htp__connection_new_ */
2755
2756#ifdef LIBEVENT_HAS_SHUTDOWN
2757#ifndef EVHTP_DISABLE_SSL
2758static void
2759htp__shutdown_eventcb_(struct bufferevent * bev, short events, void * arg)
2760{
2761}
2762
2763#endif
2764#endif
2765
2766static int
2767htp__run_post_accept_(evhtp_t * htp, evhtp_connection_t * connection)
2768{
2769 void * args;
2770 evhtp_res res;
2771
2772 if (evhtp_likely(htp->defaults.post_accept == NULL)) {
2773 return 0;
2774 }
2775
2776 args = htp->defaults.post_accept_cbarg;
2777 res = htp->defaults.post_accept(connection, args);
2778
2779 if (res != EVHTP_RES_OK) {
2780 return -1;
2781 }
2782
2783 return 0;
2784}
2785
2786#ifndef EVHTP_DISABLE_EVTHR
2787static void
2788htp__run_in_thread_(evthr_t * thr, void * arg, void * shared)
2789{
2790 evhtp_t * htp = shared;
2791 evhtp_connection_t * connection = arg;
2792
2793 connection->evbase = evthr_get_base(thr);
2794 connection->thread = thr;
2795
2796 if (htp__connection_accept_(connection->evbase, connection) < 0) {
2798
2799 return;
2800 }
2801
2802 if (htp__run_post_accept_(htp, connection) < 0) {
2804
2805 return;
2806 }
2807}
2808
2809#endif
2810
2811static void
2812htp__accept_cb_(struct evconnlistener * serv, int fd, struct sockaddr * s, int sl, void * arg)
2813{
2814 evhtp_t * htp = arg;
2815 evhtp_connection_t * connection;
2816
2817 evhtp_assert(htp && serv && serv && s);
2818
2819 connection = htp__connection_new_(htp, fd, evhtp_type_server);
2820
2821 if (evhtp_unlikely(connection == NULL)) {
2822 return;
2823 }
2824
2825 log_debug("fd = %d, conn = %p", fd, connection);
2826
2827 connection->saddr = htp__malloc_(sl);
2828
2829 if (evhtp_unlikely(connection->saddr == NULL)) {
2830 /* should probably start doing error callbacks */
2832 return;
2833 }
2834
2835
2836 memcpy(connection->saddr, s, sl);
2837
2838#ifndef EVHTP_DISABLE_EVTHR
2839 if (htp->thr_pool != NULL) {
2840 if (evthr_pool_defer(htp->thr_pool,
2841 htp__run_in_thread_, connection) != EVTHR_RES_OK) {
2842 evutil_closesocket(connection->sock);
2844
2845 return;
2846 }
2847
2848 return;
2849 }
2850
2851#endif
2852 connection->evbase = htp->evbase;
2853
2854 if (htp__connection_accept_(htp->evbase, connection) == -1) {
2856 return;
2857 }
2858
2859 if (htp__run_post_accept_(htp, connection) == -1) {
2861 return;
2862 }
2863} /* htp__accept_cb_ */
2864
2865#ifndef EVHTP_DISABLE_SSL
2866#ifndef EVHTP_DISABLE_EVTHR
2867
2868#ifndef WIN32
2869#define _HTP_tid (unsigned long)pthread_self()
2870#else
2871#define _HTP_tid pthread_self().p
2872#endif
2873
2874#if OPENSSL_VERSION_NUMBER < 0x10000000L
2875static unsigned long
2877{
2878 return _HTP_tid;
2879}
2880
2881#else
2882
2883static void
2884htp__ssl_get_thread_id_(CRYPTO_THREADID * id)
2885{
2886 CRYPTO_THREADID_set_numeric(id, _HTP_tid);
2887}
2888
2889#endif
2890
2891static void
2892htp__ssl_thread_lock_(int mode, int type, const char * file, int line)
2893{
2894 if (type < ssl_num_locks) {
2895 if (mode & CRYPTO_LOCK) {
2896 pthread_mutex_lock(&(ssl_locks[type]));
2897 } else {
2898 pthread_mutex_unlock(&(ssl_locks[type]));
2899 }
2900 }
2901}
2902
2903#endif
2904static void
2906{
2907 evhtp_t * htp;
2908 evhtp_ssl_cfg_t * cfg;
2909 evhtp_ssl_data_t * sid;
2910 unsigned int slen;
2911
2912 htp = (evhtp_t *)SSL_CTX_get_app_data(ctx);
2913 cfg = htp->ssl_cfg;
2914 sid = (evhtp_ssl_data_t *)SSL_SESSION_get_id(sess, &slen);
2915
2916 if (cfg->scache_del) {
2917 (cfg->scache_del)(htp, sid, slen);
2918 }
2919}
2920
2921static int
2923{
2924 evhtp_connection_t * connection;
2925 evhtp_ssl_cfg_t * cfg;
2926 evhtp_ssl_data_t * sid;
2927 unsigned int slen;
2928
2929 connection = (evhtp_connection_t *)SSL_get_app_data(ssl);
2930 if (connection->htp == NULL) {
2931 return 0; /* We cannot get the ssl_cfg */
2932 }
2933
2934 cfg = connection->htp->ssl_cfg;
2935 sid = (evhtp_ssl_data_t *)SSL_SESSION_get_id(sess, &slen);
2936
2937 SSL_set_timeout(sess, cfg->scache_timeout);
2938
2939 if (cfg->scache_add) {
2940 return (cfg->scache_add)(connection, sid, slen, sess);
2941 }
2942
2943 return 0;
2944}
2945
2946static evhtp_ssl_sess_t *
2947htp__ssl_get_scache_ent_(evhtp_ssl_t * ssl, evhtp_ssl_data_t * sid, int sid_len, int * copy)
2948{
2949 evhtp_connection_t * connection;
2950 evhtp_ssl_cfg_t * cfg;
2951 evhtp_ssl_sess_t * sess;
2952
2953 connection = (evhtp_connection_t * )SSL_get_app_data(ssl);
2954
2955 if (connection->htp == NULL) {
2956 return NULL; /* We have no way of getting ssl_cfg */
2957 }
2958
2959 cfg = connection->htp->ssl_cfg;
2960 sess = NULL;
2961
2962 if (cfg->scache_get) {
2963 sess = (cfg->scache_get)(connection, sid, sid_len);
2964 }
2965
2966 *copy = 0;
2967
2968 return sess;
2969}
2970
2971static int
2972htp__ssl_servername_(evhtp_ssl_t * ssl, int * unused, void * arg)
2973{
2974 const char * sname;
2975 evhtp_connection_t * connection;
2976 evhtp_t * evhtp;
2977 evhtp_t * evhtp_vhost;
2978
2979 if (evhtp_unlikely(ssl == NULL)) {
2980 return SSL_TLSEXT_ERR_NOACK;
2981 }
2982
2983 if (!(sname = SSL_get_servername(ssl, TLSEXT_NAMETYPE_host_name))) {
2984 return SSL_TLSEXT_ERR_NOACK;
2985 }
2986
2987 if (!(connection = SSL_get_app_data(ssl))) {
2988 return SSL_TLSEXT_ERR_NOACK;
2989 }
2990
2991 if (!(evhtp = connection->htp)) {
2992 return SSL_TLSEXT_ERR_NOACK;
2993 }
2994
2995 if ((evhtp_vhost = htp__request_find_vhost_(evhtp, sname))) {
2996 SSL_CTX * ctx = SSL_get_SSL_CTX(ssl);
2997
2998 connection->htp = evhtp_vhost;
2999
3001
3002 SSL_set_SSL_CTX(ssl, evhtp_vhost->ssl_ctx);
3003 SSL_set_options(ssl, SSL_CTX_get_options(ctx));
3004
3005 if ((SSL_get_verify_mode(ssl) == SSL_VERIFY_NONE) ||
3006 (SSL_num_renegotiations(ssl) == 0)) {
3007 SSL_set_verify(ssl, SSL_CTX_get_verify_mode(ctx),
3008 SSL_CTX_get_verify_callback(ctx));
3009 }
3010
3011 return SSL_TLSEXT_ERR_OK;
3012 }
3013
3014 return SSL_TLSEXT_ERR_NOACK;
3015} /* htp__ssl_servername_ */
3016
3017#endif
3018
3019/*
3020 * PUBLIC FUNCTIONS
3021 */
3022
3023htp_method
3024evhtp_request_get_method(evhtp_request_t * r)
3025{
3026 evhtp_assert(r != NULL);
3027 evhtp_assert(r->conn != NULL);
3028 evhtp_assert(r->conn->parser != NULL);
3029
3030 return htparser_get_method(r->conn->parser);
3031}
3032
3033void
3034evhtp_connection_pause(evhtp_connection_t * c)
3035{
3036 evhtp_assert(c != NULL);
3037
3038 if (c->flags & EVHTP_CONN_FLAG_PAUSED) {
3039 log_debug("connection is already paused");
3040 return;
3041 }
3042
3043 log_debug("setting PAUSED flag");
3044
3046
3047 if (HTP_IS_READING(c->bev) == true) {
3048 log_debug("disabling EV_READ");
3049 bufferevent_disable(c->bev, EV_READ);
3050 }
3051
3052 return;
3053}
3054
3055void
3056evhtp_connection_resume(evhtp_connection_t * c)
3057{
3058 evhtp_assert(c != NULL);
3059
3060 if (!(c->flags & EVHTP_CONN_FLAG_PAUSED)) {
3061 log_error("ODDITY, resuming when not paused?!?");
3062 return;
3063 }
3064
3066
3067 log_debug("resume");
3068
3069 event_active(c->resume_ev, EV_WRITE, 1);
3070
3071 return;
3072}
3073
3074void
3075evhtp_request_pause(evhtp_request_t * request)
3076{
3077 evhtp_assert(request != NULL);
3078
3079 request->status = EVHTP_RES_PAUSE;
3080 evhtp_connection_pause(request->conn);
3081}
3082
3083void
3084evhtp_request_resume(evhtp_request_t * request)
3085{
3086 evhtp_assert(request != NULL);
3087
3088 evhtp_connection_resume(request->conn);
3089}
3090
3091evhtp_header_t *
3092evhtp_header_key_add(evhtp_headers_t * headers, const char * key, char key_alloc)
3093{
3094 evhtp_header_t * header;
3095
3096 if (!(header = evhtp_header_new(key, NULL, key_alloc, 0))) {
3097 return NULL;
3098 }
3099
3100 evhtp_headers_add_header(headers, header);
3101
3102 return header;
3103}
3104
3105evhtp_header_t *
3106evhtp_header_val_add(evhtp_headers_t * headers, const char * val, char val_alloc)
3107{
3108 evhtp_header_t * header;
3109
3110 if (evhtp_unlikely(headers == NULL || val == NULL)) {
3111 return NULL;
3112 }
3113
3114 if (!(header = TAILQ_LAST(headers, evhtp_kvs))) {
3115 return NULL;
3116 }
3117
3118 if (header->val != NULL) {
3119 return NULL;
3120 }
3121
3122 header->vlen = strlen(val);
3123
3124 if (val_alloc == 1) {
3125 header->val = htp__malloc_(header->vlen + 1);
3126 evhtp_alloc_assert(header->val);
3127
3128 header->val[header->vlen] = '\0';
3129 memcpy(header->val, val, header->vlen);
3130 } else {
3131 header->val = (char *)val;
3132 }
3133
3134 header->v_heaped = val_alloc;
3135
3136 return header;
3137}
3138
3141{
3142 evhtp_kvs_t * kvs;
3143
3144 kvs = htp__malloc_(sizeof(*kvs));
3145
3146 if (evhtp_unlikely(kvs == NULL)) {
3147 return NULL;
3148 }
3149
3150 TAILQ_INIT(kvs);
3151
3152 return kvs;
3153}
3154
3155evhtp_kv_t *
3156evhtp_kv_new(const char * key, const char * val,
3157 char key_alloc, char val_alloc)
3158{
3159 evhtp_kv_t * kv;
3160
3161 kv = htp__malloc_(sizeof(*kv));
3162
3163 if (evhtp_unlikely(kv == NULL)) {
3164 return NULL;
3165 }
3166
3167 kv->k_heaped = key_alloc;
3168 kv->v_heaped = val_alloc;
3169 kv->klen = 0;
3170 kv->vlen = 0;
3171 kv->key = NULL;
3172 kv->val = NULL;
3173
3174 if (key != NULL) {
3175 kv->klen = strlen(key);
3176
3177 if (key_alloc == 1) {
3178 char * s;
3179
3180 if (!(s = htp__malloc_(kv->klen + 1))) {
3182
3183 return NULL;
3184 }
3185
3186 memcpy(s, key, kv->klen);
3187
3188 s[kv->klen] = '\0';
3189 kv->key = s;
3190 } else {
3191 kv->key = (char *)key;
3192 }
3193 }
3194
3195 if (val != NULL) {
3196 kv->vlen = strlen(val);
3197
3198 if (val_alloc == 1) {
3199 char * s = htp__malloc_(kv->vlen + 1);
3200
3201 if (evhtp_unlikely(s == NULL)) {
3203
3204 return NULL;
3205 }
3206
3207 s[kv->vlen] = '\0';
3208 memcpy(s, val, kv->vlen);
3209 kv->val = s;
3210 } else {
3211 kv->val = (char *)val;
3212 }
3213 }
3214
3215 return kv;
3216} /* evhtp_kv_new */
3217
3218void
3219evhtp_kv_free(evhtp_kv_t * kv)
3220{
3221 if (evhtp_unlikely(kv == NULL)) {
3222 return;
3223 }
3224
3225 if (kv->k_heaped == 1) {
3226 evhtp_safe_free(kv->key, htp__free_);
3227 }
3228
3229 if (kv->v_heaped == 1) {
3230 evhtp_safe_free(kv->val, htp__free_);
3231 }
3232
3234}
3235
3236void
3237evhtp_kv_rm_and_free(evhtp_kvs_t * kvs, evhtp_kv_t * kv)
3238{
3239 if (evhtp_unlikely(kvs == NULL || kv == NULL)) {
3240 return;
3241 }
3242
3243 TAILQ_REMOVE(kvs, kv, next);
3244
3246}
3247
3248void
3250{
3251 evhtp_kv_t * kv;
3252 evhtp_kv_t * save;
3253
3254 if (evhtp_unlikely(kvs == NULL)) {
3255 return;
3256 }
3257
3258 kv = NULL;
3259 save = NULL;
3260
3261 for (kv = TAILQ_FIRST(kvs); kv != NULL; kv = save) {
3262 save = TAILQ_NEXT(kv, next);
3263
3264 TAILQ_REMOVE(kvs, kv, next);
3265
3267 }
3268
3270}
3271
3272int
3274{
3275 evhtp_kv_t * kv;
3276
3277 if (kvs == NULL || cb == NULL) {
3278 return -1;
3279 }
3280
3281 TAILQ_FOREACH(kv, kvs, next) {
3282 int res;
3283
3284 if ((res = cb(kv, arg))) {
3285 return res;
3286 }
3287 }
3288
3289 return 0;
3290}
3291
3292const char *
3293evhtp_kv_find(evhtp_kvs_t * kvs, const char * key)
3294{
3295 evhtp_kv_t * kv;
3296
3297 if (evhtp_unlikely(kvs == NULL || key == NULL)) {
3298 return NULL;
3299 }
3300
3301 TAILQ_FOREACH(kv, kvs, next) {
3302 if (strcasecmp(kv->key, key) == 0) {
3303 return kv->val;
3304 }
3305 }
3306
3307 return NULL;
3308}
3309
3310const char *
3311evhtp_header_find(evhtp_headers_t * headers, const char * key)
3312{
3313 return evhtp_kv_find(headers, key);
3314}
3315
3316void
3317evhtp_headers_add_header(evhtp_headers_t * headers, evhtp_header_t * header)
3318{
3319 return evhtp_kvs_add_kv(headers, header);
3320}
3321
3322evhtp_header_t *
3323evhtp_header_new(const char * key, const char * val, char kalloc, char valloc)
3324{
3325 return evhtp_kv_new(key, val, kalloc, valloc);
3326}
3327
3328evhtp_kv_t *
3329evhtp_kvs_find_kv(evhtp_kvs_t * kvs, const char * key)
3330{
3331 evhtp_kv_t * kv;
3332
3333 if (evhtp_unlikely(kvs == NULL || key == NULL)) {
3334 return NULL;
3335 }
3336
3337 TAILQ_FOREACH(kv, kvs, next) {
3338 if (strcasecmp(kv->key, key) == 0) {
3339 return kv;
3340 }
3341 }
3342
3343 return NULL;
3344}
3345
3346void
3347evhtp_kvs_add_kv(evhtp_kvs_t * kvs, evhtp_kv_t * kv)
3348{
3349 if (evhtp_unlikely(kvs == NULL || kv == NULL)) {
3350 return;
3351 }
3352
3353 TAILQ_INSERT_TAIL(kvs, kv, next);
3354}
3355
3356void
3358{
3359 evhtp_kv_t * kv;
3360
3361 if (dst == NULL || src == NULL) {
3362 return;
3363 }
3364
3365 TAILQ_FOREACH(kv, src, next) {
3366 evhtp_kvs_add_kv(dst, evhtp_kv_new(kv->key,
3367 kv->val,
3368 kv->k_heaped,
3369 kv->v_heaped));
3370 }
3371}
3372
3384
3385static inline int
3387{
3388 switch (ch) {
3389 case 'a': case 'A':
3390 case 'b': case 'B':
3391 case 'c': case 'C':
3392 case 'd': case 'D':
3393 case 'e': case 'E':
3394 case 'f': case 'F':
3395 case '0': case '1':
3396 case '2': case '3':
3397 case '4': case '5':
3398 case '6': case '7':
3399 case '8': case '9':
3400 return 1;
3401 default:
3402 return 0;
3403 } /* switch */
3404}
3405
3411
3412int
3413evhtp_unescape_string(unsigned char ** out, unsigned char * str, size_t str_len)
3414{
3415 unsigned char * optr;
3416 unsigned char * sptr;
3417 unsigned char d;
3418 unsigned char ch;
3419 unsigned char c;
3420 size_t i;
3421 enum unscape_state state;
3422
3423 state = unscape_state_start;
3424 optr = *out;
3425 sptr = str;
3426 d = 0;
3427
3428 for (i = 0; i < str_len; i++) {
3429 ch = *sptr++;
3430
3431 switch (state) {
3433 if (ch == '%') {
3434 state = unscape_state_hex1;
3435 break;
3436 }
3437
3438 *optr++ = ch;
3439
3440 break;
3441 case unscape_state_hex1:
3442 if (ch >= '0' && ch <= '9') {
3443 d = (unsigned char)(ch - '0');
3444 state = unscape_state_hex2;
3445 break;
3446 }
3447
3448 c = (unsigned char)(ch | 0x20);
3449
3450 if (c >= 'a' && c <= 'f') {
3451 d = (unsigned char)(c - 'a' + 10);
3452 state = unscape_state_hex2;
3453 break;
3454 }
3455
3456 state = unscape_state_start;
3457 *optr++ = ch;
3458 break;
3459 case unscape_state_hex2:
3460 state = unscape_state_start;
3461
3462 if (ch >= '0' && ch <= '9') {
3463 ch = (unsigned char)((d << 4) + ch - '0');
3464
3465 *optr++ = ch;
3466 break;
3467 }
3468
3469 c = (unsigned char)(ch | 0x20);
3470
3471 if (c >= 'a' && c <= 'f') {
3472 ch = (unsigned char)((d << 4) + c - 'a' + 10);
3473 *optr++ = ch;
3474 break;
3475 }
3476
3477 break;
3478 } /* switch */
3479 }
3480
3481 *out = optr;
3482 return 0;
3483} /* evhtp_unescape_string */
3484
3486evhtp_parse_query_wflags(const char * query, const size_t len, const int flags)
3487{
3488 evhtp_query_t * query_args;
3489 query_parser_state state;
3490 size_t key_idx;
3491 size_t val_idx;
3492 unsigned char ch;
3493 size_t i;
3494
3495 if (len > (SIZE_MAX - (len + 2))) {
3496 return NULL;
3497 }
3498
3499 query_args = evhtp_query_new();
3500
3501 state = s_query_start;
3502 key_idx = 0;
3503 val_idx = 0;
3504
3505#ifdef EVHTP_HAS_C99
3506 char key_buf[len + 1];
3507 char val_buf[len + 1];
3508#else
3509 char * key_buf;
3510 char * val_buf;
3511
3512 key_buf = htp__malloc_(len + 1);
3513
3514 if (evhtp_unlikely(key_buf == NULL)) {
3515 evhtp_safe_free(query_args, evhtp_query_free);
3516
3517 return NULL;
3518 }
3519
3520 val_buf = htp__malloc_(len + 1);
3521
3522 if (evhtp_unlikely(val_buf == NULL)) {
3523 evhtp_safe_free(query_args, evhtp_query_free);
3524
3525 return NULL;
3526 }
3527
3528#endif
3529
3530 for (i = 0; i < len; i++) {
3531 ch = query[i];
3532
3533 if (key_idx >= len || val_idx >= len) {
3534 goto error;
3535 }
3536
3537 switch (state) {
3538 case s_query_start:
3539 key_idx = 0;
3540 val_idx = 0;
3541
3542 key_buf[0] = '\0';
3543 val_buf[0] = '\0';
3544
3545 state = s_query_key;
3546 /* Fall through. */
3547 case s_query_key:
3548 switch (ch) {
3549 case '=':
3550 state = s_query_val;
3551 break;
3552 case '%':
3553 key_buf[key_idx++] = ch;
3554 key_buf[key_idx] = '\0';
3555
3556 if (!(flags & EVHTP_PARSE_QUERY_FLAG_IGNORE_HEX)) {
3557 state = s_query_key_hex_1;
3558 }
3559
3560 break;
3561 case ';':
3563 key_buf[key_idx++] = ch;
3564 key_buf[key_idx] = '\0';
3565 break;
3566 }
3567
3568 /* otherwise we fallthrough */
3569 case '&':
3570 /* in this state, we have a NULL value */
3572 goto error;
3573 }
3574
3575 /* insert the key with value of NULL and set the
3576 * state back to parsing s_query_key.
3577 */
3578 evhtp_kvs_add_kv(query_args, evhtp_kv_new(key_buf, NULL, 1, 1));
3579
3580 key_idx = 0;
3581 val_idx = 0;
3582
3583 key_buf[0] = '\0';
3584 val_buf[0] = '\0';
3585
3586 state = s_query_key;
3587 break;
3588 default:
3589 key_buf[key_idx++] = ch;
3590 key_buf[key_idx] = '\0';
3591 break;
3592 } /* switch */
3593 break;
3594 case s_query_key_hex_1:
3595 if (!evhtp_is_hex_query_char(ch)) {
3596 /* not hex, so we treat as a normal key */
3597 if ((key_idx + 2) >= len) {
3598 /* we need to insert \%<ch>, but not enough space */
3599 goto error;
3600 }
3601
3602 key_buf[key_idx - 1] = '%';
3603 key_buf[key_idx++] = ch;
3604 key_buf[key_idx] = '\0';
3605
3606 state = s_query_key;
3607 break;
3608 }
3609
3610 key_buf[key_idx++] = ch;
3611 key_buf[key_idx] = '\0';
3612
3613 state = s_query_key_hex_2;
3614 break;
3615 case s_query_key_hex_2:
3616 if (!evhtp_is_hex_query_char(ch)) {
3617 goto error;
3618 }
3619
3620 key_buf[key_idx++] = ch;
3621 key_buf[key_idx] = '\0';
3622
3623 state = s_query_key;
3624 break;
3625 case s_query_val:
3626 switch (ch) {
3627 case ';':
3629 val_buf[val_idx++] = ch;
3630 val_buf[val_idx] = '\0';
3631 break;
3632 }
3633
3634 case '&':
3635 evhtp_kvs_add_kv(query_args, evhtp_kv_new(key_buf, val_buf, 1, 1));
3636
3637 key_idx = 0;
3638 val_idx = 0;
3639
3640 key_buf[0] = '\0';
3641 val_buf[0] = '\0';
3642 state = s_query_key;
3643
3644 break;
3645 case '%':
3646 val_buf[val_idx++] = ch;
3647 val_buf[val_idx] = '\0';
3648
3649 if (!(flags & EVHTP_PARSE_QUERY_FLAG_IGNORE_HEX)) {
3650 state = s_query_val_hex_1;
3651 }
3652
3653 break;
3654 default:
3655 val_buf[val_idx++] = ch;
3656 val_buf[val_idx] = '\0';
3657
3658 break;
3659 } /* switch */
3660 break;
3661 case s_query_val_hex_1:
3662 if (!evhtp_is_hex_query_char(ch)) {
3663 /* not really a hex val */
3664 if ((val_idx + 2) >= len) {
3665 /* we need to insert \%<ch>, but not enough space */
3666 goto error;
3667 }
3668
3669 if (val_idx == 0) {
3670 goto error;
3671 }
3672
3673 val_buf[val_idx - 1] = '%';
3674 val_buf[val_idx++] = ch;
3675 val_buf[val_idx] = '\0';
3676
3677 state = s_query_val;
3678 break;
3679 }
3680
3681 val_buf[val_idx++] = ch;
3682 val_buf[val_idx] = '\0';
3683
3684 state = s_query_val_hex_2;
3685 break;
3686 case s_query_val_hex_2:
3687 if (!evhtp_is_hex_query_char(ch)) {
3688 goto error;
3689 }
3690
3691 val_buf[val_idx++] = ch;
3692 val_buf[val_idx] = '\0';
3693
3694 state = s_query_val;
3695 break;
3696 default:
3697 /* bad state */
3698 goto error;
3699 } /* switch */
3700 }
3701
3702 if (key_idx) {
3703 do {
3704 if (val_idx) {
3705 evhtp_kvs_add_kv(query_args,
3706 evhtp_kv_new(key_buf, val_buf, 1, 1));
3707 break;
3708 }
3709
3710 if (state >= s_query_val) {
3712 goto error;
3713 }
3714
3715 evhtp_kvs_add_kv(query_args, evhtp_kv_new(key_buf, "", 1, 1));
3716 break;
3717 }
3718
3720 goto error;
3721 }
3722
3723 evhtp_kvs_add_kv(query_args, evhtp_kv_new(key_buf, NULL, 1, 0));
3724 } while (0);
3725 }
3726
3727#ifndef EVHTP_HAS_C99
3728 evhtp_safe_free(key_buf, htp__free_);
3729 evhtp_safe_free(val_buf, htp__free_);
3730#endif
3731
3732 return query_args;
3733error:
3734#ifndef EVHTP_HAS_C99
3735 evhtp_safe_free(key_buf, htp__free_);
3736 evhtp_safe_free(val_buf, htp__free_);
3737#endif
3738
3739 evhtp_safe_free(query_args, evhtp_query_free);
3740
3741 return NULL;
3742} /* evhtp_parse_query */
3743
3745evhtp_parse_query(const char * query, size_t len)
3746{
3747 return evhtp_parse_query_wflags(query, len,
3749}
3750
3751void
3752evhtp_send_reply_start(evhtp_request_t * request, evhtp_res code)
3753{
3754 evhtp_connection_t * c;
3755 struct evbuffer * reply_buf;
3756
3757 c = evhtp_request_get_connection(request);
3758
3759 if (!(reply_buf = htp__create_reply_(request, code))) {
3761 return;
3762 }
3763
3764 bufferevent_write_buffer(c->bev, reply_buf);
3765 evbuffer_drain(reply_buf, -1);
3766}
3767
3768void
3769evhtp_send_reply_body(evhtp_request_t * request, struct evbuffer * buf)
3770{
3771 evhtp_connection_t * c;
3772
3773 c = request->conn;
3774
3775 bufferevent_write_buffer(c->bev, buf);
3776}
3777
3778void
3779evhtp_send_reply_end(evhtp_request_t * request)
3780{
3782}
3783
3784void
3785evhtp_send_reply(evhtp_request_t * request, evhtp_res code)
3786{
3787 evhtp_connection_t * c;
3788 struct evbuffer * reply_buf;
3789 struct bufferevent * bev;
3790
3791 c = request->conn;
3792
3793 log_debug("set finished flag");
3795
3796 if (!(reply_buf = htp__create_reply_(request, code))) {
3797 evhtp_safe_free(request->conn, evhtp_connection_free);
3798
3799 return;
3800 }
3801
3802 bev = c->bev;
3803
3804 log_debug("writing to bev %p", bev);
3805 bufferevent_write_buffer(bev, reply_buf);
3806
3807 evbuffer_drain(reply_buf, -1);
3808}
3809
3810int
3811evhtp_response_needs_body(const evhtp_res code, const htp_method method)
3812{
3813 return code != EVHTP_RES_NOCONTENT &&
3814 code != EVHTP_RES_NOTMOD &&
3815 (code < 100 || code >= 200) &&
3816 method != htp_method_HEAD;
3817}
3818
3819void
3820evhtp_send_reply_chunk_start(evhtp_request_t * request, evhtp_res code)
3821{
3822 evhtp_header_t * content_len;
3823
3824 if (evhtp_response_needs_body(code, request->method)) {
3825 content_len = evhtp_headers_find_header(request->headers_out, "Content-Length");
3826
3827 switch (request->proto) {
3828 case EVHTP_PROTO_11:
3829
3830 /*
3831 * prefer HTTP/1.1 chunked encoding to closing the connection;
3832 * note RFC 2616 section 4.4 forbids it with Content-Length:
3833 * and it's not necessary then anyway.
3834 */
3835
3836 evhtp_kv_rm_and_free(request->headers_out, content_len);
3837
3839 break;
3840 case EVHTP_PROTO_10:
3841 /*
3842 * HTTP/1.0 can be chunked as long as the Content-Length header
3843 * is set to 0
3844 */
3845 evhtp_kv_rm_and_free(request->headers_out, content_len);
3846
3848 break;
3849 default:
3851 break;
3852 } /* switch */
3853 } else {
3855 }
3856
3857 if (request->flags & EVHTP_REQ_FLAG_CHUNKED) {
3858 evhtp_headers_add_header(request->headers_out,
3859 evhtp_header_new("Transfer-Encoding", "chunked", 0, 0));
3860
3861 /*
3862 * if data already exists on the output buffer, we automagically convert
3863 * it to the first chunk.
3864 */
3865 if (evbuffer_get_length(request->buffer_out) > 0) {
3866 char lstr[128];
3867 int sres;
3868
3869 sres = snprintf(lstr, sizeof(lstr), "%x\r\n",
3870 (unsigned)evbuffer_get_length(request->buffer_out));
3871
3872 if (sres >= sizeof(lstr) || sres < 0) {
3873 /* overflow condition, shouldn't ever get here, but lets
3874 * terminate the connection asap */
3875 goto end;
3876 }
3877
3878 evbuffer_prepend(request->buffer_out, lstr, strlen(lstr));
3879 evbuffer_add(request->buffer_out, "\r\n", 2);
3880 }
3881 }
3882
3883end:
3884 evhtp_send_reply_start(request, code);
3885} /* evhtp_send_reply_chunk_start */
3886
3887void
3888evhtp_send_reply_chunk(evhtp_request_t * request, struct evbuffer * buf)
3889{
3890 struct evbuffer * output;
3891
3892 if (evbuffer_get_length(buf) == 0) {
3893 return;
3894 }
3895
3896 output = bufferevent_get_output(request->conn->bev);
3897
3898 if (request->flags & EVHTP_REQ_FLAG_CHUNKED) {
3899 evbuffer_add_printf(output, "%x\r\n",
3900 (unsigned)evbuffer_get_length(buf));
3901 }
3902
3903 evhtp_send_reply_body(request, buf);
3904
3905 if (request->flags & EVHTP_REQ_FLAG_CHUNKED) {
3906 evbuffer_add(output, "\r\n", 2);
3907 }
3908
3909 bufferevent_flush(request->conn->bev, EV_WRITE, BEV_FLUSH);
3910}
3911
3912void
3913evhtp_send_reply_chunk_end(evhtp_request_t * request)
3914{
3915 if (request->flags & EVHTP_REQ_FLAG_CHUNKED) {
3916 evbuffer_add(bufferevent_get_output(evhtp_request_get_bev(request)),
3917 "0\r\n\r\n", 5);
3918 }
3919
3920 evhtp_send_reply_end(request);
3921}
3922
3923void
3925{
3926 if (htp == NULL || htp->server == NULL) {
3927 return;
3928 }
3929
3930 evhtp_safe_free(htp->server, evconnlistener_free);
3931}
3932
3933static int
3934htp__serv_setsockopts_(evhtp_t * htp, evutil_socket_t sock)
3935{
3936 int on = 1;
3937
3938 if (htp == NULL || sock == -1) {
3939 log_error("htp = %p && sock = %d", htp, sock);
3940 return -1;
3941 }
3942
3943 if (setsockopt(sock, SOL_SOCKET, SO_KEEPALIVE, (void *)&on, sizeof(on)) == -1) {
3944 return -1;
3945 }
3946
3947 if (setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, (void *)&on, sizeof(on)) == -1) {
3948 return -1;
3949 }
3950
3951#if defined(SO_REUSEPORT)
3952 if (htp->flags & EVHTP_FLAG_ENABLE_REUSEPORT) {
3953 if (setsockopt(sock, SOL_SOCKET, SO_REUSEPORT, (void *)&on, sizeof(on)) == -1) {
3954 if (errno != EOPNOTSUPP) {
3955 log_error("SO_REUSEPORT error");
3956 return -1;
3957 }
3958
3959 log_warn("SO_REUSEPORT NOT SUPPORTED");
3960 }
3961 }
3962
3963#endif
3964
3965#if defined(TCP_NODELAY)
3966 if (htp->flags & EVHTP_FLAG_ENABLE_NODELAY) {
3967 if (setsockopt(sock, IPPROTO_TCP, TCP_NODELAY, (void *)&on, sizeof(on)) == -1) {
3968 if (errno != EOPNOTSUPP) {
3969 log_error("TCP_NODELAY error");
3970 return -1;
3971 }
3972
3973 log_warn("NODELAY NOT SUPPORTED");
3974 }
3975 }
3976
3977#endif
3978
3979#if defined(TCP_DEFER_ACCEPT)
3980 if (htp->flags & EVHTP_FLAG_ENABLE_DEFER_ACCEPT) {
3981 if (setsockopt(sock, IPPROTO_TCP, TCP_DEFER_ACCEPT, (void *)&on, sizeof(on)) == -1) {
3982 if (errno != EOPNOTSUPP) {
3983 log_error("DEFER_ACCEPT error");
3984 return -1;
3985 }
3986
3987 log_warn("DEFER_ACCEPT NOT SUPPORTED");
3988 }
3989 }
3990
3991#endif
3992
3993 return 0;
3994} /* htp__setsockopts_ */
3995
3996int
3997evhtp_accept_socket(evhtp_t * htp, evutil_socket_t sock, int backlog)
3998{
3999 int err = 1;
4000
4001 if (htp == NULL || sock == -1) {
4002 log_error("htp = %p && sock = %d", htp, sock);
4003 return -1;
4004 }
4005
4006 do {
4007 htp->server = evconnlistener_new(htp->evbase,
4009 htp,
4010 LEV_OPT_CLOSE_ON_FREE | LEV_OPT_REUSEABLE,
4011 backlog,
4012 sock);
4013
4014 if (htp->server == NULL) {
4015 break;
4016 }
4017
4018#ifndef EVHTP_DISABLE_SSL
4019 if (htp->ssl_ctx != NULL) {
4020 /* if ssl is enabled and we have virtual hosts, set our servername
4021 * callback. We do this here because we want to make sure that this gets
4022 * set after all potential virtualhosts have been set, not just after
4023 * ssl_init.
4024 */
4025 if (TAILQ_FIRST(&htp->vhosts) != NULL) {
4026 SSL_CTX_set_tlsext_servername_callback(htp->ssl_ctx,
4028 }
4029 }
4030
4031#endif
4032 err = 0;
4033 } while (0);
4034
4035 if (err == 1) {
4036 if (htp->server != NULL) {
4037 evhtp_safe_free(htp->server, evconnlistener_free);
4038 }
4039
4040 return -1;
4041 }
4042
4043 return 0;
4044} /* evhtp_accept_socket */
4045
4046int
4048 struct sockaddr * sa,
4049 size_t sin_len,
4050 int backlog)
4051{
4052 evutil_socket_t fd = -1;
4053 int on = 1;
4054 int error = 1;
4055
4056 if (htp == NULL) {
4057 log_error("NULL param passed");
4058 return -1;
4059 }
4060
4061 /* XXX: API's should not set signals */
4062#ifndef WIN32
4063 signal(SIGPIPE, SIG_IGN);
4064#endif
4065
4066 do {
4067 if ((fd = socket(sa->sa_family, SOCK_STREAM, 0)) == -1) {
4068 log_error("couldn't create socket");
4069 return -1;
4070 }
4071
4072 evutil_make_socket_closeonexec(fd);
4073 evutil_make_socket_nonblocking(fd);
4074
4075 if (htp__serv_setsockopts_(htp, fd) == -1) {
4076 break;
4077 }
4078
4079 if (sa->sa_family == AF_INET6) {
4080 if (setsockopt(fd, IPPROTO_IPV6, IPV6_V6ONLY, &on, sizeof(on)) == -1) {
4081 break;
4082 }
4083 }
4084
4085 if (bind(fd, sa, sin_len) == -1) {
4086 break;
4087 }
4088
4089 error = 0;
4090 } while (0);
4091
4092
4093 if (error == 1) {
4094 if (fd != -1) {
4095 evutil_closesocket(fd);
4096 }
4097
4098 return -1;
4099 }
4100
4101 if (evhtp_accept_socket(htp, fd, backlog) == -1) {
4102 /* accept_socket() does not close the descriptor
4103 * on error, but this function does.
4104 */
4105 evutil_closesocket(fd);
4106
4107 return -1;
4108 }
4109
4110 return 0;
4111} /* evhtp_bind_sockaddr */
4112
4113int
4114evhtp_bind_socket(evhtp_t * htp, const char * baddr, uint16_t port, int backlog)
4115{
4116#ifndef NO_SYS_UN
4117 struct sockaddr_un sockun = { 0 };
4118#endif
4119 struct sockaddr * sa;
4120 struct sockaddr_in6 sin6 = { 0 };
4121 struct sockaddr_in sin = { 0 };
4122 size_t sin_len;
4123
4124 if (!strncmp(baddr, "ipv6:", 5)) {
4125 baddr += 5;
4126 sin_len = sizeof(struct sockaddr_in6);
4127 sin6.sin6_port = htons(port);
4128 sin6.sin6_family = AF_INET6;
4129
4130 evutil_inet_pton(AF_INET6, baddr, &sin6.sin6_addr);
4131 sa = (struct sockaddr *)&sin6;
4132 } else if (!strncmp(baddr, "unix:", 5)) {
4133#ifndef NO_SYS_UN
4134 baddr += 5;
4135
4136 if (strlen(baddr) >= sizeof(sockun.sun_path)) {
4137 return -1;
4138 }
4139
4140 sin_len = sizeof(struct sockaddr_un);
4141 sockun.sun_family = AF_UNIX;
4142
4143 strncpy(sockun.sun_path, baddr, strlen(baddr));
4144
4145 sa = (struct sockaddr *)&sockun;
4146#else
4147
4148 return -1;
4149#endif
4150 } else {
4151 if (!strncmp(baddr, "ipv4:", 5)) {
4152 baddr += 5;
4153 }
4154
4155 sin_len = sizeof(struct sockaddr_in);
4156 sin.sin_family = AF_INET;
4157 sin.sin_port = htons(port);
4158 sin.sin_addr.s_addr = inet_addr(baddr);
4159
4160 sa = (struct sockaddr *)&sin;
4161 }
4162
4163 return evhtp_bind_sockaddr(htp, sa, sin_len, backlog);
4164} /* evhtp_bind_socket */
4165
4166void
4168{
4169 evhtp_callback_t * callback;
4170 evhtp_callback_t * tmp;
4171
4172 if (callbacks == NULL) {
4173 return;
4174 }
4175
4176 TAILQ_FOREACH_SAFE(callback, callbacks, next, tmp) {
4177 TAILQ_REMOVE(callbacks, callback, next);
4178
4180 }
4181
4182 evhtp_safe_free(callbacks, htp__free_);
4183}
4184
4185evhtp_callback_t *
4186evhtp_callback_new(const char * path, evhtp_callback_type type, evhtp_callback_cb cb, void * arg)
4187{
4188 evhtp_callback_t * hcb;
4189
4190 hcb = htp__calloc_(sizeof(*hcb), 1);
4191
4192 if (evhtp_unlikely(hcb == NULL)) {
4194
4195 return NULL;
4196 }
4197
4198 hcb->type = type;
4199 hcb->cb = cb;
4200 hcb->cbarg = arg;
4201 hcb->len = strlen(path);
4202
4203 switch (type) {
4205 hcb->val.path = htp__strdup_(path);
4206
4207 if (evhtp_unlikely(hcb->val.path == NULL)) {
4209
4210 return NULL;
4211 }
4212
4213 break;
4214#ifndef EVHTP_DISABLE_REGEX
4216 hcb->val.regex = htp__malloc_(sizeof(regex_t));
4217
4218 if (evhtp_unlikely(hcb->val.regex == NULL)) {
4220
4221 return NULL;
4222 }
4223
4224 if (regcomp(hcb->val.regex, (char *)path, REG_EXTENDED) != 0) {
4225 evhtp_safe_free(hcb->val.regex, htp__free_);
4227
4228 return NULL;
4229 }
4230
4231 break;
4232#endif
4234 hcb->val.glob = htp__strdup_(path);
4235
4236 if (evhtp_unlikely(hcb->val.glob == NULL)) {
4238
4239 return NULL;
4240 }
4241
4242 break;
4243 default:
4245
4246 return NULL;
4247 } /* switch */
4248
4249 return hcb;
4250} /* evhtp_callback_new */
4251
4252void
4253evhtp_callback_free(evhtp_callback_t * callback)
4254{
4255 if (callback == NULL) {
4256 return;
4257 }
4258
4259 switch (callback->type) {
4261 evhtp_safe_free(callback->val.path, htp__free_);
4262 break;
4264 evhtp_safe_free(callback->val.glob, htp__free_);
4265 break;
4266#ifndef EVHTP_DISABLE_REGEX
4268 evhtp_safe_free(callback->val.regex, htp__free_);
4269 break;
4270#endif
4271 }
4272
4273 if (callback->hooks) {
4274 evhtp_safe_free(callback->hooks, htp__free_);
4275 }
4276
4277 evhtp_safe_free(callback, htp__free_);
4278
4279 return;
4280}
4281
4282int
4284{
4285 TAILQ_INSERT_TAIL(cbs, cb, next);
4286
4287 return 0;
4288}
4289
4290static int
4291htp__set_hook_(evhtp_hooks_t ** hooks, evhtp_hook_type type, evhtp_hook cb, void * arg)
4292{
4293 if (*hooks == NULL) {
4294 if (!(*hooks = htp__calloc_(sizeof(evhtp_hooks_t), 1))) {
4295 return -1;
4296 }
4297 }
4298
4299 switch (type) {
4301 (*hooks)->on_headers_start = (evhtp_hook_headers_start_cb)cb;
4302 (*hooks)->on_headers_start_arg = arg;
4303 break;
4305 (*hooks)->on_header = (evhtp_hook_header_cb)cb;
4306 (*hooks)->on_header_arg = arg;
4307 break;
4309 (*hooks)->on_headers = (evhtp_hook_headers_cb)cb;
4310 (*hooks)->on_headers_arg = arg;
4311 break;
4312 case evhtp_hook_on_path:
4313 (*hooks)->on_path = (evhtp_hook_path_cb)cb;
4314 (*hooks)->on_path_arg = arg;
4315 break;
4316 case evhtp_hook_on_read:
4317 (*hooks)->on_read = (evhtp_hook_read_cb)cb;
4318 (*hooks)->on_read_arg = arg;
4319 break;
4321 (*hooks)->on_request_fini = (evhtp_hook_request_fini_cb)cb;
4322 (*hooks)->on_request_fini_arg = arg;
4323 break;
4325 (*hooks)->on_connection_fini = (evhtp_hook_connection_fini_cb)cb;
4326 (*hooks)->on_connection_fini_arg = arg;
4327 break;
4329 (*hooks)->on_connection_error = (evhtp_hook_conn_err_cb)cb;
4330 (*hooks)->on_connection_error_arg = arg;
4331 break;
4333 (*hooks)->on_error = (evhtp_hook_err_cb)cb;
4334 (*hooks)->on_error_arg = arg;
4335 break;
4337 (*hooks)->on_new_chunk = (evhtp_hook_chunk_new_cb)cb;
4338 (*hooks)->on_new_chunk_arg = arg;
4339 break;
4341 (*hooks)->on_chunk_fini = (evhtp_hook_chunk_fini_cb)cb;
4342 (*hooks)->on_chunk_fini_arg = arg;
4343 break;
4345 (*hooks)->on_chunks_fini = (evhtp_hook_chunks_fini_cb)cb;
4346 (*hooks)->on_chunks_fini_arg = arg;
4347 break;
4349 (*hooks)->on_hostname = (evhtp_hook_hostname_cb)cb;
4350 (*hooks)->on_hostname_arg = arg;
4351 break;
4353 (*hooks)->on_write = (evhtp_hook_write_cb)cb;
4354 (*hooks)->on_write_arg = arg;
4355 break;
4357 (*hooks)->on_event = (evhtp_hook_event_cb)cb;
4358 (*hooks)->on_event_arg = arg;
4359 break;
4360 default:
4361 return -1;
4362 } /* switch */
4363
4364 return 0;
4365} /* htp__set_hook_ */
4366
4367static int
4368htp__unset_hook_(evhtp_hooks_t ** hooks, evhtp_hook_type type)
4369{
4370 return htp__set_hook_(hooks, type, NULL, NULL);
4371}
4372
4373int
4374evhtp_callback_unset_hook(evhtp_callback_t * callback, evhtp_hook_type type)
4375{
4376 return htp__unset_hook_(&callback->hooks, type);
4377}
4378
4379int
4380evhtp_request_unset_hook(evhtp_request_t * req, evhtp_hook_type type)
4381{
4382 return htp__unset_hook_(&req->hooks, type);
4383}
4384
4385int
4386evhtp_connection_unset_hook(evhtp_connection_t * conn, evhtp_hook_type type)
4387{
4388 return htp__unset_hook_(&conn->hooks, type);
4389}
4390
4391int
4392evhtp_callback_set_hook(evhtp_callback_t * callback, evhtp_hook_type type, evhtp_hook cb,
4393 void * arg)
4394{
4395 return htp__set_hook_(&callback->hooks, type, cb, arg);
4396}
4397
4398int
4399evhtp_request_set_hook(evhtp_request_t * req, evhtp_hook_type type, evhtp_hook cb, void * arg)
4400{
4401 return htp__set_hook_(&req->hooks, type, cb, arg);
4402}
4403
4404int
4406 void * arg)
4407{
4408 return htp__set_hook_(&conn->hooks, type, cb, arg);
4409}
4410
4411int
4412evhtp_unset_all_hooks(evhtp_hooks_t ** hooks)
4413{
4414 int i;
4415
4416 struct {
4417 enum evhtp_hook_type type;
4418 } hooklist_[] = {
4434 { evhtp_hook__max }
4435 };
4436
4437 if (hooks == NULL) {
4438 return -1;
4439 }
4440
4441 for (i = 0; hooklist_[i].type != evhtp_hook__max; i++) {
4442 if (htp__unset_hook_(hooks, hooklist_[i].type) == -1) {
4443 return -1;
4444 }
4445 }
4446
4447 return 0;
4448}
4449
4450evhtp_hooks_t *
4451evhtp_connection_get_hooks(evhtp_connection_t * c)
4452{
4453 if (evhtp_unlikely(c == NULL)) {
4454 return NULL;
4455 }
4456
4457 return c->hooks;
4458}
4459
4466evhtp_hooks_t *
4467evhtp_request_get_hooks(evhtp_request_t * r)
4468{
4469 if (evhtp_unlikely(r == NULL)) {
4470 return NULL;
4471 }
4472
4473 return r->hooks;
4474}
4475
4482evhtp_hooks_t *
4483evhtp_callback_get_hooks(evhtp_callback_t * cb)
4484{
4485 return cb->hooks;
4486}
4487
4488evhtp_callback_t *
4489evhtp_set_cb(evhtp_t * htp, const char * path, evhtp_callback_cb cb, void * arg)
4490{
4491 evhtp_callback_t * hcb;
4492
4493 htp__lock_(htp);
4494
4495 if (htp->callbacks == NULL) {
4496 if (!(htp->callbacks = htp__calloc_(sizeof(evhtp_callbacks_t), 1))) {
4497 htp__unlock_(htp);
4498
4499 return NULL;
4500 }
4501
4502 TAILQ_INIT(htp->callbacks);
4503 }
4504
4505 if (!(hcb = evhtp_callback_new(path, evhtp_callback_type_hash, cb, arg))) {
4506 htp__unlock_(htp);
4507
4508 return NULL;
4509 }
4510
4511 if (evhtp_callbacks_add_callback(htp->callbacks, hcb)) {
4513 htp__unlock_(htp);
4514
4515 return NULL;
4516 }
4517
4518 htp__unlock_(htp);
4519
4520 return hcb;
4521}
4522
4523evhtp_callback_t *
4524evhtp_get_cb(evhtp_t * htp, const char * path)
4525{
4526 evhtp_callback_t * callback;
4527
4528 evhtp_assert(htp != NULL);
4529
4530 if (evhtp_unlikely(htp->callbacks == NULL)) {
4531 return NULL;
4532 }
4533
4534 TAILQ_FOREACH(callback, htp->callbacks, next) {
4535 if (strcmp(callback->val.path, path) == 0) {
4536 return callback;
4537 }
4538 }
4539
4540 return NULL;
4541}
4542
4543#ifndef EVHTP_DISABLE_EVTHR
4544static void
4545htp__thread_init_(evthr_t * thr, void * arg)
4546{
4547 evhtp_t * htp = (evhtp_t *)arg;
4548
4549 if (htp->thread_init_cb) {
4550 htp->thread_init_cb(htp, thr, htp->thread_cbarg);
4551 }
4552}
4553
4554static void
4555htp__thread_exit_(evthr_t * thr, void * arg)
4556{
4557 evhtp_t * htp = (evhtp_t *)arg;
4558
4559 if (htp->thread_exit_cb) {
4560 htp->thread_exit_cb(htp, thr, htp->thread_cbarg);
4561 }
4562}
4563
4564static int
4565htp__use_threads_(evhtp_t * htp,
4566 evhtp_thread_init_cb init_cb,
4567 evhtp_thread_exit_cb exit_cb,
4568 int nthreads, void * arg)
4569{
4570 if (htp == NULL) {
4571 return -1;
4572 }
4573
4574 htp->thread_cbarg = arg;
4575 htp->thread_init_cb = init_cb;
4576 htp->thread_exit_cb = exit_cb;
4577
4578#ifndef EVHTP_DISABLE_SSL
4580#endif
4581
4582 if (!(htp->thr_pool = evthr_pool_wexit_new(nthreads,
4584 htp__thread_exit_, htp))) {
4585 return -1;
4586 }
4587
4588 evthr_pool_start(htp->thr_pool);
4589
4590 return 0;
4591}
4592
4593int
4595 int nthreads, void * arg)
4596{
4597 return htp__use_threads_(htp, init_cb, NULL, nthreads, arg);
4598}
4599
4600int
4602 evhtp_thread_init_cb init_cb,
4603 evhtp_thread_exit_cb exit_cb,
4604 int nthreads, void * arg)
4605{
4606 return htp__use_threads_(htp, init_cb, exit_cb, nthreads, arg);
4607}
4608
4609#endif
4610
4611#ifndef EVHTP_DISABLE_EVTHR
4612int
4614{
4615 if (htp == NULL) {
4616 return -1;
4617 }
4618
4619 if (!(htp->lock = htp__malloc_(sizeof(pthread_mutex_t)))) {
4620 return -1;
4621 }
4622
4623 return pthread_mutex_init(htp->lock, NULL);
4624}
4625
4626#endif
4627
4628#ifndef EVHTP_DISABLE_REGEX
4629evhtp_callback_t *
4631 const char * pattern,
4633 void * arg)
4634{
4635 evhtp_callback_t * hcb;
4636
4637 htp__lock_(htp);
4638
4639 if (htp->callbacks == NULL) {
4640 if (!(htp->callbacks = htp__calloc_(sizeof(evhtp_callbacks_t), 1))) {
4641 htp__unlock_(htp);
4642
4643 return NULL;
4644 }
4645
4646 TAILQ_INIT(htp->callbacks);
4647 }
4648
4649 if (!(hcb = evhtp_callback_new(pattern, evhtp_callback_type_regex, cb, arg))) {
4650 htp__unlock_(htp);
4651
4652 return NULL;
4653 }
4654
4655 if (evhtp_callbacks_add_callback(htp->callbacks, hcb)) {
4657 htp__unlock_(htp);
4658
4659 return NULL;
4660 }
4661
4662 htp__unlock_(htp);
4663
4664 return hcb;
4665}
4666
4667#endif
4668
4669evhtp_callback_t *
4670evhtp_set_glob_cb(evhtp_t * htp, const char * pattern, evhtp_callback_cb cb, void * arg)
4671{
4672 evhtp_callback_t * hcb;
4673
4674 htp__lock_(htp);
4675
4676 if (htp->callbacks == NULL) {
4677 if (!(htp->callbacks = htp__calloc_(sizeof(evhtp_callbacks_t), 1))) {
4678 htp__unlock_(htp);
4679
4680 return NULL;
4681 }
4682
4683 TAILQ_INIT(htp->callbacks);
4684 }
4685
4686 if (!(hcb = evhtp_callback_new(pattern, evhtp_callback_type_glob, cb, arg))) {
4687 htp__unlock_(htp);
4688
4689 return NULL;
4690 }
4691
4692 if (evhtp_callbacks_add_callback(htp->callbacks, hcb)) {
4694 htp__unlock_(htp);
4695
4696 return NULL;
4697 }
4698
4699 htp__unlock_(htp);
4700
4701 return hcb;
4702}
4703
4704void
4705evhtp_set_gencb(evhtp_t * htp, evhtp_callback_cb cb, void * arg)
4706{
4707 htp->defaults.cb = cb;
4708 htp->defaults.cbarg = arg;
4709}
4710
4711void
4713{
4714 htp->defaults.pre_accept = cb;
4715 htp->defaults.pre_accept_cbarg = arg;
4716}
4717
4718void
4720{
4721 htp->defaults.post_accept = cb;
4722 htp->defaults.post_accept_cbarg = arg;
4723}
4724
4725#ifndef EVHTP_DISABLE_SSL
4726#ifndef EVHTP_DISABLE_EVTHR
4727int
4729{
4730 int i;
4731
4732 if (ssl_locks_initialized == 1) {
4733 return 0;
4734 }
4735
4737 ssl_num_locks = CRYPTO_num_locks();
4738
4740 sizeof(evhtp_mutex_t))) == NULL) {
4741 return -1;
4742 }
4743
4744 for (i = 0; i < ssl_num_locks; i++) {
4745 pthread_mutex_init(&(ssl_locks[i]), NULL);
4746 }
4747
4748#if OPENSSL_VERSION_NUMBER < 0x10000000L
4749 CRYPTO_set_id_callback(htp__ssl_get_thread_id_);
4750#else
4751 CRYPTO_THREADID_set_callback(htp__ssl_get_thread_id_);
4752#endif
4753
4754 CRYPTO_set_locking_callback(htp__ssl_thread_lock_);
4755
4756 return 0;
4757}
4758
4759#endif
4760
4761int
4762evhtp_ssl_init(evhtp_t * htp, evhtp_ssl_cfg_t * cfg)
4763{
4764 long cache_mode;
4765 unsigned char c;
4766
4767 if (cfg == NULL || htp == NULL || cfg->pemfile == NULL) {
4768 return -1;
4769 }
4770
4771#if OPENSSL_VERSION_NUMBER < 0x10100000L
4772 SSL_library_init();
4773 ERR_load_crypto_strings();
4774 SSL_load_error_strings();
4775 OpenSSL_add_all_algorithms();
4776#else
4777 /* unnecessary in OpenSSL 1.1.0 */
4778 /*
4779 * if (OPENSSL_init_ssl(OPENSSL_INIT_SSL_DEFAULT, NULL) == 0) {
4780 * log_error("OPENSSL_init_ssl");
4781 * return -1;
4782 * }
4783 *
4784 * if (OPENSSL_init_crypto(
4785 * OPENSSL_INIT_ADD_ALL_CIPHERS |
4786 * OPENSSL_INIT_ADD_ALL_DIGESTS |
4787 * OPENSSL_INIT_LOAD_CONFIG, NULL) == 0) {
4788 * log_error("OPENSSL_init_crypto");
4789 * return -1;
4790 * }
4791 */
4792#endif
4793 if (RAND_poll() != 1) {
4794 log_error("RAND_poll");
4795 return -1;
4796 }
4797
4798 if (RAND_bytes(&c, 1) != 1) {
4799 log_error("RAND_bytes");
4800 return -1;
4801 }
4802
4803#if OPENSSL_VERSION_NUMBER < 0x10000000L
4804 STACK_OF(SSL_COMP) * comp_methods = SSL_COMP_get_compression_methods();
4805 sk_SSL_COMP_zero(comp_methods);
4806#endif
4807
4808 htp->ssl_cfg = cfg;
4809#if OPENSSL_VERSION_NUMBER < 0x10100000L
4810 htp->ssl_ctx = SSL_CTX_new(SSLv23_server_method());
4811#else
4812 htp->ssl_ctx = SSL_CTX_new(TLS_server_method());
4813#endif
4814
4815 evhtp_alloc_assert(htp->ssl_ctx);
4816
4817#if OPENSSL_VERSION_NUMBER >= 0x10000000L
4818 SSL_CTX_set_options(htp->ssl_ctx, SSL_MODE_RELEASE_BUFFERS | SSL_OP_NO_COMPRESSION);
4819 SSL_CTX_set_timeout(htp->ssl_ctx, cfg->ssl_ctx_timeout);
4820#endif
4821
4822 SSL_CTX_set_options(htp->ssl_ctx, cfg->ssl_opts);
4823
4824#ifndef OPENSSL_NO_ECDH
4825 if (cfg->named_curve != NULL) {
4826 EC_KEY * ecdh = NULL;
4827 int nid = 0;
4828
4829 nid = OBJ_sn2nid(cfg->named_curve);
4830
4831 if (nid == 0) {
4832 log_error("ECDH initialization failed: unknown curve %s", cfg->named_curve);
4833 }
4834
4835 ecdh = EC_KEY_new_by_curve_name(nid);
4836
4837 if (ecdh == NULL) {
4838 log_error("ECDH initialization failed for curve %s", cfg->named_curve);
4839 }
4840
4841 SSL_CTX_set_tmp_ecdh(htp->ssl_ctx, ecdh);
4842 EC_KEY_free(ecdh);
4843 }
4844
4845#endif /* OPENSSL_NO_ECDH */
4846#ifndef OPENSSL_NO_DH
4847 if (cfg->dhparams != NULL) {
4848 FILE * fh;
4849 DH * dh;
4850
4851 fh = fopen(cfg->dhparams, "r");
4852
4853 if (fh != NULL) {
4854 dh = PEM_read_DHparams(fh, NULL, NULL, NULL);
4855 if (dh != NULL) {
4856 SSL_CTX_set_tmp_dh(htp->ssl_ctx, dh);
4857 DH_free(dh);
4858 } else {
4859 log_error("DH initialization failed: unable to parse file %s", cfg->dhparams);
4860 }
4861
4862 fclose(fh);
4863 } else {
4864 log_error("DH initialization failed: unable to open file %s", cfg->dhparams);
4865 }
4866 }
4867
4868#endif /* OPENSSL_NO_DH */
4869
4870 if (cfg->ciphers != NULL) {
4871 if (SSL_CTX_set_cipher_list(htp->ssl_ctx, cfg->ciphers) == 0) {
4872 log_error("set_cipher_list");
4873 return -1;
4874 }
4875 }
4876
4877 SSL_CTX_load_verify_locations(htp->ssl_ctx, cfg->cafile, cfg->capath);
4878 X509_STORE_set_flags(SSL_CTX_get_cert_store(htp->ssl_ctx), cfg->store_flags);
4879 SSL_CTX_set_verify(htp->ssl_ctx, cfg->verify_peer, cfg->x509_verify_cb);
4880
4881 if (cfg->x509_chk_issued_cb != NULL) {
4882#if OPENSSL_VERSION_NUMBER < 0x10100000L
4883 htp->ssl_ctx->cert_store->check_issued = cfg->x509_chk_issued_cb;
4884#else
4885 X509_STORE_set_check_issued(SSL_CTX_get_cert_store(htp->ssl_ctx), cfg->x509_chk_issued_cb);
4886#endif
4887 }
4888
4889 if (cfg->verify_depth) {
4890 SSL_CTX_set_verify_depth(htp->ssl_ctx, cfg->verify_depth);
4891 }
4892
4893 switch (cfg->scache_type) {
4895 cache_mode = SSL_SESS_CACHE_OFF;
4896 break;
4897 default:
4898 cache_mode = SSL_SESS_CACHE_SERVER;
4899 break;
4900 } /* switch */
4901
4902 SSL_CTX_use_certificate_chain_file(htp->ssl_ctx, cfg->pemfile);
4903
4904 char * const key = cfg->privfile ? cfg->privfile : cfg->pemfile;
4905
4906 if (cfg->decrypt_cb != NULL) {
4907 EVP_PKEY * pkey = cfg->decrypt_cb(key);
4908
4909 if (pkey == NULL) {
4910 return -1;
4911 }
4912
4913 SSL_CTX_use_PrivateKey(htp->ssl_ctx, pkey);
4914
4915 /*cleanup */
4916 EVP_PKEY_free(pkey);
4917 } else {
4918 SSL_CTX_use_PrivateKey_file(htp->ssl_ctx, key, SSL_FILETYPE_PEM);
4919 }
4920
4921 SSL_CTX_set_session_id_context(htp->ssl_ctx,
4922 (void *)&session_id_context,
4923 sizeof(session_id_context));
4924
4925 SSL_CTX_set_app_data(htp->ssl_ctx, htp);
4926 SSL_CTX_set_session_cache_mode(htp->ssl_ctx, cache_mode);
4927
4928 if (cache_mode != SSL_SESS_CACHE_OFF) {
4929 SSL_CTX_sess_set_cache_size(htp->ssl_ctx,
4930 cfg->scache_size ? cfg->scache_size : 1024);
4931
4932 if (cfg->scache_type == evhtp_ssl_scache_type_builtin ||
4933 cfg->scache_type == evhtp_ssl_scache_type_user) {
4934 SSL_CTX_sess_set_new_cb(htp->ssl_ctx, htp__ssl_add_scache_ent_);
4935 SSL_CTX_sess_set_get_cb(htp->ssl_ctx, htp__ssl_get_scache_ent_);
4936 SSL_CTX_sess_set_remove_cb(htp->ssl_ctx, htp__ssl_delete_scache_ent_);
4937
4938 if (cfg->scache_init) {
4939 cfg->args = (cfg->scache_init)(htp);
4940 }
4941 }
4942 }
4943
4944 return 0;
4945} /* evhtp_use_ssl */
4946
4947#endif
4948
4949struct bufferevent *
4950evhtp_connection_get_bev(evhtp_connection_t * connection)
4951{
4952 return connection->bev;
4953}
4954
4955struct bufferevent *
4956evhtp_connection_take_ownership(evhtp_connection_t * connection)
4957{
4958 struct bufferevent * bev = evhtp_connection_get_bev(connection);
4959
4960 if (connection->hooks) {
4961 evhtp_unset_all_hooks(&connection->hooks);
4962 }
4963
4964 if (connection->request && connection->request->hooks) {
4965 evhtp_unset_all_hooks(&connection->request->hooks);
4966 }
4967
4968 evhtp_connection_set_bev(connection, NULL);
4969
4970 /* relinquish ownership of this connection, unset
4971 * the ownership flag.
4972 */
4974
4975 bufferevent_disable(bev, EV_READ);
4976 bufferevent_setcb(bev, NULL, NULL, NULL, NULL);
4977
4978 return bev;
4979}
4980
4981struct bufferevent *
4982evhtp_request_get_bev(evhtp_request_t * request)
4983{
4984 return evhtp_connection_get_bev(request->conn);
4985}
4986
4987struct bufferevent *
4988evhtp_request_take_ownership(evhtp_request_t * request)
4989{
4990 return evhtp_connection_take_ownership(request->conn);
4991}
4992
4993void
4994evhtp_connection_set_bev(evhtp_connection_t * conn, struct bufferevent * bev)
4995{
4996 conn->bev = bev;
4997}
4998
4999void
5000evhtp_request_set_bev(evhtp_request_t * request, struct bufferevent * bev)
5001{
5002 evhtp_connection_set_bev(request->conn, bev);
5003}
5004
5005void
5006evhtp_request_set_keepalive(evhtp_request_t * request, int val)
5007{
5008 if (val) {
5010 }
5011}
5012
5013evhtp_connection_t *
5014evhtp_request_get_connection(evhtp_request_t * request)
5015{
5016 return request->conn;
5017}
5018
5020evhtp_request_get_proto(evhtp_request_t * request)
5021{
5022 return request->proto;
5023}
5024
5026evhtp_request_get_status_code(evhtp_request_t * request)
5027{
5028 return request->status;
5029}
5030
5031const char *
5032evhtp_request_get_status_code_str(evhtp_request_t * request)
5033{
5034 return status_code_to_str(request->status);
5035}
5036
5037inline void
5038evhtp_connection_set_timeouts(evhtp_connection_t * c,
5039 const struct timeval * rtimeo,
5040 const struct timeval * wtimeo)
5041{
5042 if (evhtp_unlikely(c == NULL)) {
5043 return;
5044 }
5045
5046 bufferevent_set_timeouts(c->bev, rtimeo, wtimeo);
5047}
5048
5049void
5050evhtp_connection_set_max_body_size(evhtp_connection_t * c, uint64_t len)
5051{
5052 if (len == 0) {
5053 c->max_body_size = c->htp->max_body_size;
5054 } else {
5055 c->max_body_size = len;
5056 }
5057}
5058
5059void
5060evhtp_request_set_max_body_size(evhtp_request_t * req, uint64_t len)
5061{
5062 evhtp_connection_set_max_body_size(req->conn, len);
5063}
5064
5065void
5066evhtp_connection_free(evhtp_connection_t * connection)
5067{
5068 if (evhtp_unlikely(connection == NULL)) {
5069 return;
5070 }
5071
5072 htp__hook_connection_fini_(connection);
5073
5074 evhtp_safe_free(connection->request, htp__request_free_);
5075 evhtp_safe_free(connection->parser, htp__free_);
5076 evhtp_safe_free(connection->hooks, htp__free_);
5077 evhtp_safe_free(connection->saddr, htp__free_);
5078 evhtp_safe_free(connection->scratch_buf, evbuffer_free);
5079
5080 if (connection->resume_ev) {
5081 evhtp_safe_free(connection->resume_ev, event_free);
5082 }
5083
5084 if (connection->bev) {
5085#ifdef LIBEVENT_HAS_SHUTDOWN
5086 bufferevent_shutdown(connection->bev, htp__shutdown_eventcb_);
5087#else
5088#ifndef EVHTP_DISABLE_SSL
5089 if (connection->ssl != NULL) {
5090 SSL_set_shutdown(connection->ssl, SSL_RECEIVED_SHUTDOWN);
5091 SSL_shutdown(connection->ssl);
5092 }
5093
5094#endif
5095 evhtp_safe_free(connection->bev, bufferevent_free);
5096#endif
5097 }
5098
5099 evhtp_safe_free(connection, htp__free_);
5100} /* evhtp_connection_free */
5101
5102void
5103evhtp_request_free(evhtp_request_t * request)
5104{
5105 if (request == NULL) {
5106 return;
5107 }
5108
5110}
5111
5112void
5113evhtp_set_timeouts(evhtp_t * htp, const struct timeval * r_timeo, const struct timeval * w_timeo)
5114{
5115 if (r_timeo != NULL) {
5116 htp->recv_timeo = *r_timeo;
5117 }
5118
5119 if (w_timeo != NULL) {
5120 htp->send_timeo = *w_timeo;
5121 }
5122}
5123
5124void
5125evhtp_set_max_keepalive_requests(evhtp_t * htp, uint64_t num)
5126{
5127 htp->max_keepalive_requests = num;
5128}
5129
5130void
5131evhtp_set_bev_flags(evhtp_t * htp, int flags)
5132{
5133 htp->bev_flags = flags;
5134}
5135
5136void
5137evhtp_set_max_body_size(evhtp_t * htp, uint64_t len)
5138{
5139 htp->max_body_size = len;
5140}
5141
5142void
5147
5148void
5149evhtp_set_parser_flags(evhtp_t * htp, int flags)
5150{
5151 htp->parser_flags = flags;
5152}
5153
5154#define HTP_FLAG_FNGEN(NAME, TYPE) void \
5155 evhtp ## NAME ## _enable_flag(TYPE v, int flag) { \
5156 HTP_FLAG_ON(v, flag); \
5157 } \
5158 \
5159 void \
5160 evhtp ## NAME ## _disable_flag(TYPE v, int flag) { \
5161 HTP_FLAG_OFF(v, flag); \
5162 } \
5163 \
5164 int \
5165 evhtp ## NAME ## _get_flags(TYPE v) { \
5166 if (v) { \
5167 return v->flags; \
5168 } \
5169 return -1; \
5170 }
5171
5172HTP_FLAG_FNGEN(, evhtp_t *);
5173HTP_FLAG_FNGEN(_connection, evhtp_connection_t *);
5174HTP_FLAG_FNGEN(_request, evhtp_request_t *);
5175
5176int
5177evhtp_add_alias(evhtp_t * evhtp, const char * name)
5178{
5179 evhtp_alias_t * alias;
5180
5181 if (evhtp_unlikely(evhtp == NULL || name == NULL)) {
5182 return -1;
5183 }
5184
5185 if (!(alias = htp__calloc_(sizeof(evhtp_alias_t), 1))) {
5186 return -1;
5187 }
5188
5189 log_debug("Adding %s to aliases", name);
5190
5191 alias->alias = htp__strdup_(name);
5192
5193 if (evhtp_unlikely(alias->alias == NULL)) {
5195
5196 return -1;
5197 }
5198
5199 TAILQ_INSERT_TAIL(&evhtp->aliases, alias, next);
5200
5201 return 0;
5202}
5203
5204int
5205evhtp_add_aliases(evhtp_t * htp, const char * name, ...)
5206{
5207 va_list argp;
5208
5209 if (evhtp_add_alias(htp, name) == -1) {
5210 return -1;
5211 }
5212
5213 va_start(argp, name);
5214 {
5215 const char * p;
5216
5217 while ((p = va_arg(argp, const char *)) != NULL) {
5218 if (evhtp_add_alias(htp, p) == -1) {
5219 log_error("Unable to add %s alias", p);
5220 va_end(argp);
5221
5222 return -1;
5223 }
5224 }
5225 }
5226 va_end(argp);
5227
5228 return 0;
5229}
5230
5231int
5232evhtp_add_vhost(evhtp_t * evhtp, const char * name, evhtp_t * vhost)
5233{
5234 if (evhtp == NULL || name == NULL || vhost == NULL) {
5235 return -1;
5236 }
5237
5238 if (TAILQ_FIRST(&vhost->vhosts) != NULL) {
5239 /* vhosts cannot have secondary vhosts defined */
5240 return -1;
5241 }
5242
5243 vhost->server_name = htp__strdup_(name);
5244
5245 if (evhtp_unlikely(vhost->server_name == NULL)) {
5246 return -1;
5247 }
5248
5249 /* set the parent of this vhost so when the request has been completely
5250 * serviced, the vhost can be reset to the original evhtp structure.
5251 *
5252 * This allows for a keep-alive connection to make multiple requests with
5253 * different Host: values.
5254 */
5255 vhost->parent = evhtp;
5256
5257 /* inherit various flags from the parent evhtp structure */
5258 vhost->bev_flags = evhtp->bev_flags;
5259 vhost->max_body_size = evhtp->max_body_size;
5260 vhost->max_keepalive_requests = evhtp->max_keepalive_requests;
5261 vhost->recv_timeo = evhtp->recv_timeo;
5262 vhost->send_timeo = evhtp->send_timeo;
5263
5264 TAILQ_INSERT_TAIL(&evhtp->vhosts, vhost, next_vhost);
5265
5266 return 0;
5267}
5268
5278static int
5279evhtp__new_(evhtp_t ** out, struct event_base * evbase, void * arg)
5280{
5281 evhtp_t * htp;
5282
5283
5284 if (evhtp_unlikely(evbase == NULL)) {
5285 return -1;
5286 }
5287
5288 *out = NULL;
5289
5290 if ((htp = htp__calloc_(1, sizeof(*htp))) == NULL) {
5291 return -1;
5292 }
5293
5294 htp->arg = arg;
5295 htp->evbase = evbase;
5296 htp->flags = EVHTP_FLAG_DEFAULTS;
5297 htp->bev_flags = BEV_OPT_CLOSE_ON_FREE | BEV_OPT_DEFER_CALLBACKS;
5298
5299 /* default to lenient argument parsing */
5300 htp->parser_flags = EVHTP_PARSE_QUERY_FLAG_DEFAULT;
5301
5302
5303 TAILQ_INIT(&htp->vhosts);
5304 TAILQ_INIT(&htp->aliases);
5305
5306 /* note that we pass the htp context to the callback,
5307 * not the user supplied arguments. That is stored
5308 * within the context itself.
5309 */
5310 evhtp_set_gencb(htp, htp__default_request_cb_, (void *)htp);
5311
5312 *out = htp;
5313
5314 return 0;
5315}
5316
5317evhtp_t *
5318evhtp_new(struct event_base * evbase, void * arg)
5319{
5320 evhtp_t * htp;
5321
5322 if (evhtp__new_(&htp, evbase, arg) == -1) {
5323 return NULL;
5324 }
5325
5326 return htp;
5327}
5328
5329void
5331{
5332 evhtp_alias_t * evhtp_alias, * tmp;
5333
5334 if (evhtp == NULL) {
5335 return;
5336 }
5337
5338#ifndef EVHTP_DISABLE_EVTHR
5339 if (evhtp->thr_pool) {
5342 }
5343
5344#endif
5345
5346#ifndef EVHTP_DISABLE_SSL
5347 if (evhtp->ssl_ctx) {
5348 evhtp_safe_free(evhtp->ssl_ctx, SSL_CTX_free);
5349 }
5350
5351#endif
5352
5353 if (evhtp->server_name) {
5355 }
5356
5357 if (evhtp->callbacks) {
5359 }
5360
5361 TAILQ_FOREACH_SAFE(evhtp_alias, &evhtp->aliases, next, tmp) {
5362 if (evhtp_alias->alias != NULL) {
5364 }
5365
5366 TAILQ_REMOVE(&evhtp->aliases, evhtp_alias, next);
5368 }
5369
5371} /* evhtp_free */
5372
5373/*****************************************************************
5374* client request functions *
5375*****************************************************************/
5376
5377evhtp_connection_t *
5378evhtp_connection_new(struct event_base * evbase, const char * addr, uint16_t port)
5379{
5380 return evhtp_connection_new_dns(evbase, NULL, addr, port);
5381}
5382
5383evhtp_connection_t *
5384evhtp_connection_new_dns(struct event_base * evbase, struct evdns_base * dns_base,
5385 const char * addr, uint16_t port)
5386{
5387 evhtp_connection_t * conn;
5388 int err;
5389
5390 log_debug("Enter");
5391 evhtp_assert(evbase != NULL);
5392
5393 if (!(conn = htp__connection_new_(NULL, -1, evhtp_type_client))) {
5394 return NULL;
5395 }
5396
5397 conn->evbase = evbase;
5398 conn->bev = bufferevent_socket_new(evbase, -1, BEV_OPT_CLOSE_ON_FREE);
5399
5400 if (conn->bev == NULL) {
5402
5403 return NULL;
5404 }
5405
5406 bufferevent_enable(conn->bev, EV_READ);
5407 bufferevent_setcb(conn->bev, NULL, NULL,
5409
5410 if (dns_base != NULL) {
5411 err = bufferevent_socket_connect_hostname(conn->bev, dns_base,
5412 AF_UNSPEC, addr, port);
5413 } else {
5414 struct sockaddr_in sin4;
5415 struct sockaddr_in6 sin6;
5416 struct sockaddr * sin;
5417 int salen;
5418
5419 if (inet_pton(AF_INET, addr, &sin4.sin_addr)) {
5420 sin4.sin_family = AF_INET;
5421 sin4.sin_port = htons(port);
5422 sin = (struct sockaddr *)&sin4;
5423 salen = sizeof(sin4);
5424 } else if (inet_pton(AF_INET6, addr, &sin6.sin6_addr)) {
5425 sin6.sin6_family = AF_INET6;
5426 sin6.sin6_port = htons(port);
5427 sin = (struct sockaddr *)&sin6;
5428 salen = sizeof(sin6);
5429 } else {
5430 /* Not a valid IP. */
5432
5433 return NULL;
5434 }
5435
5436 err = bufferevent_socket_connect(conn->bev, sin, salen);
5437 }
5438
5439 /* not needed since any of the bufferevent errors will go straight to
5440 * the eventcb
5441 */
5442 if (err) {
5443 return NULL;
5444 }
5445
5446 return conn;
5447} /* evhtp_connection_new_dns */
5448
5449#ifndef EVHTP_DISABLE_SSL
5450
5451#define ssl_sk_new_ bufferevent_openssl_socket_new
5452#define ssl_sk_connect_ bufferevent_socket_connect
5453
5454evhtp_connection_t *
5455evhtp_connection_ssl_new(struct event_base * evbase,
5456 const char * addr,
5457 uint16_t port,
5458 evhtp_ssl_ctx_t * ctx)
5459{
5460 evhtp_connection_t * conn;
5461 struct sockaddr_in sin;
5462 const char * errstr;
5463
5464 if (evbase == NULL) {
5465 return NULL;
5466 }
5467
5468 if (!(conn = htp__connection_new_(NULL, -1, evhtp_type_client))) {
5469 return NULL;
5470 }
5471
5472 conn->evbase = evbase;
5473 errstr = NULL;
5474
5475 do {
5476 if ((conn->ssl = SSL_new(ctx)) == NULL) {
5477 errstr = "unable to allocate SSL context";
5478
5479 break;
5480 }
5481
5482 if ((conn->bev = ssl_sk_new_(evbase, -1, conn->ssl,
5483 BUFFEREVENT_SSL_CONNECTING,
5484 BEV_OPT_CLOSE_ON_FREE)) == NULL) {
5485 errstr = "unable to allocate bev context";
5486 break;
5487 }
5488
5489 if (bufferevent_enable(conn->bev, EV_READ) == -1) {
5490 errstr = "unable to enable reading";
5491 break;
5492 }
5493
5494 bufferevent_setcb(conn->bev, NULL, NULL,
5496
5497
5498 sin.sin_family = AF_INET;
5499 sin.sin_addr.s_addr = inet_addr(addr);
5500 sin.sin_port = htons(port);
5501
5502 if (ssl_sk_connect_(conn->bev,
5503 (struct sockaddr *)&sin,
5504 sizeof(sin)) == -1) {
5505 errstr = "sk_connect_ failure";
5506 break;
5507 }
5508 } while (0);
5509
5510
5511 if (errstr != NULL) {
5512 log_error("%s", errstr);
5513
5515
5516 return NULL;
5517 }
5518
5519 return conn;
5520} /* evhtp_connection_ssl_new */
5521
5522#endif
5523
5524
5525evhtp_request_t *
5527{
5528 evhtp_request_t * r;
5529
5530 r = htp__request_new_(NULL);
5532
5533 r->cb = cb;
5534 r->cbarg = arg;
5535 r->proto = EVHTP_PROTO_11;
5536
5537 return r;
5538}
5539
5540int
5541evhtp_make_request(evhtp_connection_t * c, evhtp_request_t * r,
5542 htp_method meth, const char * uri)
5543{
5544 struct evbuffer * obuf;
5545 char * proto;
5546
5547 obuf = bufferevent_get_output(c->bev);
5548 r->conn = c;
5549 r->method = meth;
5550 c->request = r;
5551
5552 switch (r->proto) {
5553 case EVHTP_PROTO_10:
5554 proto = "1.0";
5555 break;
5556 case EVHTP_PROTO_11:
5557 default:
5558 proto = "1.1";
5559 break;
5560 }
5561
5562 evbuffer_add_printf(obuf, "%s %s HTTP/%s\r\n",
5563 htparser_get_methodstr_m(meth), uri, proto);
5564
5565 if (evbuffer_get_length(r->buffer_out)) {
5566 if (evhtp_header_find(r->headers_out, "content-length") == NULL) {
5567 char out_buf[64] = { 0 };
5568 size_t out_len = evbuffer_get_length(r->buffer_out);
5569
5570 evhtp_modp_sizetoa(out_len, out_buf);
5571
5572 evhtp_headers_add_header(r->headers_out,
5573 evhtp_header_new("Content-Length", out_buf, 0, 1));
5574 }
5575 }
5576
5577 evhtp_headers_for_each(r->headers_out, htp__create_headers_, obuf);
5578 evbuffer_add_reference(obuf, "\r\n", 2, NULL, NULL);
5579
5580
5581 if (evbuffer_get_length(r->buffer_out)) {
5582 evbuffer_add_buffer(obuf, r->buffer_out);
5583 }
5584
5585 return 0;
5586} /* evhtp_make_request */
5587
5588unsigned int
5589evhtp_request_status(evhtp_request_t * r)
5590{
5591 return htparser_get_status(r->conn->parser);
5592}
#define EVHTP_PARSE_QUERY_FLAG_TREAT_SEMICOLON_AS_SEP
pthread_mutex_t evhtp_mutex_t
Definition evhtp/evhtp.h:73
#define EVHTP_CONN_FLAG_VHOST_VIA_SNI
set to 1 if the vhost was found via SSL SNI
#define EVHTP_PARSE_QUERY_FLAG_STRICT
#define EVHTP_PARSE_QUERY_FLAG_IGNORE_FRAGMENTS
#define EVHTP_CONN_FLAG_OWNER
set to 1 if this structure owns the bufferevent
#define EVHTP_RES_OK
unsigned char evhtp_ssl_data_t
Definition evhtp/evhtp.h:50
evhtp_res(* evhtp_hook_headers_start_cb)(evhtp_request_t *r, void *arg)
evhtp_res(* evhtp_hook_chunk_new_cb)(evhtp_request_t *r, uint64_t len, void *arg)
#define EVHTP_RES_FATAL
#define evhtp_headers_find_header
#define EVHTP_PARSE_QUERY_FLAG_ALLOW_EMPTY_VALS
evhtp_res(* evhtp_hook_hostname_cb)(evhtp_request_t *r, const char *hostname, void *arg)
#define evhtp_query_new
evhtp_res(* evhtp_hook_connection_fini_cb)(evhtp_connection_t *connection, void *arg)
struct evhtp_kvs evhtp_headers_t
Definition evhtp/evhtp.h:94
#define EVHTP_RES_ERROR
SSL_CTX evhtp_ssl_ctx_t
Definition evhtp/evhtp.h:46
#define EVHTP_CONN_FLAG_WAITING
used to make sure resuming happens AFTER sending a reply
evhtp_res(* evhtp_hook_conn_err_cb)(evhtp_connection_t *connection, evhtp_error_flags errtype, void *arg)
#define EVHTP_PARSE_QUERY_FLAG_IGNORE_HEX
evhtp_res(* evhtp_hook_request_fini_cb)(evhtp_request_t *req, void *arg)
#define EVHTP_CONN_FLAG_PAUSED
this connection has been marked as paused
SSL_SESSION evhtp_ssl_sess_t
Definition evhtp/evhtp.h:44
#define EVHTP_FLAG_DEFAULTS
evhtp_res(* evhtp_hook_path_cb)(evhtp_request_t *req, evhtp_path_t *path, void *arg)
#define EVHTP_FLAG_ENABLE_100_CONT
#define EVHTP_REQ_FLAG_CHUNKED
void(* evhtp_callback_cb)(evhtp_request_t *req, void *arg)
#define EVHTP_FLAG_ENABLE_NODELAY
#define evhtp_query_free
evhtp_res(* evhtp_post_accept_cb)(evhtp_connection_t *conn, void *arg)
evhtp_callback_type
@ evhtp_callback_type_glob
@ evhtp_callback_type_hash
@ evhtp_callback_type_regex
#define EVHTP_REQ_FLAG_FINISHED
#define EVHTP_PARSE_QUERY_FLAG_DEFAULT
evhtp_res(* evhtp_hook_chunks_fini_cb)(evhtp_request_t *r, void *arg)
#define EVHTP_PARSE_QUERY_FLAG_ALLOW_NULL_VALS
#define EVHTP_CONN_FLAG_FREE_CONN
#define evhtp_safe_free(_var, _freefn)
evhtp_hook_type
types associated with where a developer can hook into during the request processing cycle.
@ evhtp_hook_on_error
type which defines to hook whenever an error occurs
@ evhtp_hook_on_header
type which defines to hook after one header has been parsed
@ evhtp_hook_on_read
type which defines to hook whenever the parser recieves data in a body
@ evhtp_hook_on_new_chunk
@ evhtp_hook_on_chunk_complete
@ evhtp_hook_on_write
@ evhtp_hook_on_request_fini
type which defines to hook before the request is free'd
@ evhtp_hook_on_hostname
@ evhtp_hook_on_chunks_complete
@ evhtp_hook_on_event
@ evhtp_hook_on_conn_error
type which defines to hook whenever a connection error occurs
@ evhtp_hook_on_headers_start
@ evhtp_hook_on_path
type which defines to hook once a path has been parsed
@ evhtp_hook_on_connection_fini
@ evhtp_hook_on_headers
type which defines to hook after all headers have been parsed
@ evhtp_hook__max
SSL evhtp_ssl_t
Definition evhtp/evhtp.h:45
#define evhtp_request_content_len(r)
evhtp_res(* evhtp_hook_read_cb)(evhtp_request_t *req, struct evbuffer *buf, void *arg)
#define EVHTP_REQ_FLAG_ERROR
evhtp_res(* evhtp_hook_header_cb)(evhtp_request_t *req, evhtp_header_t *hdr, void *arg)
#define evhtp_headers_for_each
uint8_t evhtp_error_flags
Definition evhtp/evhtp.h:91
#define EVHTP_CONN_FLAG_KEEPALIVE
set to 1 after the first request has been processed and the connection is kept open
evhtp_res(* evhtp_hook)()
int(* evhtp_kvs_iterator)(evhtp_kv_t *kv, void *arg)
#define EVHTP_CONN_FLAG_ERROR
@ evhtp_ssl_scache_type_user
@ evhtp_ssl_scache_type_builtin
@ evhtp_ssl_scache_type_disabled
Definition evhtp/evhtp.h:98
#define EVHTP_RES_PAUSE
evhtp_res(* evhtp_hook_chunk_fini_cb)(evhtp_request_t *r, void *arg)
evhtp_res(* evhtp_hook_headers_cb)(evhtp_request_t *req, evhtp_headers_t *hdr, void *arg)
evhtp_res(* evhtp_pre_accept_cb)(evhtp_connection_t *conn, void *arg)
void(* evhtp_hook_err_cb)(evhtp_request_t *req, evhtp_error_flags errtype, void *arg)
void(* evhtp_thread_exit_cb)(evhtp_t *htp, evthr_t *thr, void *arg)
struct evhtp_kvs evhtp_kvs_t
Definition evhtp/evhtp.h:81
evhtp_proto
@ EVHTP_PROTO_10
@ EVHTP_PROTO_INVALID
@ EVHTP_PROTO_11
uint16_t evhtp_res
Definition evhtp/evhtp.h:90
evhtp_res(* evhtp_hook_write_cb)(evhtp_connection_t *conn, void *arg)
#define EVHTP_FLAG_ENABLE_REUSEPORT
void(* evhtp_thread_init_cb)(evhtp_t *htp, evthr_t *thr, void *arg)
#define EVHTP_FLAG_ENABLE_DEFER_ACCEPT
struct evhtp_kvs evhtp_query_t
Definition evhtp/evhtp.h:95
#define EVHTP_RES_DATA_TOO_LONG
evhtp_type
@ evhtp_type_server
@ evhtp_type_client
#define EVHTP_REQ_FLAG_KEEPALIVE
void(* evhtp_hook_event_cb)(evhtp_connection_t *conn, short events, void *arg)
struct evhtp_callbacks evhtp_callbacks_t
Definition evhtp/evhtp.h:78
#define EVHTP_CONN_FLAG_CONNECTED
client specific - set after successful connection
query_parser_state
Definition evhtp.c:3373
@ s_query_done
Definition evhtp.c:3382
@ s_query_val
Definition evhtp.c:3377
@ s_query_val_hex_1
Definition evhtp.c:3380
@ s_query_key_hex_2
Definition evhtp.c:3379
@ s_query_val_hex_2
Definition evhtp.c:3381
@ s_query_key
Definition evhtp.c:3376
@ s_query_start
Definition evhtp.c:3374
@ s_query_separator
Definition evhtp.c:3375
@ s_query_key_hex_1
Definition evhtp.c:3378
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.
Definition evhtp.c:4712
#define HTP_IS_WRITING(b)
Definition evhtp.c:79
void evhtp_kvs_add_kv(evhtp_kvs_t *kvs, evhtp_kv_t *kv)
appends a key/val structure to a evhtp_kvs_t tailq
Definition evhtp.c:3347
struct bufferevent * evhtp_connection_get_bev(evhtp_connection_t *connection)
returns the underlying connections bufferevent
Definition evhtp.c:4950
static int htp__request_parse_hostname_(htparser *p, const char *data, size_t len)
Definition evhtp.c:1623
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.
Definition evhtp.c:4186
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...
Definition evhtp.c:5050
evhtp_connection_t * evhtp_connection_ssl_new(struct event_base *evbase, const char *addr, uint16_t port, evhtp_ssl_ctx_t *ctx)
Definition evhtp.c:5455
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
Definition evhtp.c:3237
void evhtp_free(evhtp_t *evhtp)
Frees evhtp_t structure; will stop and free threads associated with the structure,...
Definition evhtp.c:5330
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.
Definition evhtp.c:5113
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
Definition evhtp.c:3092
static evhtp_t * htp__request_find_vhost_(evhtp_t *evhtp, const char *name)
Definition evhtp.c:1493
evhtp_t * evhtp_new(struct event_base *evbase, void *arg)
creates a new evhtp_t instance
Definition evhtp.c:5318
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.
Definition evhtp.c:5038
static void htp__thread_exit_(evthr_t *thr, void *arg)
Definition evhtp.c:4555
static evhtp_res htp__hook_connection_error_(struct evhtp_connection *connection, evhtp_error_flags errtype)
runs the user-defined hook when a connection error occurs
Definition evhtp.c:761
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
Definition evhtp.c:3785
static evhtp_res htp__hook_chunk_new_(struct evhtp_request *request, uint64_t len)
Runs the user defined request hook.
Definition evhtp.c:669
void evhtp_send_reply_end(evhtp_request_t *request)
Definition evhtp.c:3779
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.
Definition evhtp.c:4114
int evhtp_callback_set_hook(evhtp_callback_t *callback, evhtp_hook_type type, evhtp_hook cb, void *arg)
Definition evhtp.c:4392
unscape_state
Definition evhtp.c:3406
@ unscape_state_hex1
Definition evhtp.c:3408
@ unscape_state_start
Definition evhtp.c:3407
@ unscape_state_hex2
Definition evhtp.c:3409
void evhtp_send_reply_body(evhtp_request_t *request, struct evbuffer *buf)
Definition evhtp.c:3769
static void htp__request_free_(evhtp_request_t *request)
frees all data in an evhtp_request_t along with calling finished hooks
Definition evhtp.c:1217
struct bufferevent * evhtp_request_get_bev(evhtp_request_t *request)
returns the underlying requests bufferevent
Definition evhtp.c:4982
static int htp__request_parse_headers_start_(htparser *p)
Definition evhtp.c:1420
static evhtp_proto htp__protocol_(const char major, const char minor)
returns the HTTP protocol version
Definition evhtp.c:555
static evhtp_connection_t * htp__connection_new_(evhtp_t *htp, evutil_socket_t sock, evhtp_type type)
Definition evhtp.c:2704
const char * evhtp_header_find(evhtp_headers_t *headers, const char *key)
finds the value of a key in a evhtp_headers_t structure
Definition evhtp.c:3311
static evhtp_res htp__hook_headers_(struct evhtp_request *request, evhtp_headers_t *headers)
runs the user-defined on_Headers hook for a request after all headers have been parsed.
Definition evhtp.c:612
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
Definition evhtp.c:4489
TAILQ_HEAD(evhtp_callbacks, evhtp_callback)
static int htp__request_parse_headers_(htparser *p)
Definition evhtp.c:1789
static void htp__accept_cb_(struct evconnlistener *serv, int fd, struct sockaddr *s, int sl, void *arg)
Definition evhtp.c:2812
static void htp__thread_init_(evthr_t *thr, void *arg)
Definition evhtp.c:4545
int evhtp_callbacks_add_callback(evhtp_callbacks_t *cbs, evhtp_callback_t *cb)
Adds a evhtp_callback_t to the evhtp_callbacks_t list.
Definition evhtp.c:4283
static const char * status_code_to_str(evhtp_res code)
returns string status code from enum code
Definition evhtp.c:342
evhtp_request_t * evhtp_request_new(evhtp_callback_cb cb, void *arg)
allocate a new request
Definition evhtp.c:5526
evhtp_connection_t * evhtp_connection_new(struct event_base *evbase, const char *addr, uint16_t port)
allocate a new connection
Definition evhtp.c:5378
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
Definition evhtp.c:4705
static int htp__request_parse_header_val_(htparser *p, const char *data, size_t len)
Definition evhtp.c:1464
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.
Definition evhtp.c:3486
static unsigned long htp__ssl_get_thread_id_(void)
Definition evhtp.c:2876
static int session_id_context
Definition evhtp.c:445
static int htp__request_parse_chunk_fini_(htparser *p)
Definition evhtp.c:1881
#define HOOK_REQUEST_RUN_NARGS(__request, hook_name)
Definition evhtp.c:100
static char * htp__strndup_(const char *str, size_t len)
implementation of strndup function.
Definition evhtp.c:291
static int htp__path_new_(evhtp_path_t **out, const char *data, size_t len)
parses the path and file from an input buffer
Definition evhtp.c:985
static htparse_hooks request_psets
callback definitions for request processing from libhtparse
Definition evhtp.c:2193
void evhtp_request_resume(evhtp_request_t *request)
Wrapper around evhtp_connection_resume.
Definition evhtp.c:3084
void evhtp_connection_pause(evhtp_connection_t *c)
pauses a connection (disables reading)
Definition evhtp.c:3034
static evhtp_res htp__hook_header_(struct evhtp_request *request, evhtp_header_t *header)
runs the user-defined on_header hook for a request
Definition evhtp.c:595
static void htp__path_free_(struct evhtp_path *path)
Correctly frees the evhtp_path_t ptr that is passed in.
Definition evhtp.c:953
evhtp_connection_t * evhtp_request_get_connection(evhtp_request_t *request)
returns the underlying evhtp_connection_t structure from a request
Definition evhtp.c:5014
#define HTP_FLAG_FNGEN(NAME, TYPE)
Definition evhtp.c:5154
static void htp__ssl_thread_lock_(int mode, int type, const char *file, int line)
Definition evhtp.c:2892
static int htp__require_uri_(evhtp_connection_t *c)
Definition evhtp.c:1677
int evhtp_bind_sockaddr(evhtp_t *htp, struct sockaddr *sa, size_t sin_len, int backlog)
bind to an already allocated sockaddr.
Definition evhtp.c:4047
void evhtp_callbacks_free(evhtp_callbacks_t *callbacks)
Definition evhtp.c:4167
static void htp__uri_free_(evhtp_uri_t *uri)
frees an overlay URI structure
Definition evhtp.c:1167
int evhtp_ssl_use_threads(void)
Definition evhtp.c:4728
static int htp__request_parse_chunk_new_(htparser *p)
Definition evhtp.c:1864
static evhtp_request_t * htp__request_new_(evhtp_connection_t *c)
Creates a new evhtp_request_t.
Definition evhtp.c:1253
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.
Definition evhtp.c:5232
#define htp__unlock_(h)
Helper macro to unlock htp lock.
Definition evhtp.c:128
static void(* free_)(void *d)
Definition evhtp.c:168
static size_t htp__evbuffer_add_iovec_(struct evbuffer *buf, struct evbuffer_iovec *vec, int n_vec)
Definition evhtp.c:2017
static evhtp_res htp__hook_chunks_fini_(struct evhtp_request *request)
Runs the user defined on chunk_finis hook.
Definition evhtp.c:697
static int htp__run_pre_accept_(evhtp_t *htp, evhtp_connection_t *conn)
Definition evhtp.c:2606
static void htp__connection_eventcb_(struct bufferevent *bev, short events, void *arg)
Definition evhtp.c:2452
static int htp__ssl_servername_(evhtp_ssl_t *ssl, int *unused, void *arg)
Definition evhtp.c:2972
static int htp__request_parse_fini_(htparser *p)
Definition evhtp.c:1958
static int htp__request_parse_body_(htparser *p, const char *data, size_t len)
Definition evhtp.c:1829
static evhtp_ssl_sess_t * htp__ssl_get_scache_ent_(evhtp_ssl_t *ssl, evhtp_ssl_data_t *sid, int sid_len, int *copy)
Definition evhtp.c:2947
static int ssl_locks_initialized
Definition evhtp.c:449
void evhtp_send_reply_start(evhtp_request_t *request, evhtp_res code)
Definition evhtp.c:3752
static int evhtp_is_hex_query_char(unsigned char ch)
Definition evhtp.c:3386
int evhtp_add_aliases(evhtp_t *htp, const char *name,...)
set a variable number of aliases in one call @reference evhtp_add_alias
Definition evhtp.c:5205
static int htp__request_parse_chunks_fini_(htparser *p)
Definition evhtp.c:1897
#define _HTP_tid
Definition evhtp.c:2869
void evhtp_kvs_free(evhtp_kvs_t *kvs)
frees a the list of key/values, and all underlying entries
Definition evhtp.c:3249
void evhtp_send_reply_chunk(evhtp_request_t *request, struct evbuffer *buf)
send a chunk reply.
Definition evhtp.c:3888
#define HTP_LEN_INPUT(b)
Definition evhtp.c:83
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...
Definition evhtp.c:4670
static evhtp_res htp__hook_request_fini_(struct evhtp_request *request)
runs the user-defined hook called just prior to a request been free()'d
Definition evhtp.c:650
static void htp__ssl_delete_scache_ent_(evhtp_ssl_ctx_t *ctx, evhtp_ssl_sess_t *sess)
Definition evhtp.c:2905
void evhtp_request_free(evhtp_request_t *request)
Definition evhtp.c:5103
#define HTP_IS_READING(b)
Definition evhtp.c:77
static evhtp_res htp__hook_headers_start_(struct evhtp_request *request)
Runs the user defined on_headers_start hook.
Definition evhtp.c:711
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.
Definition evhtp.c:3997
int evhtp_connection_unset_hook(evhtp_connection_t *conn, evhtp_hook_type type)
Definition evhtp.c:4386
void evhtp_set_mem_functions(void *(*mallocfn_)(size_t len), void *(*reallocfn_)(void *p, size_t sz), void(*freefn_)(void *p))
Definition evhtp.c:321
static int htp__glob_match_(const char *pattern, size_t plen, const char *string, size_t str_len)
glob/wildcard type pattern matching.
Definition evhtp.c:817
static int htp__unset_hook_(evhtp_hooks_t **hooks, evhtp_hook_type type)
Definition evhtp.c:4368
static int htp__request_parse_start_(htparser *p)
Starts the parser for the connection associated with the parser struct.
Definition evhtp.c:1306
static int htp__request_set_callbacks_(evhtp_request_t *request)
Definition evhtp.c:1526
static int htp__connection_accept_(struct event_base *evbase, evhtp_connection_t *connection)
Definition evhtp.c:2626
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}'.
Definition evhtp.c:3413
void evhtp_kv_free(evhtp_kv_t *kv)
frees resources allocated for a single key/value
Definition evhtp.c:3219
static int htp__request_parse_args_(htparser *p, const char *data, size_t len)
parses http request arguments
Definition evhtp.c:1352
#define HTP_LEN_OUTPUT(b)
Definition evhtp.c:82
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'
Definition evhtp.c:3329
static evhtp_res htp__hook_path_(struct evhtp_request *request, struct evhtp_path *path)
runs the user-defined on_path hook for a request
Definition evhtp.c:577
void evhtp_send_reply_chunk_start(evhtp_request_t *request, evhtp_res code)
start a chunked response.
Definition evhtp.c:3820
#define htp__is_http_10_(_major, _minor)
helper function to determine if http version is HTTP/1.1
Definition evhtp.c:541
void evhtp_set_max_keepalive_requests(evhtp_t *htp, uint64_t num)
sets a maximum number of requests that a single connection can make.
Definition evhtp.c:5125
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.
Definition evhtp.c:4719
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.
Definition evhtp.c:3913
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.
Definition evhtp.c:4956
void evhtp_set_bev_flags(evhtp_t *htp, int flags)
bufferevent flags which will be used for bev sockets.
Definition evhtp.c:5131
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.
Definition evhtp.c:3745
#define htp__is_http_11_(_major, _minor)
helper macro to determine if http version is HTTP/1.0
Definition evhtp.c:529
static evhtp_res htp__hook_chunk_fini_(struct evhtp_request *request)
Runs the user defined on_chunk_fini hook.
Definition evhtp.c:683
evhtp_hooks_t * evhtp_connection_get_hooks(evhtp_connection_t *c)
Definition evhtp.c:4451
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
Definition evhtp.c:5384
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.
Definition evhtp.c:5149
static void htp__connection_readcb_(struct bufferevent *bev, void *arg)
Definition evhtp.c:2215
int evhtp_use_callback_locks(evhtp_t *htp)
creates a lock around callbacks and hooks, allowing for threaded applications to add/remove/modify ho...
Definition evhtp.c:4613
static void htp__free_(void *ptr)
Wrapper for free so that a different free can be used if desired.
Definition evhtp.c:213
#define htp__lock_(h)
Helper macro to lock htp structure.
Definition evhtp.c:117
static int htp__request_parse_header_key_(htparser *p, const char *data, size_t len)
Definition evhtp.c:1432
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
Definition evhtp.c:3323
static int evhtp__new_(evhtp_t **out, struct event_base *evbase, void *arg)
Allocates new evhtp_t structure.
Definition evhtp.c:5279
static char * htp__strdup_(const char *str)
implementation of strdup function.
Definition evhtp.c:261
static int htp__create_headers_(evhtp_header_t *header, void *arg)
Definition evhtp.c:2045
void evhtp_callback_free(evhtp_callback_t *callback)
safely frees callback structure memory and internals
Definition evhtp.c:4253
static evhtp_res htp__hook_body_(struct evhtp_request *request, struct evbuffer *buf)
runs the user-defined on_body hook for requests containing a body.
Definition evhtp.c:630
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 .
Definition evhtp.c:4405
static struct evbuffer * htp__create_reply_(evhtp_request_t *request, evhtp_res code)
Definition evhtp.c:2061
evhtp_proto evhtp_request_get_proto(evhtp_request_t *request)
Definition evhtp.c:5020
const char * evhtp_kv_find(evhtp_kvs_t *kvs, const char *key)
find the string value of 'key' from the key/value list 'kvs'
Definition evhtp.c:3293
static int htp__request_parse_path_(htparser *p, const char *data, size_t len)
Definition evhtp.c:1752
void evhtp_request_pause(evhtp_request_t *request)
Wrapper around evhtp_connection_pause.
Definition evhtp.c:3075
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'
Definition evhtp.c:3273
#define HTP_FLAG_ON(PRE, FLAG)
Definition evhtp.c:74
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.
Definition evhtp.c:4601
int evhtp_request_unset_hook(evhtp_request_t *req, evhtp_hook_type type)
Definition evhtp.c:4380
static void htp__default_request_cb_(evhtp_request_t *request, void *arg)
Definition evhtp.c:2696
int evhtp_response_needs_body(const evhtp_res code, const htp_method method)
Determine if a response should have a body.
Definition evhtp.c:3811
evhtp_kv_t * evhtp_kv_new(const char *key, const char *val, char key_alloc, char val_alloc)
Allocates a new key/value structure.
Definition evhtp.c:3156
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
Definition evhtp.c:3317
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.
Definition evhtp.c:4594
static evhtp_res htp__hook_connection_write_(struct evhtp_connection *connection)
Runs the user defined on_write hook.
Definition evhtp.c:796
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
Definition evhtp.c:4630
#define ssl_sk_connect_
Definition evhtp.c:5452
const char * evhtp_request_get_status_code_str(evhtp_request_t *request)
wrapper around get_status_code that returns the string version of the last status code set for a requ...
Definition evhtp.c:5032
void evhtp_unbind_socket(evhtp_t *htp)
stops the listening socket.
Definition evhtp.c:3924
static int htp__request_parse_host_(htparser *p, const char *data, size_t len)
Definition evhtp.c:1691
void evhtp_connection_resume(evhtp_connection_t *c)
resumes a connection (enables reading) and activates resume event.
Definition evhtp.c:3056
unsigned int evhtp_request_status(evhtp_request_t *r)
Definition evhtp.c:5589
evhtp_hooks_t * evhtp_callback_get_hooks(evhtp_callback_t *cb)
returns callback hooks
Definition evhtp.c:4483
static evhtp_res htp__hook_hostname_(struct evhtp_request *r, const char *hostname)
Runs the user defined hostname processing hook.
Definition evhtp.c:782
static evhtp_res htp__hook_connection_fini_(struct evhtp_connection *connection)
runs the user-definedhook called just prior to a connection being closed
Definition evhtp.c:727
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.
Definition evhtp.c:5060
static int htp__ssl_add_scache_ent_(evhtp_ssl_t *ssl, evhtp_ssl_sess_t *sess)
Definition evhtp.c:2922
int evhtp_unset_all_hooks(evhtp_hooks_t **hooks)
removes all hooks.
Definition evhtp.c:4412
static evhtp_mutex_t * ssl_locks
Definition evhtp.c:448
static void htp__connection_resumecb_(int fd, short events, void *arg)
Definition evhtp.c:2551
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.
Definition evhtp.c:883
static void htp__hook_error_(struct evhtp_request *request, evhtp_error_flags errtype)
runs the user-defined hook when a connection error occurs
Definition evhtp.c:747
static int ssl_num_locks
Definition evhtp.c:447
static void htp__connection_writecb_(struct bufferevent *bev, void *arg)
Definition evhtp.c:2296
static void * htp__malloc_(size_t size)
Wrapper for malloc so that a different malloc can be used if desired.
Definition evhtp.c:181
#define HTP_FLAG_OFF(PRE, FLAG)
Definition evhtp.c:75
static void * htp__realloc_(void *ptr, size_t size)
Wrapper for realloc so that a different realloc can be used if desired.
Definition evhtp.c:198
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 ...
Definition evhtp.c:5066
void evhtp_connection_set_bev(evhtp_connection_t *conn, struct bufferevent *bev)
Sets the connections underlying bufferevent.
Definition evhtp.c:4994
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
Definition evhtp.c:3106
#define ssl_sk_new_
Definition evhtp.c:5451
int evhtp_callback_unset_hook(evhtp_callback_t *callback, evhtp_hook_type type)
Definition evhtp.c:4374
#define HOOK_REQUEST_RUN(request, hook_name,...)
Definition evhtp.c:89
static void *(* realloc_)(void *d, size_t sz)
Definition evhtp.c:167
static void * htp__calloc_(size_t nmemb, size_t size)
Wrapper for calloc so that a different calloc can be used if desired.
Definition evhtp.c:234
static int htp__use_threads_(evhtp_t *htp, evhtp_thread_init_cb init_cb, evhtp_thread_exit_cb exit_cb, int nthreads, void *arg)
Definition evhtp.c:4565
void evhtp_kvs_add_kvs(evhtp_kvs_t *dst, evhtp_kvs_t *src)
appends all key/val structures from src tailq onto dst tailq
Definition evhtp.c:3357
void evhtp_disable_100_continue(evhtp_t *htp)
Definition evhtp.c:5143
evhtp_hooks_t * evhtp_request_get_hooks(evhtp_request_t *r)
returns request hooks
Definition evhtp.c:4467
static int htp__serv_setsockopts_(evhtp_t *htp, evutil_socket_t sock)
Definition evhtp.c:3934
evhtp_callback_t * evhtp_get_cb(evhtp_t *htp, const char *path)
attempts to find the callback matching the exact string 'needle'.
Definition evhtp.c:4524
static void htp__authority_free_(evhtp_authority_t *authority)
frees an authority structure
Definition evhtp.c:1148
static int htp__authority_new_(evhtp_authority_t **out)
create an authority structure
Definition evhtp.c:1129
static int htp__set_hook_(evhtp_hooks_t **hooks, evhtp_hook_type type, evhtp_hook cb, void *arg)
Definition evhtp.c:4291
struct bufferevent * evhtp_request_take_ownership(evhtp_request_t *request)
Definition evhtp.c:4988
void evhtp_request_set_keepalive(evhtp_request_t *request, int val)
Definition evhtp.c:5006
int evhtp_add_alias(evhtp_t *evhtp, const char *name)
Add an alias hostname for a virtual-host specific evhtp_t.
Definition evhtp.c:5177
htp_method evhtp_request_get_method(evhtp_request_t *r)
returns the htp_method enum version of the request method.
Definition evhtp.c:3024
int evhtp_make_request(evhtp_connection_t *c, evhtp_request_t *r, htp_method meth, const char *uri)
make a client request
Definition evhtp.c:5541
static void *(* malloc_)(size_t sz)
Definition evhtp.c:166
int evhtp_request_set_hook(evhtp_request_t *req, evhtp_hook_type type, evhtp_hook cb, void *arg)
Definition evhtp.c:4399
void evhtp_request_set_bev(evhtp_request_t *request, struct bufferevent *bev)
sets the underlying bufferevent for a evhtp_request
Definition evhtp.c:5000
static void htp__run_in_thread_(evthr_t *thr, void *arg, void *shared)
Definition evhtp.c:2788
static int htp__should_parse_query_body_(evhtp_request_t *req)
determines if the request body contains the query arguments.
Definition evhtp.c:1923
static int htp__run_post_accept_(evhtp_t *htp, evhtp_connection_t *connection)
Definition evhtp.c:2767
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.
Definition evhtp.c:5137
evhtp_res evhtp_request_get_status_code(evhtp_request_t *request)
Returns the last status code set for a request (request/response)
Definition evhtp.c:5026
static int htp__uri_new_(evhtp_uri_t **out)
create an overlay URI structure
Definition evhtp.c:1189
int evhtp_ssl_init(evhtp_t *htp, evhtp_ssl_cfg_t *cfg)
Definition evhtp.c:4762
static int htp__request_parse_port_(htparser *p, const char *data, size_t len)
Definition evhtp.c:1726
evhtp_kvs_t * evhtp_kvs_new(void)
creates an empty list of key/values
Definition evhtp.c:3140
#define log_warn(M,...)
Definition internal.h:67
#define log_error(M,...)
Definition internal.h:57
#define TAILQ_FOREACH_SAFE(var, head, field, tvar)
Definition internal.h:22
#define evhtp_alloc_assert(x)
Definition internal.h:93
#define log_debug(M,...)
Definition internal.h:47
#define evhtp_assert(x)
Definition internal.h:83
#define evhtp_unlikely(x)
Definition internal.h:18
#define evhtp_likely(x)
Definition internal.h:17
#define evhtp_modp_uchartoa(_val)
Definition numtoa.h:43
EVHTP_EXPORT size_t evhtp_modp_u32toa(uint32_t value, char *str)
converts uint32_t value to string
EVHTP_EXPORT size_t evhtp_modp_sizetoa(size_t value, char *str)
based on the system architecture, convert a size_t number to a string.
htpparse_error htparser_get_error(htparser *p)
Definition parser.c:426
size_t htparser_run(htparser *p, htparse_hooks *hooks, const char *data, size_t len)
Definition parser.c:723
htp_method htparser_get_method(htparser *p)
Definition parser.c:480
htparser * htparser_new(void)
Definition parser.c:581
void htparser_set_major(htparser *p, unsigned char major)
Definition parser.c:503
void * htparser_get_userdata(htparser *p)
Definition parser.c:533
int htparser_should_keep_alive(htparser *p)
Definition parser.c:451
unsigned char htparser_get_minor(htparser *p)
Definition parser.c:521
htp_scheme htparser_get_scheme(htparser *p)
Definition parser.c:474
void htparser_init(htparser *p, htp_type type)
Definition parser.c:569
uint64_t htparser_get_content_length(htparser *p)
Definition parser.c:551
void htparser_set_minor(htparser *p, unsigned char minor)
Definition parser.c:509
unsigned char htparser_get_major(htparser *p)
Definition parser.c:515
unsigned int htparser_get_status(htparser *p)
Definition parser.c:445
unsigned char htparser_get_multipart(htparser *p)
Definition parser.c:527
void htparser_set_userdata(htparser *p, void *ud)
Definition parser.c:539
const char * htparser_get_methodstr_m(htp_method meth)
Definition parser.c:486
structure which represents authority information in a URI
structure containing a single callback and configuration
Definition evhtp.c:51
char * path
Definition evhtp.c:59
size_t len
Definition evhtp.c:56
void * cbarg
user-defind arguments passed to the cb
Definition evhtp.c:54
evhtp_callback_type type
the type of callback (regex|path)
Definition evhtp.c:52
union evhtp_callback::@0 val
regex_t * regex
Definition evhtp.c:62
evhtp_hooks_t * hooks
per-callback hooks
Definition evhtp.c:55
char * glob
Definition evhtp.c:60
evhtp_callback_cb cb
the actual callback function
Definition evhtp.c:53
evhtp_request_t * request
the request currently being processed
evhtp_hooks_t * hooks
structure which represents a URI path and or file
char * file
the filename if present (c.html)
char * match_start
char * full
the full path+file (/a/b/c.html)
char * match_end
char * path
the path (/a/b/)
a structure containing all information for a http request.
struct evbuffer * buffer_in
buffer containing data from client
void * cbarg
argument which is passed to the cb function
evhtp_uri_t * uri
request URI information
struct evbuffer * buffer_out
buffer containing data to client
evhtp_headers_t * headers_out
headers to client
evhtp_headers_t * headers_in
headers from client
evhtp_t * htp
the parent evhtp_t structure
evhtp_hooks_t * hooks
request specific hooks
evhtp_res status
The HTTP response code or other error conditions.
evhtp_connection_t * conn
the associated connection
a generic container representing an entire URI strucutre
evhtp_authority_t * authority
main structure containing all configuration information
char * server_name
the name included in Host: responses
evthr_pool_t * thr_pool
connection threadpool
struct timeval send_timeo
int bev_flags
bufferevent flags to use on bufferevent_*_socket_new()
struct timeval recv_timeo
evhtp_ssl_ctx_t * ssl_ctx
if ssl enabled, this is the servers CTX
uint64_t max_keepalive_requests
uint64_t max_body_size
evhtp_callbacks_t * callbacks
evhtp_defaults_t defaults
void evthr_pool_free(evthr_pool_t *pool)
Definition thread.c:316
evthr_pool_t * evthr_pool_wexit_new(int nthreads, evthr_init_cb init_cb, evthr_exit_cb exit_cb, void *shared)
Definition thread.c:468
evthr_cb cb
Definition thread.c:2
evbase_t * evthr_get_base(evthr_t *thr)
Definition thread.c:176
evthr_res evthr_pool_defer(evthr_pool_t *pool, evthr_cb cb, void *arg)
Definition thread.c:362
void * args
Definition thread.c:1
int evthr_pool_start(evthr_pool_t *pool)
Definition thread.c:476
evthr_res evthr_pool_stop(evthr_pool_t *pool)
Definition thread.c:335