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 
69 TAILQ_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 
166 static void * (*malloc_)(size_t sz) = malloc;
167 static void * (* realloc_)(void * d, size_t sz) = realloc;
168 static void (* free_)(void * d) = free;
169 
180 static void *
181 htp__malloc_(size_t size)
182 {
183  return malloc_(size);
184 }
185 
197 static void *
198 htp__realloc_(void * ptr, size_t size)
199 {
200  return realloc_(ptr, size);
201 }
202 
212 static void
213 htp__free_(void * ptr)
214 {
215  if (ptr == NULL) {
216  return;
217  }
218 
219  evhtp_safe_free(ptr, free_);
220 }
221 
233 static void *
234 htp__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 
260 static char *
261 htp__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 
290 static char *
291 htp__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 
320 void
321 evhtp_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 
341 static 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
445 static int session_id_context = 1;
446 #ifndef EVHTP_DISABLE_EVTHR
447 static int ssl_num_locks;
449 static int ssl_locks_initialized = 0;
450 #endif
451 #endif
452 
453 /*
454  * COMPAT FUNCTIONS
455  */
456 
457 #ifdef NO_STRNLEN
467 static size_t
468 strnlen(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
492 static char *
493 strndup(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 
554 static inline evhtp_proto
555 htp__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 
576 static inline evhtp_res
577 htp__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 
594 static inline evhtp_res
595 htp__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 
611 static inline evhtp_res
613 {
614  HOOK_REQUEST_RUN(request, on_headers, headers);
615 
616  return EVHTP_RES_OK;
617 }
618 
629 static inline evhtp_res
630 htp__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 
649 static 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 
668 static inline evhtp_res
669 htp__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 
682 static inline evhtp_res
684 {
685  HOOK_REQUEST_RUN_NARGS(request, on_chunk_fini);
686 
687  return EVHTP_RES_OK;
688 }
689 
696 static inline evhtp_res
698 {
699  HOOK_REQUEST_RUN_NARGS(request, on_chunks_fini);
700 
701  return EVHTP_RES_OK;
702 }
703 
710 static inline evhtp_res
712 {
713  HOOK_REQUEST_RUN_NARGS(request, on_headers_start);
714 
715  return EVHTP_RES_OK;
716 }
717 
726 static 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 
746 static inline void
748 {
749  if (request && request->hooks && request->rh_err) {
750  (*request->rh_err)(request, errtype, request->rh_err_arg);
751  }
752 }
753 
760 static 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 
781 static inline evhtp_res
782 htp__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 
795 static 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 
816 static int
817 htp__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 
882 static 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 
952 static void
954 {
955  if (evhtp_unlikely(path == NULL)) {
956  return;
957  }
958 
964 
966 }
967 
984 static int
985 htp__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;
1115 error:
1118  evhtp_safe_free(req_path, htp__path_free_);
1119 
1120  return -1;
1121 } /* htp__path_new_ */
1122 
1128 static int
1129 htp__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 
1147 static void
1148 htp__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 
1166 static void
1167 htp__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 
1188 static int
1189 htp__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 
1216 static void
1217 htp__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 
1252 static evhtp_request_t *
1253 htp__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 
1305 static 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) {
1328  evhtp_safe_free(c->request, htp__request_free_);
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 
1351 static int
1352 htp__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 
1419 static 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 
1431 static int
1432 htp__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 
1463 static int
1464 htp__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) {
1477  evhtp_safe_free(val_s, htp__free_);
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 
1492 static inline evhtp_t *
1493 htp__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 
1525 static inline int
1526 htp__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 
1622 static int
1623 htp__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  */
1651  htp__lock_(evhtp);
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 
1676 static int
1677 htp__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 
1690 static int
1691 htp__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 
1725 static int
1726 htp__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 
1751 static int
1752 htp__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 
1788 static 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 
1828 static int
1829 htp__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 
1863 static 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 
1880 static 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 
1896 static 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 
1922 static int
1923 htp__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 
1957 static 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 
2016 static size_t
2017 htp__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 
2044 static int
2045 htp__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 
2060 static struct evbuffer *
2061 htp__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 
2107 check_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 
2193 static htparse_hooks request_psets = {
2194  .on_msg_begin = htp__request_parse_start_,
2195  .method = NULL,
2196  .scheme = NULL,
2197  .host = htp__request_parse_host_,
2198  .port = htp__request_parse_port_,
2199  .path = htp__request_parse_path_,
2200  .args = htp__request_parse_args_,
2201  .uri = NULL,
2202  .on_hdrs_begin = htp__request_parse_headers_start_,
2203  .hdr_key = htp__request_parse_header_key_,
2204  .hdr_val = htp__request_parse_header_val_,
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_,
2210  .body = htp__request_parse_body_,
2211  .on_msg_complete = htp__request_parse_fini_
2212 };
2213 
2214 static void
2215 htp__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 
2295 static void
2296 htp__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 
2451 static void
2452 htp__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 
2550 static void
2551 htp__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 
2605 static int
2606 htp__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 
2625 static int
2626 htp__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
2658 end:
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 
2695 static void
2696 htp__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 
2703 static evhtp_connection_t *
2704 htp__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
2758 static void
2759 htp__shutdown_eventcb_(struct bufferevent * bev, short events, void * arg)
2760 {
2761 }
2762 
2763 #endif
2764 #endif
2765 
2766 static int
2767 htp__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
2787 static void
2788 htp__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 
2811 static void
2812 htp__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
2875 static unsigned long
2877 {
2878  return _HTP_tid;
2879 }
2880 
2881 #else
2882 
2883 static void
2884 htp__ssl_get_thread_id_(CRYPTO_THREADID * id)
2885 {
2886  CRYPTO_THREADID_set_numeric(id, _HTP_tid);
2887 }
2888 
2889 #endif
2890 
2891 static void
2892 htp__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
2904 static 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 
2921 static 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 
2946 static evhtp_ssl_sess_t *
2947 htp__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 
2971 static int
2972 htp__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 
3023 htp_method
3024 evhtp_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 
3033 void
3034 evhtp_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 
3055 void
3056 evhtp_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 
3074 void
3075 evhtp_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 
3083 void
3084 evhtp_request_resume(evhtp_request_t * request)
3085 {
3086  evhtp_assert(request != NULL);
3087 
3088  evhtp_connection_resume(request->conn);
3089 }
3090 
3091 evhtp_header_t *
3092 evhtp_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 
3105 evhtp_header_t *
3106 evhtp_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 
3139 evhtp_kvs_t *
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 
3155 evhtp_kv_t *
3156 evhtp_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 
3218 void
3219 evhtp_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 
3236 void
3237 evhtp_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 
3248 void
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 
3272 int
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 
3292 const char *
3293 evhtp_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 
3310 const char *
3311 evhtp_header_find(evhtp_headers_t * headers, const char * key)
3312 {
3313  return evhtp_kv_find(headers, key);
3314 }
3315 
3316 void
3317 evhtp_headers_add_header(evhtp_headers_t * headers, evhtp_header_t * header)
3318 {
3319  return evhtp_kvs_add_kv(headers, header);
3320 }
3321 
3322 evhtp_header_t *
3323 evhtp_header_new(const char * key, const char * val, char kalloc, char valloc)
3324 {
3325  return evhtp_kv_new(key, val, kalloc, valloc);
3326 }
3327 
3328 evhtp_kv_t *
3329 evhtp_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 
3346 void
3347 evhtp_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 
3356 void
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 
3373 typedef enum {
3382  s_query_done
3384 
3385 static inline int
3386 evhtp_is_hex_query_char(unsigned char ch)
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 
3410 };
3411 
3412 int
3413 evhtp_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) {
3432  case unscape_state_start:
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 
3485 evhtp_query_t *
3486 evhtp_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 */
3571  if (!(flags & EVHTP_PARSE_QUERY_FLAG_ALLOW_NULL_VALS)) {
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) {
3711  if (!(flags & EVHTP_PARSE_QUERY_FLAG_ALLOW_EMPTY_VALS)) {
3712  goto error;
3713  }
3714 
3715  evhtp_kvs_add_kv(query_args, evhtp_kv_new(key_buf, "", 1, 1));
3716  break;
3717  }
3718 
3719  if (!(flags & EVHTP_PARSE_QUERY_FLAG_ALLOW_NULL_VALS)) {
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;
3733 error:
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 
3744 evhtp_query_t *
3745 evhtp_parse_query(const char * query, size_t len)
3746 {
3747  return evhtp_parse_query_wflags(query, len,
3749 }
3750 
3751 void
3752 evhtp_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 
3768 void
3769 evhtp_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 
3778 void
3779 evhtp_send_reply_end(evhtp_request_t * request)
3780 {
3782 }
3783 
3784 void
3785 evhtp_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 
3810 int
3811 evhtp_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 
3819 void
3820 evhtp_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 
3883 end:
3884  evhtp_send_reply_start(request, code);
3885 } /* evhtp_send_reply_chunk_start */
3886 
3887 void
3888 evhtp_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 
3912 void
3913 evhtp_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 
3923 void
3924 evhtp_unbind_socket(evhtp_t * htp)
3925 {
3926  if (htp == NULL || htp->server == NULL) {
3927  return;
3928  }
3929 
3930  evhtp_safe_free(htp->server, evconnlistener_free);
3931 }
3932 
3933 static int
3934 htp__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 
3996 int
3997 evhtp_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 
4046 int
4047 evhtp_bind_sockaddr(evhtp_t * htp,
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 
4113 int
4114 evhtp_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 
4166 void
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 
4185 evhtp_callback_t *
4186 evhtp_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 
4252 void
4253 evhtp_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 
4282 int
4284 {
4285  TAILQ_INSERT_TAIL(cbs, cb, next);
4286 
4287  return 0;
4288 }
4289 
4290 static int
4291 htp__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;
4304  case evhtp_hook_on_header:
4305  (*hooks)->on_header = (evhtp_hook_header_cb)cb;
4306  (*hooks)->on_header_arg = arg;
4307  break;
4308  case evhtp_hook_on_headers:
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;
4332  case evhtp_hook_on_error:
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;
4352  case evhtp_hook_on_write:
4353  (*hooks)->on_write = (evhtp_hook_write_cb)cb;
4354  (*hooks)->on_write_arg = arg;
4355  break;
4356  case evhtp_hook_on_event:
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 
4367 static int
4368 htp__unset_hook_(evhtp_hooks_t ** hooks, evhtp_hook_type type)
4369 {
4370  return htp__set_hook_(hooks, type, NULL, NULL);
4371 }
4372 
4373 int
4374 evhtp_callback_unset_hook(evhtp_callback_t * callback, evhtp_hook_type type)
4375 {
4376  return htp__unset_hook_(&callback->hooks, type);
4377 }
4378 
4379 int
4380 evhtp_request_unset_hook(evhtp_request_t * req, evhtp_hook_type type)
4381 {
4382  return htp__unset_hook_(&req->hooks, type);
4383 }
4384 
4385 int
4386 evhtp_connection_unset_hook(evhtp_connection_t * conn, evhtp_hook_type type)
4387 {
4388  return htp__unset_hook_(&conn->hooks, type);
4389 }
4390 
4391 int
4392 evhtp_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 
4398 int
4399 evhtp_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 
4404 int
4405 evhtp_connection_set_hook(evhtp_connection_t * conn, evhtp_hook_type type, evhtp_hook cb,
4406  void * arg)
4407 {
4408  return htp__set_hook_(&conn->hooks, type, cb, arg);
4409 }
4410 
4411 int
4412 evhtp_unset_all_hooks(evhtp_hooks_t ** hooks)
4413 {
4414  int i;
4415 
4416  struct {
4417  enum evhtp_hook_type type;
4418  } hooklist_[] = {
4421  { evhtp_hook_on_path },
4422  { evhtp_hook_on_read },
4429  { evhtp_hook_on_error },
4431  { evhtp_hook_on_write },
4432  { evhtp_hook_on_event },
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 
4450 evhtp_hooks_t *
4451 evhtp_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 
4466 evhtp_hooks_t *
4467 evhtp_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 
4482 evhtp_hooks_t *
4483 evhtp_callback_get_hooks(evhtp_callback_t * cb)
4484 {
4485  return cb->hooks;
4486 }
4487 
4488 evhtp_callback_t *
4489 evhtp_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 
4523 evhtp_callback_t *
4524 evhtp_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
4544 static void
4545 htp__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 
4554 static void
4555 htp__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 
4564 static int
4565 htp__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 
4593 int
4595  int nthreads, void * arg)
4596 {
4597  return htp__use_threads_(htp, init_cb, NULL, nthreads, arg);
4598 }
4599 
4600 int
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
4612 int
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
4629 evhtp_callback_t *
4630 evhtp_set_regex_cb(evhtp_t * htp,
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 
4669 evhtp_callback_t *
4670 evhtp_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 
4704 void
4705 evhtp_set_gencb(evhtp_t * htp, evhtp_callback_cb cb, void * arg)
4706 {
4707  htp->defaults.cb = cb;
4708  htp->defaults.cbarg = arg;
4709 }
4710 
4711 void
4713 {
4714  htp->defaults.pre_accept = cb;
4715  htp->defaults.pre_accept_cbarg = arg;
4716 }
4717 
4718 void
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
4727 int
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 
4761 int
4762 evhtp_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 
4949 struct bufferevent *
4950 evhtp_connection_get_bev(evhtp_connection_t * connection)
4951 {
4952  return connection->bev;
4953 }
4954 
4955 struct bufferevent *
4956 evhtp_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  */
4973  HTP_FLAG_OFF(connection, EVHTP_CONN_FLAG_OWNER);
4974 
4975  bufferevent_disable(bev, EV_READ);
4976  bufferevent_setcb(bev, NULL, NULL, NULL, NULL);
4977 
4978  return bev;
4979 }
4980 
4981 struct bufferevent *
4982 evhtp_request_get_bev(evhtp_request_t * request)
4983 {
4984  return evhtp_connection_get_bev(request->conn);
4985 }
4986 
4987 struct bufferevent *
4988 evhtp_request_take_ownership(evhtp_request_t * request)
4989 {
4990  return evhtp_connection_take_ownership(request->conn);
4991 }
4992 
4993 void
4994 evhtp_connection_set_bev(evhtp_connection_t * conn, struct bufferevent * bev)
4995 {
4996  conn->bev = bev;
4997 }
4998 
4999 void
5000 evhtp_request_set_bev(evhtp_request_t * request, struct bufferevent * bev)
5001 {
5002  evhtp_connection_set_bev(request->conn, bev);
5003 }
5004 
5005 void
5006 evhtp_request_set_keepalive(evhtp_request_t * request, int val)
5007 {
5008  if (val) {
5010  }
5011 }
5012 
5013 evhtp_connection_t *
5014 evhtp_request_get_connection(evhtp_request_t * request)
5015 {
5016  return request->conn;
5017 }
5018 
5020 evhtp_request_get_proto(evhtp_request_t * request)
5021 {
5022  return request->proto;
5023 }
5024 
5025 evhtp_res
5026 evhtp_request_get_status_code(evhtp_request_t * request)
5027 {
5028  return request->status;
5029 }
5030 
5031 const char *
5032 evhtp_request_get_status_code_str(evhtp_request_t * request)
5033 {
5034  return status_code_to_str(request->status);
5035 }
5036 
5037 inline void
5038 evhtp_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 
5049 void
5050 evhtp_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 
5059 void
5060 evhtp_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 
5065 void
5066 evhtp_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 
5102 void
5103 evhtp_request_free(evhtp_request_t * request)
5104 {
5105  if (request == NULL) {
5106  return;
5107  }
5108 
5110 }
5111 
5112 void
5113 evhtp_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 
5124 void
5125 evhtp_set_max_keepalive_requests(evhtp_t * htp, uint64_t num)
5126 {
5127  htp->max_keepalive_requests = num;
5128 }
5129 
5130 void
5131 evhtp_set_bev_flags(evhtp_t * htp, int flags)
5132 {
5133  htp->bev_flags = flags;
5134 }
5135 
5136 void
5137 evhtp_set_max_body_size(evhtp_t * htp, uint64_t len)
5138 {
5139  htp->max_body_size = len;
5140 }
5141 
5142 void
5144 {
5146 }
5147 
5148 void
5149 evhtp_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 
5172 HTP_FLAG_FNGEN(, evhtp_t *);
5173 HTP_FLAG_FNGEN(_connection, evhtp_connection_t *);
5174 HTP_FLAG_FNGEN(_request, evhtp_request_t *);
5175 
5176 int
5177 evhtp_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)) {
5194  evhtp_safe_free(alias, htp__free_);
5195 
5196  return -1;
5197  }
5198 
5199  TAILQ_INSERT_TAIL(&evhtp->aliases, alias, next);
5200 
5201  return 0;
5202 }
5203 
5204 int
5205 evhtp_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 
5231 int
5232 evhtp_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 
5278 static int
5279 evhtp__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 
5317 evhtp_t *
5318 evhtp_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 
5329 void
5330 evhtp_free(evhtp_t * evhtp)
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 
5377 evhtp_connection_t *
5378 evhtp_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 
5383 evhtp_connection_t *
5384 evhtp_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,
5408  htp__connection_eventcb_, conn);
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 
5454 evhtp_connection_t *
5455 evhtp_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,
5495  htp__connection_eventcb_, conn);
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 
5525 evhtp_request_t *
5527 {
5528  evhtp_request_t * r;
5529 
5530  r = htp__request_new_(NULL);
5531  evhtp_alloc_assert(r);
5532 
5533  r->cb = cb;
5534  r->cbarg = arg;
5535  r->proto = EVHTP_PROTO_11;
5536 
5537  return r;
5538 }
5539 
5540 int
5541 evhtp_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 
5588 unsigned int
5589 evhtp_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
Definition: evhtp/evhtp.h:1107
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
Definition: evhtp/evhtp.h:451
#define EVHTP_PARSE_QUERY_FLAG_STRICT
Definition: evhtp/evhtp.h:1103
#define EVHTP_PARSE_QUERY_FLAG_IGNORE_FRAGMENTS
Definition: evhtp/evhtp.h:1108
#define EVHTP_CONN_FLAG_OWNER
set to 1 if this structure owns the bufferevent
Definition: evhtp/evhtp.h:450
#define EVHTP_RES_OK
Definition: evhtp/evhtp.h:204
unsigned char evhtp_ssl_data_t
Definition: evhtp/evhtp.h:50
evhtp_res(* evhtp_hook_headers_start_cb)(evhtp_request_t *r, void *arg)
Definition: evhtp/evhtp.h:173
evhtp_res(* evhtp_hook_chunk_new_cb)(evhtp_request_t *r, uint64_t len, void *arg)
Definition: evhtp/evhtp.h:170
#define EVHTP_RES_FATAL
Definition: evhtp/evhtp.h:201
#define evhtp_headers_find_header
Definition: evhtp/evhtp.h:1212
#define EVHTP_PARSE_QUERY_FLAG_ALLOW_EMPTY_VALS
Definition: evhtp/evhtp.h:1105
evhtp_res(* evhtp_hook_hostname_cb)(evhtp_request_t *r, const char *hostname, void *arg)
Definition: evhtp/evhtp.h:174
#define evhtp_query_new
Definition: evhtp/evhtp.h:1219
evhtp_res(* evhtp_hook_connection_fini_cb)(evhtp_connection_t *connection, void *arg)
Definition: evhtp/evhtp.h:169
struct evhtp_kvs evhtp_headers_t
Definition: evhtp/evhtp.h:94
#define EVHTP_RES_ERROR
Definition: evhtp/evhtp.h:199
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
Definition: evhtp/evhtp.h:454
evhtp_res(* evhtp_hook_conn_err_cb)(evhtp_connection_t *connection, evhtp_error_flags errtype, void *arg)
Definition: evhtp/evhtp.h:161
#define EVHTP_PARSE_QUERY_FLAG_IGNORE_HEX
Definition: evhtp/evhtp.h:1104
evhtp_res(* evhtp_hook_request_fini_cb)(evhtp_request_t *req, void *arg)
Definition: evhtp/evhtp.h:168
#define EVHTP_CONN_FLAG_PAUSED
this connection has been marked as paused
Definition: evhtp/evhtp.h:452
SSL_SESSION evhtp_ssl_sess_t
Definition: evhtp/evhtp.h:41
#define EVHTP_FLAG_DEFAULTS
Definition: evhtp/evhtp.h:297
evhtp_res(* evhtp_hook_path_cb)(evhtp_request_t *req, evhtp_path_t *path, void *arg)
Definition: evhtp/evhtp.h:166
#define EVHTP_FLAG_ENABLE_100_CONT
Definition: evhtp/evhtp.h:293
#define EVHTP_REQ_FLAG_CHUNKED
Definition: evhtp/evhtp.h:415
void(* evhtp_callback_cb)(evhtp_request_t *req, void *arg)
Definition: evhtp/evhtp.h:154
#define EVHTP_FLAG_ENABLE_NODELAY
Definition: evhtp/evhtp.h:295
#define evhtp_query_free
Definition: evhtp/evhtp.h:1220
evhtp_res(* evhtp_post_accept_cb)(evhtp_connection_t *conn, void *arg)
Definition: evhtp/evhtp.h:163
evhtp_callback_type
Definition: evhtp/evhtp.h:127
@ evhtp_callback_type_glob
Definition: evhtp/evhtp.h:129
@ evhtp_callback_type_hash
Definition: evhtp/evhtp.h:128
@ evhtp_callback_type_regex
Definition: evhtp/evhtp.h:131
#define EVHTP_REQ_FLAG_FINISHED
Definition: evhtp/evhtp.h:414
#define EVHTP_PARSE_QUERY_FLAG_DEFAULT
Definition: evhtp/evhtp.h:1115
evhtp_res(* evhtp_hook_chunks_fini_cb)(evhtp_request_t *r, void *arg)
Definition: evhtp/evhtp.h:172
#define EVHTP_PARSE_QUERY_FLAG_ALLOW_NULL_VALS
Definition: evhtp/evhtp.h:1106
#define EVHTP_CONN_FLAG_FREE_CONN
Definition: evhtp/evhtp.h:455
#define evhtp_safe_free(_var, _freefn)
Definition: evhtp/evhtp.h:1445
evhtp_hook_type
types associated with where a developer can hook into during the request processing cycle.
Definition: evhtp/evhtp.h:108
@ evhtp_hook_on_error
type which defines to hook whenever an error occurs
Definition: evhtp/evhtp.h:119
@ evhtp_hook_on_header
type which defines to hook after one header has been parsed
Definition: evhtp/evhtp.h:109
@ evhtp_hook_on_read
type which defines to hook whenever the parser recieves data in a body
Definition: evhtp/evhtp.h:112
@ evhtp_hook_on_new_chunk
Definition: evhtp/evhtp.h:115
@ evhtp_hook_on_chunk_complete
Definition: evhtp/evhtp.h:116
@ evhtp_hook_on_write
Definition: evhtp/evhtp.h:121
@ evhtp_hook_on_request_fini
type which defines to hook before the request is free'd
Definition: evhtp/evhtp.h:113
@ evhtp_hook_on_hostname
Definition: evhtp/evhtp.h:120
@ evhtp_hook_on_chunks_complete
Definition: evhtp/evhtp.h:117
@ evhtp_hook_on_event
Definition: evhtp/evhtp.h:122
@ evhtp_hook_on_conn_error
type which defines to hook whenever a connection error occurs
Definition: evhtp/evhtp.h:123
@ evhtp_hook_on_headers_start
Definition: evhtp/evhtp.h:118
@ evhtp_hook_on_path
type which defines to hook once a path has been parsed
Definition: evhtp/evhtp.h:111
@ evhtp_hook_on_connection_fini
Definition: evhtp/evhtp.h:114
@ evhtp_hook_on_headers
type which defines to hook after all headers have been parsed
Definition: evhtp/evhtp.h:110
@ evhtp_hook__max
Definition: evhtp/evhtp.h:124
SSL evhtp_ssl_t
Definition: evhtp/evhtp.h:45
#define evhtp_request_content_len(r)
Definition: evhtp/evhtp.h:425
evhtp_res(* evhtp_hook_read_cb)(evhtp_request_t *req, struct evbuffer *buf, void *arg)
Definition: evhtp/evhtp.h:167
#define EVHTP_REQ_FLAG_ERROR
Definition: evhtp/evhtp.h:416
evhtp_res(* evhtp_hook_header_cb)(evhtp_request_t *req, evhtp_header_t *hdr, void *arg)
Definition: evhtp/evhtp.h:164
#define evhtp_headers_for_each
Definition: evhtp/evhtp.h:1213
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
Definition: evhtp/evhtp.h:456
evhtp_res(* evhtp_hook)()
Definition: evhtp/evhtp.h:159
int(* evhtp_kvs_iterator)(evhtp_kv_t *kv, void *arg)
Definition: evhtp/evhtp.h:177
#define EVHTP_CONN_FLAG_ERROR
Definition: evhtp/evhtp.h:449
@ evhtp_ssl_scache_type_user
Definition: evhtp/evhtp.h:100
@ evhtp_ssl_scache_type_builtin
Definition: evhtp/evhtp.h:101
@ evhtp_ssl_scache_type_disabled
Definition: evhtp/evhtp.h:98
#define EVHTP_RES_PAUSE
Definition: evhtp/evhtp.h:200
evhtp_res(* evhtp_hook_chunk_fini_cb)(evhtp_request_t *r, void *arg)
Definition: evhtp/evhtp.h:171
evhtp_res(* evhtp_hook_headers_cb)(evhtp_request_t *req, evhtp_headers_t *hdr, void *arg)
Definition: evhtp/evhtp.h:165
evhtp_res(* evhtp_pre_accept_cb)(evhtp_connection_t *conn, void *arg)
Definition: evhtp/evhtp.h:162
void(* evhtp_hook_err_cb)(evhtp_request_t *req, evhtp_error_flags errtype, void *arg)
Definition: evhtp/evhtp.h:155
void(* evhtp_thread_exit_cb)(evhtp_t *htp, evthr_t *thr, void *arg)
Definition: evhtp/evhtp.h:153
struct evhtp_kvs evhtp_kvs_t
Definition: evhtp/evhtp.h:81
evhtp_proto
Definition: evhtp/evhtp.h:135
@ EVHTP_PROTO_10
Definition: evhtp/evhtp.h:137
@ EVHTP_PROTO_INVALID
Definition: evhtp/evhtp.h:136
@ EVHTP_PROTO_11
Definition: evhtp/evhtp.h:138
uint16_t evhtp_res
Definition: evhtp/evhtp.h:90
evhtp_res(* evhtp_hook_write_cb)(evhtp_connection_t *conn, void *arg)
Definition: evhtp/evhtp.h:175
#define EVHTP_FLAG_ENABLE_REUSEPORT
Definition: evhtp/evhtp.h:294
void(* evhtp_thread_init_cb)(evhtp_t *htp, evthr_t *thr, void *arg)
Definition: evhtp/evhtp.h:152
#define EVHTP_FLAG_ENABLE_DEFER_ACCEPT
Definition: evhtp/evhtp.h:296
struct evhtp_kvs evhtp_query_t
Definition: evhtp/evhtp.h:95
#define EVHTP_RES_DATA_TOO_LONG
Definition: evhtp/evhtp.h:203
evhtp_type
Definition: evhtp/evhtp.h:141
@ evhtp_type_server
Definition: evhtp/evhtp.h:143
@ evhtp_type_client
Definition: evhtp/evhtp.h:142
#define EVHTP_REQ_FLAG_KEEPALIVE
Definition: evhtp/evhtp.h:413
void(* evhtp_hook_event_cb)(evhtp_connection_t *conn, short events, void *arg)
Definition: evhtp/evhtp.h:156
struct evhtp_callbacks evhtp_callbacks_t
Definition: evhtp/evhtp.h:78
#define EVHTP_CONN_FLAG_CONNECTED
client specific - set after successful connection
Definition: evhtp/evhtp.h:453
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
static void *(* realloc_)(void *d, size_t sz)
Definition: evhtp.c:167
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
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
static int htp__request_parse_hostname_(htparser *p, const char *data, size_t len)
Definition: evhtp.c:1623
static void * htp__malloc_(size_t size)
Wrapper for malloc so that a different malloc can be used if desired.
Definition: evhtp.c:181
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_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
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
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
static int htp__request_parse_headers_start_(htparser *p)
Definition: evhtp.c:1420
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
static evhtp_proto htp__protocol_(const char major, const char minor)
returns the HTTP protocol version
Definition: evhtp.c:555
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
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
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
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 char * htp__strdup_(const char *str)
implementation of strdup function.
Definition: evhtp.c:261
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
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 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
#define HTP_FLAG_FNGEN(NAME, TYPE)
Definition: evhtp.c:5154
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 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 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__request_parse_chunk_new_(htparser *p)
Definition: evhtp.c:1864
evhtp_request_t * evhtp_request_new(evhtp_callback_cb cb, void *arg)
allocate a new request
Definition: evhtp.c:5526
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
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
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 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 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 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 *(* malloc_)(size_t sz)
Definition: evhtp.c:166
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
struct bufferevent * evhtp_request_get_bev(evhtp_request_t *request)
returns the underlying requests bufferevent
Definition: evhtp.c:4982
#define HTP_LEN_INPUT(b)
Definition: evhtp.c:83
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
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 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
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
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
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
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
evhtp_hooks_t * evhtp_request_get_hooks(evhtp_request_t *r)
returns request hooks
Definition: evhtp.c:4467
void evhtp_set_bev_flags(evhtp_t *htp, int flags)
bufferevent flags which will be used for bev sockets.
Definition: evhtp.c:5131
#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_t * evhtp_new(struct event_base *evbase, void *arg)
creates a new evhtp_t instance
Definition: evhtp.c:5318
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_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
static evhtp_t * htp__request_find_vhost_(evhtp_t *evhtp, const char *name)
Definition: evhtp.c:1493
#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
static int evhtp__new_(evhtp_t **out, struct event_base *evbase, void *arg)
Allocates new evhtp_t structure.
Definition: evhtp.c:5279
static evhtp_connection_t * htp__connection_new_(evhtp_t *htp, evutil_socket_t sock, evhtp_type type)
Definition: evhtp.c:2704
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
struct bufferevent * evhtp_request_take_ownership(evhtp_request_t *request)
Definition: evhtp.c:4988
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
evhtp_hooks_t * evhtp_connection_get_hooks(evhtp_connection_t *c)
Definition: evhtp.c:4451
evhtp_proto evhtp_request_get_proto(evhtp_request_t *request)
Definition: evhtp.c:5020
static int htp__request_parse_path_(htparser *p, const char *data, size_t len)
Definition: evhtp.c:1752
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
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
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
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
static char * htp__strndup_(const char *str, size_t len)
implementation of strndup function.
Definition: evhtp.c:291
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
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
static evhtp_request_t * htp__request_new_(evhtp_connection_t *c)
Creates a new evhtp_request_t.
Definition: evhtp.c:1253
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
#define ssl_sk_connect_
Definition: evhtp.c:5452
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
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
struct bufferevent * evhtp_connection_get_bev(evhtp_connection_t *connection)
returns the underlying connections bufferevent
Definition: evhtp.c:4950
int evhtp_unset_all_hooks(evhtp_hooks_t **hooks)
removes all hooks.
Definition: evhtp.c:4412
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 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 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
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
static void htp__connection_writecb_(struct bufferevent *bev, void *arg)
Definition: evhtp.c:2296
static const char * status_code_to_str(evhtp_res code)
returns string status code from enum code
Definition: evhtp.c:342
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
#define HTP_FLAG_OFF(PRE, FLAG)
Definition: evhtp.c:75
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
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
void evhtp_connection_set_bev(evhtp_connection_t *conn, struct bufferevent *bev)
Sets the connections underlying bufferevent.
Definition: evhtp.c:4994
#define ssl_sk_new_
Definition: evhtp.c:5451
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
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
int evhtp_callback_unset_hook(evhtp_callback_t *callback, evhtp_hook_type type)
Definition: evhtp.c:4374
evhtp_hooks_t * evhtp_callback_get_hooks(evhtp_callback_t *cb)
returns callback hooks
Definition: evhtp.c:4483
#define HOOK_REQUEST_RUN(request, hook_name,...)
Definition: evhtp.c:89
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
evhtp_kvs_t * evhtp_kvs_new(void)
creates an empty list of key/values
Definition: evhtp.c:3140
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
static int htp__serv_setsockopts_(evhtp_t *htp, evutil_socket_t sock)
Definition: evhtp.c:3934
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
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
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
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
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
static struct evbuffer * htp__create_reply_(evhtp_request_t *request, evhtp_res code)
Definition: evhtp.c:2061
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
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
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
#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
void * htparser_get_userdata(htparser *p)
Definition: parser.c:533
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
void htparser_set_major(htparser *p, unsigned char major)
Definition: parser.c:503
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
const char * htparser_get_methodstr_m(htp_method meth)
Definition: parser.c:486
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
htparser * htparser_new(void)
Definition: parser.c:581
char * alias
Definition: evhtp/evhtp.h:274
structure which represents authority information in a URI
Definition: evhtp/evhtp.h:372
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
Definition: evhtp/evhtp.h:444
evhtp_hooks_t * hooks
Definition: evhtp/evhtp.h:437
structure which represents a URI path and or file
Definition: evhtp/evhtp.h:383
char * file
the filename if present (c.html)
Definition: evhtp/evhtp.h:386
char * match_start
Definition: evhtp/evhtp.h:387
char * full
the full path+file (/a/b/c.html)
Definition: evhtp/evhtp.h:384
char * match_end
Definition: evhtp/evhtp.h:388
char * path
the path (/a/b/)
Definition: evhtp/evhtp.h:385
a structure containing all information for a http request.
Definition: evhtp/evhtp.h:401
struct evbuffer * buffer_in
buffer containing data from client
Definition: evhtp/evhtp.h:406
void * cbarg
argument which is passed to the cb function
Definition: evhtp/evhtp.h:420
evhtp_uri_t * uri
request URI information
Definition: evhtp/evhtp.h:405
struct evbuffer * buffer_out
buffer containing data to client
Definition: evhtp/evhtp.h:407
evhtp_headers_t * headers_out
headers to client
Definition: evhtp/evhtp.h:409
evhtp_headers_t * headers_in
headers from client
Definition: evhtp/evhtp.h:408
evhtp_t * htp
the parent evhtp_t structure
Definition: evhtp/evhtp.h:402
evhtp_hooks_t * hooks
request specific hooks
Definition: evhtp/evhtp.h:404
evhtp_res status
The HTTP response code or other error conditions.
Definition: evhtp/evhtp.h:412
evhtp_connection_t * conn
the associated connection
Definition: evhtp/evhtp.h:403
a generic container representing an entire URI strucutre
Definition: evhtp/evhtp.h:359
evhtp_authority_t * authority
Definition: evhtp/evhtp.h:360
main structure containing all configuration information
Definition: evhtp/evhtp.h:283
char * server_name
the name included in Host: responses
Definition: evhtp/evhtp.h:287
evthr_pool_t * thr_pool
connection threadpool
Definition: evhtp/evhtp.h:312
struct timeval send_timeo
Definition: evhtp/evhtp.h:328
int bev_flags
bufferevent flags to use on bufferevent_*_socket_new()
Definition: evhtp/evhtp.h:289
struct timeval recv_timeo
Definition: evhtp/evhtp.h:327
evhtp_ssl_ctx_t * ssl_ctx
if ssl enabled, this is the servers CTX
Definition: evhtp/evhtp.h:307
uint64_t max_keepalive_requests
Definition: evhtp/evhtp.h:291
uint64_t max_body_size
Definition: evhtp/evhtp.h:290
evhtp_callbacks_t * callbacks
Definition: evhtp/evhtp.h:324
evhtp_defaults_t defaults
Definition: evhtp/evhtp.h:325
evbase_t * evthr_get_base(evthr_t *thr)
Definition: thread.c:176
void evthr_pool_free(evthr_pool_t *pool)
Definition: thread.c:316
evthr_cb cb
Definition: thread.c:2
evthr_res evthr_pool_defer(evthr_pool_t *pool, evthr_cb cb, void *arg)
Definition: thread.c:362
void * args
Definition: thread.c:1
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
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