Libevhtp  0.3.7
evhtp.c
Go to the documentation of this file.
1 #define _GNU_SOURCE
2 #include <stdlib.h>
3 #include <string.h>
4 #include <stdint.h>
5 #include <errno.h>
6 #include <signal.h>
7 #include <strings.h>
8 #include <inttypes.h>
9 #ifndef WIN32
10 #include <sys/socket.h>
11 #include <netinet/in.h>
12 #include <netinet/tcp.h>
13 #include <arpa/inet.h>
14 #else
15 #define WINVER 0x0501
16 #include <winsock2.h>
17 #include <ws2tcpip.h>
18 #endif
19 #ifndef NO_SYS_UN
20 #include <sys/un.h>
21 #endif
22 
23 #include <limits.h>
24 #include <event2/dns.h>
25 
26 #include "evhtp-internal.h"
27 #include "evhtp_numtoa.h"
28 #include "evhtp.h"
29 
30 
31 static int _evhtp_request_parser_start(htparser * p);
32 static int _evhtp_request_parser_host(htparser * p, const char * data, size_t len);
33 static int _evhtp_request_parser_port(htparser * p, const char * data, size_t len);
34 static int _evhtp_request_parser_path(htparser * p, const char * data, size_t len);
35 static int _evhtp_request_parser_args(htparser * p, const char * data, size_t len);
36 static int _evhtp_request_parser_header_key(htparser * p, const char * data, size_t len);
37 static int _evhtp_request_parser_header_val(htparser * p, const char * data, size_t len);
38 static int _evhtp_request_parser_hostname(htparser * p, const char * data, size_t len);
39 static int _evhtp_request_parser_headers(htparser * p);
40 static int _evhtp_request_parser_body(htparser * p, const char * data, size_t len);
41 static int _evhtp_request_parser_fini(htparser * p);
42 static int _evhtp_request_parser_chunk_new(htparser * p);
43 static int _evhtp_request_parser_chunk_fini(htparser * p);
44 static int _evhtp_request_parser_chunks_fini(htparser * p);
45 static int _evhtp_request_parser_headers_start(htparser * p);
46 
47 static void _evhtp_connection_readcb(evbev_t * bev, void * arg);
48 
49 static evhtp_connection_t * _evhtp_connection_new(evhtp_t * htp, evutil_socket_t sock, evhtp_type type);
50 
51 static evhtp_uri_t * _evhtp_uri_new(void);
52 static void _evhtp_uri_free(evhtp_uri_t * uri);
53 
55 static void _evhtp_authority_free(evhtp_authority_t * authority);
56 
57 static evhtp_path_t * _evhtp_path_new(const char * data, size_t len);
58 static void _evhtp_path_free(evhtp_path_t * path);
59 
61 
62 #define HOOK_AVAIL(var, hook_name) (var->hooks && var->hooks->hook_name)
63 #define HOOK_FUNC(var, hook_name) (var->hooks->hook_name)
64 #define HOOK_ARGS(var, hook_name) var->hooks->hook_name ## _arg
65 
66 #define HOOK_REQUEST_RUN(request, hook_name, ...) do { \
67  if (HOOK_AVAIL(request, hook_name)) { \
68  return HOOK_FUNC(request, hook_name) (request, __VA_ARGS__, \
69  HOOK_ARGS(request, hook_name)); \
70  } \
71  \
72  if (HOOK_AVAIL(evhtp_request_get_connection(request), hook_name)) { \
73  return HOOK_FUNC(request->conn, hook_name) (request, __VA_ARGS__, \
74  HOOK_ARGS(request->conn, hook_name)); \
75  } \
76 } while (0)
77 
78 #define HOOK_REQUEST_RUN_NARGS(request, hook_name) do { \
79  if (HOOK_AVAIL(request, hook_name)) { \
80  return HOOK_FUNC(request, hook_name) (request, \
81  HOOK_ARGS(request, hook_name)); \
82  } \
83  \
84  if (HOOK_AVAIL(request->conn, hook_name)) { \
85  return HOOK_FUNC(request->conn, hook_name) (request, \
86  HOOK_ARGS(request->conn, hook_name)); \
87  } \
88 } while (0);
89 
90 #define HOOK_CONN_RUN(conn, hook_name, ...) do { \
91  if (conn->request) { \
92  evhtp_request_t * request = conn->request; \
93  if (HOOK_AVAIL(request, hook_name)) { \
94  return HOOK_FUNC(conn, hook_name) (conn, __VA_ARGS__, \
95  HOOK_ARGS(conn, hook_name)); \
96  } \
97  } \
98  \
99  if (HOOK_AVAIL(conn, hook_name)) { \
100  return HOOK_FUNC(conn, hook_name) (conn, __VA_ARGS__, \
101  HOOK_ARGS(conn, hook_name)); \
102  } \
103 } while (0);
104 
105 #ifndef EVHTP_DISABLE_EVTHR
106 #define _evhtp_lock(h) do { \
107  if (h->lock) { \
108  pthread_mutex_lock(h->lock); \
109  } \
110 } while (0)
111 
112 #define _evhtp_unlock(h) do { \
113  if (h->lock) { \
114  pthread_mutex_unlock(h->lock); \
115  } \
116 } while (0)
117 #else
118 #define _evhtp_lock(h) do {} while (0)
119 #define _evhtp_unlock(h) do {} while (0)
120 #endif
121 
122 #ifndef TAILQ_FOREACH_SAFE
123 #define TAILQ_FOREACH_SAFE(var, head, field, tvar) \
124  for ((var) = TAILQ_FIRST((head)); \
125  (var) && ((tvar) = TAILQ_NEXT((var), field), 1); \
126  (var) = (tvar))
127 #endif
128 
129 static const char *
131  switch (code) {
132  case EVHTP_RES_200:
133  return "OK";
134  case EVHTP_RES_300:
135  return "Redirect";
136  case EVHTP_RES_400:
137  return "Bad Request";
138  case EVHTP_RES_NOTFOUND:
139  return "Not Found";
140  case EVHTP_RES_SERVERR:
141  return "Internal Server Error";
142  case EVHTP_RES_CONTINUE:
143  return "Continue";
144  case EVHTP_RES_FORBIDDEN:
145  return "Forbidden";
147  return "Switching Protocols";
148  case EVHTP_RES_MOVEDPERM:
149  return "Moved Permanently";
151  return "Processing";
153  return "URI Too Long";
154  case EVHTP_RES_CREATED:
155  return "Created";
156  case EVHTP_RES_ACCEPTED:
157  return "Accepted";
158  case EVHTP_RES_NAUTHINFO:
159  return "No Auth Info";
160  case EVHTP_RES_NOCONTENT:
161  return "No Content";
163  return "Reset Content";
164  case EVHTP_RES_PARTIAL:
165  return "Partial Content";
166  case EVHTP_RES_MSTATUS:
167  return "Multi-Status";
168  case EVHTP_RES_IMUSED:
169  return "IM Used";
170  case EVHTP_RES_FOUND:
171  return "Found";
172  case EVHTP_RES_SEEOTHER:
173  return "See Other";
174  case EVHTP_RES_NOTMOD:
175  return "Not Modified";
176  case EVHTP_RES_USEPROXY:
177  return "Use Proxy";
179  return "Switch Proxy";
180  case EVHTP_RES_TMPREDIR:
181  return "Temporary Redirect";
182  case EVHTP_RES_UNAUTH:
183  return "Unauthorized";
184  case EVHTP_RES_PAYREQ:
185  return "Payment Required";
187  return "Not Allowed";
189  return "Not Acceptable";
191  return "Proxy Authentication Required";
192  case EVHTP_RES_TIMEOUT:
193  return "Request Timeout";
194  case EVHTP_RES_CONFLICT:
195  return "Conflict";
196  case EVHTP_RES_GONE:
197  return "Gone";
198  case EVHTP_RES_LENREQ:
199  return "Length Required";
201  return "Precondition Failed";
203  return "Entity Too Large";
205  return "Request-URI Too Long";
207  return "Unsupported Media Type";
209  return "Requested Range Not Satisfiable";
211  return "Expectation Failed";
213  return "I'm a teapot";
214  case EVHTP_RES_NOTIMPL:
215  return "Not Implemented";
217  return "Bad Gateway";
219  return "Service Unavailable";
220  case EVHTP_RES_GWTIMEOUT:
221  return "Gateway Timeout";
223  return "HTTP Version Not Supported";
224  case EVHTP_RES_BWEXEED:
225  return "Bandwidth Limit Exceeded";
226  } /* switch */
227 
228  return "UNKNOWN";
229 } /* status_code_to_str */
230 
234 static htparse_hooks request_psets = {
235  .on_msg_begin = _evhtp_request_parser_start,
236  .method = NULL,
237  .scheme = NULL,
242  .uri = NULL,
243  .on_hdrs_begin = _evhtp_request_parser_headers_start,
246  .hostname = _evhtp_request_parser_hostname,
247  .on_hdrs_complete = _evhtp_request_parser_headers,
248  .on_new_chunk = _evhtp_request_parser_chunk_new,
249  .on_chunk_complete = _evhtp_request_parser_chunk_fini,
250  .on_chunks_complete = _evhtp_request_parser_chunks_fini,
252  .on_msg_complete = _evhtp_request_parser_fini
253 };
254 
255 #ifndef EVHTP_DISABLE_SSL
256 static int session_id_context = 1;
257 #ifndef EVHTP_DISABLE_EVTHR
258 static int ssl_num_locks;
260 static int ssl_locks_initialized = 0;
261 #endif
262 #endif
263 
264 /*
265  * COMPAT FUNCTIONS
266  */
267 
268 #ifdef NO_STRNLEN
269 static size_t
270 strnlen(const char * s, size_t maxlen) {
271  const char * e;
272  size_t n;
273 
274  for (e = s, n = 0; *e && n < maxlen; e++, n++) {
275  ;
276  }
277 
278  return n;
279 }
280 
281 #endif
282 
283 #ifdef NO_STRNDUP
284 static char *
285 strndup(const char * s, size_t n) {
286  size_t len = strnlen(s, n);
287  char * ret;
288 
289  if (len < n) {
290  return strdup(s);
291  }
292 
293  ret = malloc(n + 1);
294  ret[n] = '\0';
295 
296  memcpy(ret, s, n);
297 
298  return ret;
299 }
300 
301 #endif
302 
303 /*
304  * PRIVATE FUNCTIONS
305  */
306 
314 static inline unsigned int
315 _evhtp_quick_hash(const char * str) {
316  unsigned int h = 0;
317 
318  for (; *str; str++) {
319  h = 31 * h + *str;
320  }
321 
322  return h;
323 }
324 
335 #define _evhtp_is_http_11(_major, _minor) \
336  (_major >= 1 && _minor >= 1)
337 
346 #define _evhtp_is_http_10(_major, _minor) \
347  (_major >= 1 && _minor <= 0)
348 
349 
359 static inline evhtp_proto
360 _evhtp_protocol(const char major, const char minor) {
361  if (_evhtp_is_http_10(major, minor)) {
362  return EVHTP_PROTO_10;
363  }
364 
365  if (_evhtp_is_http_11(major, minor)) {
366  return EVHTP_PROTO_11;
367  }
368 
369  return EVHTP_PROTO_INVALID;
370 }
371 
380 static inline evhtp_res
382  HOOK_REQUEST_RUN(request, on_path, path);
383 
384  return EVHTP_RES_OK;
385 }
386 
397 static inline evhtp_res
399  HOOK_REQUEST_RUN(request, on_header, header);
400 
401  return EVHTP_RES_OK;
402 }
403 
413 static inline evhtp_res
415  HOOK_REQUEST_RUN(request, on_headers, headers);
416 
417  return EVHTP_RES_OK;
418 }
419 
430 static inline evhtp_res
432  HOOK_REQUEST_RUN(request, on_read, buf);
433 
434  return EVHTP_RES_OK;
435 }
436 
445 static inline evhtp_res
447  HOOK_REQUEST_RUN_NARGS(request, on_request_fini);
448 
449  return EVHTP_RES_OK;
450 }
451 
452 static inline evhtp_res
453 _evhtp_chunk_new_hook(evhtp_request_t * request, uint64_t len) {
454  HOOK_REQUEST_RUN(request, on_new_chunk, len);
455 
456  return EVHTP_RES_OK;
457 }
458 
459 static inline evhtp_res
461  HOOK_REQUEST_RUN_NARGS(request, on_chunk_fini);
462 
463  return EVHTP_RES_OK;
464 }
465 
466 static inline evhtp_res
468  HOOK_REQUEST_RUN_NARGS(request, on_chunks_fini);
469 
470  return EVHTP_RES_OK;
471 }
472 
473 static inline evhtp_res
475  HOOK_REQUEST_RUN_NARGS(request, on_headers_start);
476 
477  return EVHTP_RES_OK;
478 }
479 
488 static inline evhtp_res
490  if (connection->hooks && connection->hooks->on_connection_fini) {
491  return (connection->hooks->on_connection_fini)(connection,
492  connection->hooks->on_connection_fini_arg);
493  }
494 
495  return EVHTP_RES_OK;
496 }
497 
504 static inline void
506  if (request && request->hooks && request->hooks->on_error) {
507  (*request->hooks->on_error)(request, errtype,
508  request->hooks->on_error_arg);
509  }
510 }
511 
518 static inline evhtp_res
520  if (connection->request) {
521  _evhtp_error_hook(connection->request, errtype);
522  }
523  HOOK_CONN_RUN(connection, on_connection_error, errtype);
524 
525  return EVHTP_RES_OK;
526 }
527 
528 static inline evhtp_res
529 _evhtp_hostname_hook(evhtp_request_t * r, const char * hostname) {
530  HOOK_REQUEST_RUN(r, on_hostname, hostname);
531 
532  return EVHTP_RES_OK;
533 }
534 
535 static inline evhtp_res
537  if (connection->hooks && connection->hooks->on_write) {
538  return (connection->hooks->on_write)(connection,
539  connection->hooks->on_write_arg);
540  }
541 
542  return EVHTP_RES_OK;
543 }
544 
545 static int
546 _evhtp_glob_match2(const char * pattern, size_t plen,
547  const char * string, size_t str_len) {
548  while (plen) {
549  switch (pattern[0]) {
550  case '*':
551  while (pattern[1] == '*') {
552  pattern++;
553  plen--;
554  }
555 
556  if (plen == 1) {
557  return 1; /* match */
558  }
559 
560  while (str_len) {
561  if (_evhtp_glob_match2(pattern + 1, plen - 1,
562  string, str_len)) {
563  return 1; /* match */
564  }
565 
566  string++;
567  str_len--;
568  }
569 
570  return 0; /* no match */
571  default:
572  if (pattern[0] != string[0]) {
573  return 0; /* no match */
574  }
575 
576  string++;
577  str_len--;
578  break;
579  } /* switch */
580 
581  pattern++;
582  plen--;
583 
584  if (str_len == 0) {
585  while (*pattern == '*') {
586  pattern++;
587  plen--;
588  }
589 
590  break;
591  }
592  }
593 
594  if (plen == 0 && str_len == 0) {
595  return 1;
596  }
597 
598  return 0;
599 } /* _evhtp_glob_match2 */
600 
611 static inline int
612 _evhtp_glob_match(const char * pattern, size_t pat_len, const char * string, size_t str_len) {
613  if (!pattern || !string) {
614  return 0;
615  }
616 
617  if (pat_len == 0) {
618  pat_len = strlen(pattern);
619  }
620 
621  if (str_len == 0) {
622  str_len = strlen(string);
623  }
624 
625  /* XXX still in testing */
626  return _evhtp_glob_match2(pattern, pat_len, string, str_len);
627 
628 #if 0
629  while (pat_len) {
630  if (pattern[0] == '*') {
631  while (pattern[1] == '*') {
632  pattern++;
633  pat_len--;
634  }
635 
636  if (pat_len == 1) {
637  return 1;
638  }
639 
640  while (str_len) {
641  if (_evhtp_glob_match(pattern + 1, pat_len, string, str_len)) {
642  return 1;
643  }
644 
645  string++;
646  str_len--;
647  }
648 
649  return 0;
650  } else {
651  if (pattern[0] != string[0]) {
652  return 0;
653  }
654 
655  string++;
656  str_len--;
657  }
658 
659  pattern++;
660  pat_len--;
661 
662  if (str_len == 0) {
663  while (*pattern == '*') {
664  pattern++;
665  pat_len--;
666  }
667  break;
668  }
669  }
670 
671  if (pat_len == 0 && str_len == 0) {
672  return 1;
673  }
674 
675  return 0;
676 #endif
677 } /* _evhtp_glob_match */
678 
679 static evhtp_callback_t *
681  const char * path,
682  unsigned int * start_offset,
683  unsigned int * end_offset) {
684 #ifndef EVHTP_DISABLE_REGEX
685  regmatch_t pmatch[28];
686 #endif
687  evhtp_callback_t * callback;
688 
689  if (cbs == NULL) {
690  return NULL;
691  }
692 
693  TAILQ_FOREACH(callback, cbs, next) {
694  switch (callback->type) {
696  if (strcmp(callback->val.path, path) == 0) {
697  *start_offset = 0;
698  *end_offset = (unsigned int)strlen(path);
699 
700  return callback;
701  }
702  break;
703 #ifndef EVHTP_DISABLE_REGEX
705  if (regexec(callback->val.regex, path, callback->val.regex->re_nsub + 1, pmatch, 0) == 0) {
706  *start_offset = pmatch[callback->val.regex->re_nsub].rm_so;
707  *end_offset = pmatch[callback->val.regex->re_nsub].rm_eo;
708 
709  return callback;
710  }
711 
712  break;
713 #endif
715  {
716  size_t path_len = strlen(path);
717  size_t glob_len = strlen(callback->val.glob);
718 
719  if (_evhtp_glob_match(callback->val.glob, glob_len,
720  path, path_len) == 1) {
721  *start_offset = 0;
722  *end_offset = (unsigned int)path_len;
723 
724  return callback;
725  }
726  }
727  default:
728  break;
729  } /* switch */
730  }
731 
732  return NULL;
733 } /* _evhtp_callback_find */
734 
742 static evhtp_request_t *
744  evhtp_request_t * req;
745  uint8_t error;
746 
747  if (!(req = calloc(sizeof(evhtp_request_t), 1))) {
748  return NULL;
749  }
750 
751  error = 1;
752  req->conn = c;
753  req->htp = c ? c->htp : NULL;
754  req->status = EVHTP_RES_OK;
755 
756  do {
757  if (!(req->buffer_in = evbuffer_new())) {
758  break;
759  }
760 
761  if (!(req->buffer_out = evbuffer_new())) {
762  break;
763  }
764 
765  if (!(req->headers_in = malloc(sizeof(evhtp_headers_t)))) {
766  break;
767  }
768 
769  if (!(req->headers_out = malloc(sizeof(evhtp_headers_t)))) {
770  break;
771  }
772 
773  TAILQ_INIT(req->headers_in);
774  TAILQ_INIT(req->headers_out);
775 
776  error = 0;
777  } while (0);
778 
779  if (error == 0) {
780  return req;
781  }
782 
783  _evhtp_request_free(req);
784 
785  return NULL;
786 } /* _evhtp_request_new */
787 
793 static void
795  if (request == NULL) {
796  return;
797  }
798 
799  _evhtp_request_fini_hook(request);
800  _evhtp_uri_free(request->uri);
801 
802  evhtp_headers_free(request->headers_in);
804 
805  if (request->conn && request->conn->request == request) {
806  request->conn->request = NULL;
807  }
808 
809  if (request->buffer_in) {
810  evbuffer_free(request->buffer_in);
811  }
812 
813  if (request->buffer_out) {
814  evbuffer_free(request->buffer_out);
815  }
816 
817  free(request->hooks);
818  free(request);
819 }
820 
826 static evhtp_uri_t *
828  evhtp_uri_t * uri;
829 
830  if (!(uri = calloc(sizeof(evhtp_uri_t), 1))) {
831  return NULL;
832  }
833 
835 
836  if (!uri->authority) {
837  _evhtp_uri_free(uri);
838 
839  return NULL;
840  }
841 
842  return uri;
843 }
844 
850 static void
852  if (authority == NULL) {
853  return;
854  }
855 
856  free(authority->username);
857  free(authority->password);
858  free(authority->hostname);
859 
860  free(authority);
861 }
862 
868 static evhtp_authority_t *
870  evhtp_authority_t * authority;
871 
872  if (!(authority = calloc(1, sizeof(*authority)))) {
873  return NULL;
874  }
875 
876  return authority;
877 }
878 
884 static void
886  if (uri == NULL) {
887  return;
888  }
889 
890  evhtp_query_free(uri->query);
891 
892  _evhtp_path_free(uri->path);
894 
895  free(uri->fragment);
896  free(uri->query_raw);
897  free(uri);
898 }
899 
915 static evhtp_path_t *
916 _evhtp_path_new(const char * data, size_t len) {
917  evhtp_path_t * req_path;
918  const char * data_end = (const char *)(data + len);
919  char * path = NULL;
920  char * file = NULL;
921 
922  if (!(req_path = calloc(sizeof(evhtp_path_t), 1))) {
923  return NULL;
924  }
925 
926  if (len == 0) {
927  /*
928  * odd situation here, no preceding "/", so just assume the path is "/"
929  */
930  path = strdup("/");
931  } else if (*data != '/') {
932  /* request like GET stupid HTTP/1.0, treat stupid as the file, and
933  * assume the path is "/"
934  */
935  path = strdup("/");
936  file = strndup(data, len);
937  } else {
938  if (data[len - 1] != '/') {
939  /*
940  * the last character in data is assumed to be a file, not the end of path
941  * loop through the input data backwards until we find a "/"
942  */
943  size_t i;
944 
945  for (i = (len - 1); i != 0; i--) {
946  if (data[i] == '/') {
947  /*
948  * we have found a "/" representing the start of the file,
949  * and the end of the path
950  */
951  size_t path_len;
952  size_t file_len;
953 
954  path_len = (size_t)(&data[i] - data) + 1;
955  file_len = (size_t)(data_end - &data[i + 1]);
956 
957  /* check for overflow */
958  if ((const char *)(data + path_len) > data_end) {
959  free(req_path);
960 
961  return NULL;
962  }
963 
964  /* check for overflow */
965  if ((const char *)(&data[i + 1] + file_len) > data_end) {
966  free(req_path);
967 
968  return NULL;
969  }
970 
971  path = strndup(data, path_len);
972  file = strndup(&data[i + 1], file_len);
973 
974  break;
975  }
976  }
977 
978  if (i == 0 && data[i] == '/' && !file && !path) {
979  /* drops here if the request is something like GET /foo */
980  path = strdup("/");
981 
982  if (len > 1) {
983  file = strndup((const char *)(data + 1), len);
984  }
985  }
986  } else {
987  /* the last character is a "/", thus the request is just a path */
988  path = strndup(data, len);
989  }
990  }
991 
992  if (len != 0) {
993  req_path->full = strndup(data, len);
994  } else {
995  req_path->full = strdup("/");
996  }
997 
998  req_path->path = path;
999  req_path->file = file;
1000 
1001  return req_path;
1002 } /* _evhtp_path_new */
1003 
1004 static void
1006  if (path == NULL) {
1007  return;
1008  }
1009 
1010  free(path->full);
1011 
1012  free(path->path);
1013  free(path->file);
1014  free(path->match_start);
1015  free(path->match_end);
1016 
1017  free(path);
1018 }
1019 
1020 static int
1022  evhtp_connection_t * c = htparser_get_userdata(p);
1023 
1024  if (c->type == evhtp_type_client) {
1025  return 0;
1026  }
1027 
1028  if (c->paused == 1) {
1029  return -1;
1030  }
1031 
1032  if (c->request) {
1033  if (c->request->finished == 1) {
1035  } else {
1036  return -1;
1037  }
1038  }
1039 
1040  if (!(c->request = _evhtp_request_new(c))) {
1041  return -1;
1042  }
1043 
1044  return 0;
1045 }
1046 
1047 static int
1048 _evhtp_request_parser_args(htparser * p, const char * data, size_t len) {
1049  evhtp_connection_t * c = htparser_get_userdata(p);
1050  evhtp_uri_t * uri = c->request->uri;
1051  const char * fragment;
1052  int ignore_fragment;
1053 
1054  if (c->type == evhtp_type_client) {
1055  /* as a client, technically we should never get here, but just in case
1056  * we return a 0 to the parser to continue.
1057  */
1058  return 0;
1059  }
1060 
1061 
1062  /* if the parser flags has the IGNORE_FRAGMENTS bit set, skip
1063  * the fragment parsing
1064  */
1065  ignore_fragment = (c->htp->parser_flags &
1067 
1068 
1069  if (!ignore_fragment && (fragment = memchr(data, '#', len))) {
1070  /* Separate fragment from query according to RFC 3986.
1071  *
1072  * XXX: not happy about using strchr stuff, maybe this functionality
1073  * is more apt as part of evhtp_parse_query()
1074  */
1075 
1076  ptrdiff_t frag_offset;
1077 
1078  frag_offset = fragment - data;
1079 
1080  if (frag_offset < len) {
1081  size_t fraglen;
1082 
1083  /* Skip '#'. */
1084  fragment += 1;
1085  frag_offset += 1;
1086  fraglen = len - frag_offset;
1087 
1088  if (!(uri->fragment = malloc(fraglen + 1))) {
1090 
1091  return -1;
1092  }
1093 
1094  memcpy(uri->fragment, fragment, fraglen);
1095 
1096  uri->fragment[fraglen] = '\0';
1097  len -= fraglen + 1; /* Skip '#' + fragment string. */
1098  }
1099  }
1100 
1101  uri->query = evhtp_parse_query_wflags(data, len, c->htp->parser_flags);
1102 
1103  if (!uri->query) {
1105 
1106  return -1;
1107  }
1108 
1109  uri->query_raw = malloc(len + 1);
1110  memcpy(uri->query_raw, data, len);
1111 
1112  uri->query_raw[len] = '\0';
1113 
1114  return 0;
1115 } /* _evhtp_request_parser_args */
1116 
1117 static int
1119  evhtp_connection_t * c = htparser_get_userdata(p);
1120 
1122  return -1;
1123  }
1124 
1125  return 0;
1126 }
1127 
1128 static int
1129 _evhtp_request_parser_header_key(htparser * p, const char * data, size_t len) {
1130  evhtp_connection_t * c = htparser_get_userdata(p);
1131  char * key_s;
1132  evhtp_header_t * hdr;
1133 
1134  key_s = malloc(len + 1);
1135  key_s[len] = '\0';
1136  memcpy(key_s, data, len);
1137 
1138  if ((hdr = evhtp_header_key_add(c->request->headers_in, key_s, 0)) == NULL) {
1140 
1141  return -1;
1142  }
1143 
1144  hdr->k_heaped = 1;
1145 
1146  return 0;
1147 }
1148 
1149 static int
1150 _evhtp_request_parser_header_val(htparser * p, const char * data, size_t len) {
1151  evhtp_connection_t * c = htparser_get_userdata(p);
1152  char * val_s;
1153  evhtp_header_t * header;
1154 
1155  val_s = malloc(len + 1);
1156  val_s[len] = '\0';
1157  memcpy(val_s, data, len);
1158 
1159  if ((header = evhtp_header_val_add(c->request->headers_in, val_s, 0)) == NULL) {
1160  free(val_s);
1162 
1163  return -1;
1164  }
1165 
1166  header->v_heaped = 1;
1167 
1168  if ((c->request->status = _evhtp_header_hook(c->request, header)) != EVHTP_RES_OK) {
1169  return -1;
1170  }
1171 
1172  return 0;
1173 }
1174 
1175 static inline evhtp_t *
1176 _evhtp_request_find_vhost(evhtp_t * evhtp, const char * name) {
1177  evhtp_t * evhtp_vhost;
1178  evhtp_alias_t * evhtp_alias;
1179 
1180  TAILQ_FOREACH(evhtp_vhost, &evhtp->vhosts, next_vhost) {
1181  if (evhtp_vhost->server_name == NULL) {
1182  continue;
1183  }
1184 
1185  if (_evhtp_glob_match(evhtp_vhost->server_name, 0, name, 0) == 1) {
1186  return evhtp_vhost;
1187  }
1188 
1189  TAILQ_FOREACH(evhtp_alias, &evhtp_vhost->aliases, next) {
1190  if (evhtp_alias->alias == NULL) {
1191  continue;
1192  }
1193 
1194  if (_evhtp_glob_match(evhtp_alias->alias, 0, name, 0) == 1) {
1195  return evhtp_vhost;
1196  }
1197  }
1198  }
1199 
1200  return NULL;
1201 }
1202 
1203 static inline int
1205  evhtp_t * evhtp;
1206  evhtp_connection_t * conn;
1207  evhtp_uri_t * uri;
1208  evhtp_path_t * path;
1209  evhtp_hooks_t * hooks;
1210  evhtp_callback_t * callback;
1211  evhtp_callback_cb cb;
1212  void * cbarg;
1213 
1214  if (request == NULL) {
1215  return -1;
1216  }
1217 
1218  if ((evhtp = request->htp) == NULL) {
1219  return -1;
1220  }
1221 
1222  if ((conn = request->conn) == NULL) {
1223  return -1;
1224  }
1225 
1226  if ((uri = request->uri) == NULL) {
1227  return -1;
1228  }
1229 
1230  if ((path = uri->path) == NULL) {
1231  return -1;
1232  }
1233 
1234  hooks = NULL;
1235  callback = NULL;
1236  cb = NULL;
1237  cbarg = NULL;
1238 
1239  if ((callback = _evhtp_callback_find(evhtp->callbacks, path->full,
1240  &path->matched_soff, &path->matched_eoff))) {
1241  /* matched a callback using both path and file (/a/b/c/d) */
1242  cb = callback->cb;
1243  cbarg = callback->cbarg;
1244  hooks = callback->hooks;
1245  } else if ((callback = _evhtp_callback_find(evhtp->callbacks, path->path,
1246  &path->matched_soff, &path->matched_eoff))) {
1247  /* matched a callback using *just* the path (/a/b/c/) */
1248  cb = callback->cb;
1249  cbarg = callback->cbarg;
1250  hooks = callback->hooks;
1251  } else {
1252  /* no callbacks found for either case, use defaults */
1253  cb = evhtp->defaults.cb;
1254  cbarg = evhtp->defaults.cbarg;
1255 
1256  path->matched_soff = 0;
1257  path->matched_eoff = (unsigned int)strlen(path->full);
1258  }
1259 
1260  if (path->match_start == NULL) {
1261  path->match_start = calloc(strlen(path->full) + 1, 1);
1262  }
1263 
1264  if (path->match_end == NULL) {
1265  path->match_end = calloc(strlen(path->full) + 1, 1);
1266  }
1267 
1268  if (path->matched_soff != UINT_MAX /*ONIG_REGION_NOTPOS*/) {
1269  if (path->matched_eoff - path->matched_soff) {
1270  memcpy(path->match_start, (void *)(path->full + path->matched_soff),
1271  path->matched_eoff - path->matched_soff);
1272  } else {
1273  memcpy(path->match_start, (void *)(path->full + path->matched_soff),
1274  strlen((const char *)(path->full + path->matched_soff)));
1275  }
1276 
1277  memcpy(path->match_end,
1278  (void *)(path->full + path->matched_eoff),
1279  strlen(path->full) - path->matched_eoff);
1280  }
1281 
1282  if (hooks != NULL) {
1283  if (request->hooks == NULL) {
1284  request->hooks = malloc(sizeof(evhtp_hooks_t));
1285  }
1286 
1287  memcpy(request->hooks, hooks, sizeof(evhtp_hooks_t));
1288  }
1289 
1290  request->cb = cb;
1291  request->cbarg = cbarg;
1292 
1293  return 0;
1294 } /* _evhtp_request_set_callbacks */
1295 
1296 static int
1297 _evhtp_request_parser_hostname(htparser * p, const char * data, size_t len) {
1298  evhtp_connection_t * c = htparser_get_userdata(p);
1299  evhtp_t * evhtp;
1300  evhtp_t * evhtp_vhost;
1301 
1302 #ifndef EVHTP_DISABLE_SSL
1303  if (c->vhost_via_sni == 1 && c->ssl != NULL) {
1304  /* use the SNI set hostname instead of the header hostname */
1305  const char * host;
1306 
1307  host = SSL_get_servername(c->ssl, TLSEXT_NAMETYPE_host_name);
1308 
1309  if ((c->request->status = _evhtp_hostname_hook(c->request, host)) != EVHTP_RES_OK) {
1310  return -1;
1311  }
1312 
1313  return 0;
1314  }
1315 #endif
1316 
1317  evhtp = c->htp;
1318 
1319  /* since this is called after _evhtp_request_parser_path(), which already
1320  * setup callbacks for the URI, we must now attempt to find callbacks which
1321  * are specific to this host.
1322  */
1323  _evhtp_lock(evhtp);
1324  {
1325  if ((evhtp_vhost = _evhtp_request_find_vhost(evhtp, data))) {
1326  _evhtp_lock(evhtp_vhost);
1327  {
1328  /* if we found a match for the host, we must set the htp
1329  * variables for both the connection and the request.
1330  */
1331  c->htp = evhtp_vhost;
1332  c->request->htp = evhtp_vhost;
1333 
1335  }
1336  _evhtp_unlock(evhtp_vhost);
1337  }
1338  }
1339  _evhtp_unlock(evhtp);
1340 
1341  if ((c->request->status = _evhtp_hostname_hook(c->request, data)) != EVHTP_RES_OK) {
1342  return -1;
1343  }
1344 
1345  return 0;
1346 } /* _evhtp_request_parser_hostname */
1347 
1348 static int
1350  if (c && c->request && !c->request->uri) {
1351  if (!(c->request->uri = _evhtp_uri_new())) {
1353 
1354  return -1;
1355  }
1356  }
1357 
1358  return 0;
1359 }
1360 
1361 static int
1362 _evhtp_request_parser_host(htparser * p, const char * data, size_t len) {
1363  evhtp_connection_t * c = htparser_get_userdata(p);
1364  evhtp_authority_t * authority;
1365 
1366  if (_evhtp_require_uri(c) != 0) {
1367  return -1;
1368  }
1369 
1370  authority = c->request->uri->authority;
1371  authority->hostname = strndup(data, len);
1372 
1373  if (!authority->hostname) {
1375 
1376  return -1;
1377  }
1378 
1379  return 0;
1380 }
1381 
1382 static int
1383 _evhtp_request_parser_port(htparser * p, const char * data, size_t len) {
1384  evhtp_connection_t * c = htparser_get_userdata(p);
1385  evhtp_authority_t * authority;
1386  char * endptr;
1387  unsigned long port;
1388 
1389  if (_evhtp_require_uri(c) != 0) {
1390  return -1;
1391  }
1392 
1393  authority = c->request->uri->authority;
1394  port = strtoul(data, &endptr, 10);
1395 
1396  if (endptr - data != len || port > 65535) {
1398 
1399  return -1;
1400  }
1401 
1402  authority->port = port;
1403 
1404  return 0;
1405 }
1406 
1407 static int
1408 _evhtp_request_parser_path(htparser * p, const char * data, size_t len) {
1409  evhtp_connection_t * c = htparser_get_userdata(p);
1410  evhtp_path_t * path;
1411 
1412  if (_evhtp_require_uri(c) != 0) {
1413  return -1;
1414  }
1415 
1416  if (!(path = _evhtp_path_new(data, len))) {
1418 
1419  return -1;
1420  }
1421 
1422  c->request->uri->path = path;
1423  c->request->uri->scheme = htparser_get_scheme(p);
1424  c->request->method = htparser_get_method(p);
1425 
1426  _evhtp_lock(c->htp);
1427  {
1429  }
1430  _evhtp_unlock(c->htp);
1431 
1432  if ((c->request->status = _evhtp_path_hook(c->request, path)) != EVHTP_RES_OK) {
1433  return -1;
1434  }
1435 
1436  return 0;
1437 } /* _evhtp_request_parser_path */
1438 
1439 static int
1441  evhtp_connection_t * c = htparser_get_userdata(p);
1442 
1443  /* XXX proto should be set with htparsers on_hdrs_begin hook */
1444  c->request->keepalive = htparser_should_keep_alive(p);
1445  c->request->proto = _evhtp_protocol(htparser_get_major(p), htparser_get_minor(p));
1447 
1448  if (c->request->status != EVHTP_RES_OK) {
1449  return -1;
1450  }
1451 
1452  if (c->type == evhtp_type_server && c->htp->disable_100_cont == 0) {
1453  /* only send a 100 continue response if it hasn't been disabled via
1454  * evhtp_disable_100_continue.
1455  */
1456  if (!evhtp_header_find(c->request->headers_in, "Expect")) {
1457  return 0;
1458  }
1459 
1460  evbuffer_add_printf(bufferevent_get_output(c->bev),
1461  "HTTP/%c.%c 100 Continue\r\n\r\n",
1462  evhtp_modp_uchartoa(htparser_get_major(p)),
1463  evhtp_modp_uchartoa(htparser_get_minor(p)));
1464  }
1465 
1466  return 0;
1467 }
1468 
1469 static int
1470 _evhtp_request_parser_body(htparser * p, const char * data, size_t len) {
1471  evhtp_connection_t * c = htparser_get_userdata(p);
1472  evbuf_t * buf;
1473  int res = 0;
1474 
1475  if (c->max_body_size > 0 && c->body_bytes_read + len >= c->max_body_size) {
1476  c->error = 1;
1478 
1479  return -1;
1480  }
1481 
1482  buf = evbuffer_new();
1483  evbuffer_add(buf, data, len);
1484 
1485  if ((c->request->status = _evhtp_body_hook(c->request, buf)) != EVHTP_RES_OK) {
1486  res = -1;
1487  }
1488 
1489  if (evbuffer_get_length(buf)) {
1490  evbuffer_add_buffer(c->request->buffer_in, buf);
1491  }
1492 
1493  evbuffer_free(buf);
1494 
1495  c->body_bytes_read += len;
1496 
1497  return res;
1498 }
1499 
1500 static int
1502  evhtp_connection_t * c = htparser_get_userdata(p);
1503 
1505  htparser_get_content_length(p))) != EVHTP_RES_OK) {
1506  return -1;
1507  }
1508 
1509  return 0;
1510 }
1511 
1512 static int
1514  evhtp_connection_t * c = htparser_get_userdata(p);
1515 
1517  return -1;
1518  }
1519 
1520  return 0;
1521 }
1522 
1523 static int
1525  evhtp_connection_t * c = htparser_get_userdata(p);
1526 
1528  return -1;
1529  }
1530 
1531  return 0;
1532 }
1533 
1544 static int
1546  const char * content_type;
1547 
1548  if (req == NULL) {
1549  return 0;
1550  }
1551 
1552  if (req->uri == NULL || req->uri->query != NULL) {
1553  return 0;
1554  }
1555 
1556  if (evhtp_request_content_len(req) == 0) {
1557  return 0;
1558  }
1559 
1560  if (evhtp_request_content_len(req) !=
1561  evbuffer_get_length(req->buffer_in)) {
1562  return 0;
1563  }
1564 
1565  content_type = evhtp_kv_find(req->headers_in, "content-type");
1566 
1567  if (content_type == NULL) {
1568  return 0;
1569  }
1570 
1571  if (strncasecmp(content_type, "application/x-www-form-urlencoded", 33)) {
1572  return 0;
1573  }
1574 
1575  return 1;
1576 }
1577 
1578 static int
1580  evhtp_connection_t * c = htparser_get_userdata(p);
1581 
1582  if (c->paused == 1) {
1583  return -1;
1584  }
1585 
1586  /* check to see if we should use the body of the request as the query
1587  * arguments.
1588  */
1589  if (_evhtp_should_parse_query_body(c->request) == 1) {
1590  const char * body;
1591  size_t body_len;
1592  evhtp_uri_t * uri;
1593  evbuf_t * buf_in;
1594 
1595  uri = c->request->uri;
1596  buf_in = c->request->buffer_in;
1597 
1598  body_len = evbuffer_get_length(buf_in);
1599  body = (const char *)evbuffer_pullup(buf_in, body_len);
1600 
1601  uri->query_raw = calloc(body_len + 1, 1);
1602  memcpy(uri->query_raw, body, body_len);
1603 
1604  uri->query = evhtp_parse_query(body, body_len);
1605  }
1606 
1607 
1608  /*
1609  * XXX c->request should never be NULL, but we have found some path of
1610  * execution where this actually happens. We will check for now, but the bug
1611  * path needs to be tracked down.
1612  *
1613  */
1614  if (c->request && c->request->cb) {
1615  (c->request->cb)(c->request, c->request->cbarg);
1616  }
1617 
1618  if (c->paused == 1) {
1619  return -1;
1620  }
1621 
1622  return 0;
1623 } /* _evhtp_request_parser_fini */
1624 
1625 static int
1626 _evhtp_create_headers(evhtp_header_t * header, void * arg) {
1627  evbuf_t * buf = arg;
1628 
1629  evbuffer_expand(buf, header->klen + 2 + header->vlen + 2);
1630  evbuffer_add(buf, header->key, header->klen);
1631  evbuffer_add(buf, ": ", 2);
1632  evbuffer_add(buf, header->val, header->vlen);
1633  evbuffer_add(buf, "\r\n", 2);
1634 
1635  return 0;
1636 }
1637 
1638 static evbuf_t *
1640  evbuf_t * buf;
1641  const char * content_type;
1642  char res_buf[2048];
1643  int sres;
1644  size_t out_len;
1645  unsigned char major;
1646  unsigned char minor;
1647  char out_buf[64];
1648 
1649 
1650  content_type = evhtp_header_find(request->headers_out, "Content-Type");
1651  out_len = evbuffer_get_length(request->buffer_out);
1652  buf = evbuffer_new();
1653 
1654  if (htparser_get_multipart(request->conn->parser) == 1) {
1655  goto check_proto;
1656  }
1657 
1658  if (out_len && request->chunked == 0) {
1659  /* add extra headers (like content-length/type) if not already present */
1660 
1661  if (!evhtp_header_find(request->headers_out, "Content-Length")) {
1662  /* convert the buffer_out length to a string and set
1663  * and add the new Content-Length header.
1664  */
1665  evhtp_modp_sizetoa(out_len, out_buf);
1666 
1668  evhtp_header_new("Content-Length", out_buf, 0, 1));
1669  }
1670 
1671  if (!content_type) {
1673  evhtp_header_new("Content-Type", "text/plain", 0, 0));
1674  }
1675  } else {
1676  if (!evhtp_header_find(request->headers_out, "Content-Length")) {
1677  const char * chunked = evhtp_header_find(request->headers_out,
1678  "transfer-encoding");
1679 
1680  if (!chunked || !strstr(chunked, "chunked")) {
1682  evhtp_header_new("Content-Length", "0", 0, 0));
1683  }
1684  }
1685  }
1686 
1687 check_proto:
1688  /* add the proper keep-alive type headers based on http version */
1689  switch (request->proto) {
1690  case EVHTP_PROTO_11:
1691  if (request->keepalive == 0) {
1692  /* protocol is HTTP/1.1 but client wanted to close */
1694  evhtp_header_new("Connection", "close", 0, 0));
1695  }
1696  break;
1697  case EVHTP_PROTO_10:
1698  if (request->keepalive == 1) {
1699  /* protocol is HTTP/1.0 and clients wants to keep established */
1701  evhtp_header_new("Connection", "keep-alive", 0, 0));
1702  }
1703  break;
1704  default:
1705  /* this sometimes happens when a response is made but paused before
1706  * the method has been parsed */
1707  htparser_set_major(request->conn->parser, 1);
1708  htparser_set_minor(request->conn->parser, 0);
1709  break;
1710  } /* switch */
1711 
1712 
1713  /* attempt to add the status line into a temporary buffer and then use
1714  * evbuffer_add(). Using plain old snprintf() will be faster than
1715  * evbuffer_add_printf(). If the snprintf() fails, which it rarely should,
1716  * we fallback to using evbuffer_add_printf().
1717  */
1718 
1719  major = evhtp_modp_uchartoa(htparser_get_major(request->conn->parser));
1720  minor = evhtp_modp_uchartoa(htparser_get_minor(request->conn->parser));
1721 
1722  evhtp_modp_u32toa((uint32_t)code, out_buf);
1723 
1724  sres = snprintf(res_buf, sizeof(res_buf), "HTTP/%c.%c %s %s\r\n",
1725  major, minor, out_buf, status_code_to_str(code));
1726 
1727  if (sres >= sizeof(res_buf) || sres < 0) {
1728  /* failed to fit the whole thing in the res_buf, so just fallback to
1729  * using evbuffer_add_printf().
1730  */
1731  evbuffer_add_printf(buf, "HTTP/%c.%c %d %s\r\n",
1732  major, minor,
1733  code, status_code_to_str(code));
1734  } else {
1735  /* copy the res_buf using evbuffer_add() instead of add_printf() */
1736  evbuffer_add(buf, res_buf, sres);
1737  }
1738 
1739 
1741  evbuffer_add(buf, "\r\n", 2);
1742 
1743  if (evbuffer_get_length(request->buffer_out)) {
1744  evbuffer_add_buffer(buf, request->buffer_out);
1745  }
1746 
1747  return buf;
1748 } /* _evhtp_create_reply */
1749 
1750 static void
1751 _evhtp_connection_resumecb(int fd, short events, void * arg) {
1752  evhtp_connection_t * c = arg;
1753 
1754  c->paused = 0;
1755 
1756  if (c->request) {
1757  c->request->status = EVHTP_RES_OK;
1758  }
1759 
1760  if (c->free_connection == 1) {
1762 
1763  return;
1764  }
1765 
1766  /* XXX this is a hack to show a potential fix for issues/86, the main indea
1767  * is that you call resume AFTER you have sent the reply (not BEFORE).
1768  *
1769  * When it has been decided this is a proper fix, the pause bit should be
1770  * changed to a state-type flag.
1771  */
1772 
1773  if (evbuffer_get_length(bufferevent_get_output(c->bev))) {
1774  bufferevent_enable(c->bev, EV_WRITE);
1775  c->waiting = 1;
1776  } else {
1777  bufferevent_enable(c->bev, EV_READ | EV_WRITE);
1779  }
1780 }
1781 
1782 static void
1783 _evhtp_connection_readcb(evbev_t * bev, void * arg) {
1784  evhtp_connection_t * c = arg;
1785  void * buf;
1786  size_t nread;
1787  size_t avail;
1788 
1789  avail = evbuffer_get_length(bufferevent_get_input(bev));
1790 
1791  if (avail == 0) {
1792  return;
1793  }
1794 
1795  if (c->request) {
1796  c->request->status = EVHTP_RES_OK;
1797  }
1798 
1799  if (c->paused == 1) {
1800  return;
1801  }
1802 
1803  buf = evbuffer_pullup(bufferevent_get_input(bev), avail);
1804 
1805  nread = htparser_run(c->parser, &request_psets, (const char *)buf, avail);
1806 
1807  if (c->owner != 1) {
1808  /*
1809  * someone has taken the ownership of this connection, we still need to
1810  * drain the input buffer that had been read up to this point.
1811  */
1812  evbuffer_drain(bufferevent_get_input(bev), nread);
1814 
1815  return;
1816  }
1817 
1818  if (c->request) {
1819  switch (c->request->status) {
1823 
1824  return;
1825  default:
1826  break;
1827  }
1828  }
1829 
1830  evbuffer_drain(bufferevent_get_input(bev), nread);
1831 
1832  if (c->request && c->request->status == EVHTP_RES_PAUSE) {
1834  } else if (htparser_get_error(c->parser) != htparse_error_none) {
1836  }
1837 } /* _evhtp_connection_readcb */
1838 
1839 static void
1841  evhtp_connection_t * c = arg;
1842 
1843  if (c->request == NULL) {
1844  return;
1845  }
1846 
1848 
1849  if (c->paused == 1) {
1850  return;
1851  }
1852 
1853  if (c->waiting == 1) {
1854  c->waiting = 0;
1855 
1856  bufferevent_enable(bev, EV_READ);
1857 
1858  if (evbuffer_get_length(bufferevent_get_input(bev))) {
1859  _evhtp_connection_readcb(bev, arg);
1860  }
1861 
1862  return;
1863  }
1864 
1865  if (c->request->finished == 0 || evbuffer_get_length(bufferevent_get_output(bev))) {
1866  return;
1867  }
1868 
1869 
1870  /*
1871  * if there is a set maximum number of keepalive requests configured, check
1872  * to make sure we are not over it. If we have gone over the max we set the
1873  * keepalive bit to 0, thus closing the connection.
1874  */
1875  if (c->htp->max_keepalive_requests) {
1876  if (++c->num_requests >= c->htp->max_keepalive_requests) {
1877  c->request->keepalive = 0;
1878  }
1879  }
1880 
1881  if (c->request->keepalive == 1) {
1883 
1884  c->keepalive = 1;
1885  c->request = NULL;
1886  c->body_bytes_read = 0;
1887 
1888  if (c->htp->parent && c->vhost_via_sni == 0) {
1889  /* this request was servied by a virtual host evhtp_t structure
1890  * which was *NOT* found via SSL SNI lookup. In this case we want to
1891  * reset our connections evhtp_t structure back to the original so
1892  * that subsequent requests can have a different Host: header.
1893  */
1894  evhtp_t * orig_htp = c->htp->parent;
1895 
1896  c->htp = orig_htp;
1897  }
1898 
1899  htparser_init(c->parser, htp_type_request);
1900 
1901 
1902  htparser_set_userdata(c->parser, c);
1903 
1904  return;
1905  } else {
1907 
1908  return;
1909  }
1910 
1911  return;
1912 } /* _evhtp_connection_writecb */
1913 
1914 static void
1915 _evhtp_connection_eventcb(evbev_t * bev, short events, void * arg) {
1916  evhtp_connection_t * c = arg;
1917 
1918  if (c->hooks && c->hooks->on_event) {
1919  (c->hooks->on_event)(c, events, c->hooks->on_event_arg);
1920  }
1921 
1922  if ((events & BEV_EVENT_CONNECTED)) {
1923  if (c->type == evhtp_type_client) {
1924  c->connected = 1;
1925  bufferevent_setcb(bev,
1929  }
1930 
1931  return;
1932  }
1933 
1934 #ifndef EVHTP_DISABLE_SSL
1935  if (c->ssl && !(events & BEV_EVENT_EOF)) {
1936  /* XXX need to do better error handling for SSL specific errors */
1937  c->error = 1;
1938 
1939  if (c->request) {
1940  c->request->error = 1;
1941  }
1942  }
1943 #endif
1944 
1945  if (events == (BEV_EVENT_EOF | BEV_EVENT_READING)) {
1946  if (errno == EAGAIN) {
1947  /* libevent will sometimes recv again when it's not actually ready,
1948  * this results in a 0 return value, and errno will be set to EAGAIN
1949  * (try again). This does not mean there is a hard socket error, but
1950  * simply needs to be read again.
1951  *
1952  * but libevent will disable the read side of the bufferevent
1953  * anyway, so we must re-enable it.
1954  */
1955  bufferevent_enable(bev, EV_READ);
1956  errno = 0;
1957 
1958  return;
1959  }
1960  }
1961 
1962  c->error = 1;
1963  c->connected = 0;
1964 
1965  _evhtp_connection_error_hook(c, events);
1966 
1967  if (c->paused == 1) {
1968  c->free_connection = 1;
1969  } else {
1971  }
1972 } /* _evhtp_connection_eventcb */
1973 
1974 static int
1976  void * args;
1977  evhtp_res res;
1978 
1979  if (htp->defaults.pre_accept == NULL) {
1980  return 0;
1981  }
1982 
1983  args = htp->defaults.pre_accept_cbarg;
1984  res = htp->defaults.pre_accept(conn, args);
1985 
1986  if (res != EVHTP_RES_OK) {
1987  return -1;
1988  }
1989 
1990  return 0;
1991 }
1992 
1993 static int
1994 _evhtp_connection_accept(evbase_t * evbase, evhtp_connection_t * connection) {
1995  struct timeval * c_recv_timeo;
1996  struct timeval * c_send_timeo;
1997 
1998  if (_evhtp_run_pre_accept(connection->htp, connection) < 0) {
1999  evutil_closesocket(connection->sock);
2000 
2001  return -1;
2002  }
2003 
2004 #ifndef EVHTP_DISABLE_SSL
2005  if (connection->htp->ssl_ctx != NULL) {
2006  connection->ssl = SSL_new(connection->htp->ssl_ctx);
2007  connection->bev = bufferevent_openssl_socket_new(evbase,
2008  connection->sock,
2009  connection->ssl,
2010  BUFFEREVENT_SSL_ACCEPTING,
2011  connection->htp->bev_flags);
2012  SSL_set_app_data(connection->ssl, connection);
2013  goto end;
2014  }
2015 #endif
2016 
2017  connection->bev = bufferevent_socket_new(evbase,
2018  connection->sock,
2019  connection->htp->bev_flags);
2020 #ifndef EVHTP_DISABLE_SSL
2021 end:
2022 #endif
2023 
2024  if (connection->recv_timeo.tv_sec || connection->recv_timeo.tv_usec) {
2025  c_recv_timeo = &connection->recv_timeo;
2026  } else if (connection->htp->recv_timeo.tv_sec ||
2027  connection->htp->recv_timeo.tv_usec) {
2028  c_recv_timeo = &connection->htp->recv_timeo;
2029  } else {
2030  c_recv_timeo = NULL;
2031  }
2032 
2033  if (connection->send_timeo.tv_sec || connection->send_timeo.tv_usec) {
2034  c_send_timeo = &connection->send_timeo;
2035  } else if (connection->htp->send_timeo.tv_sec ||
2036  connection->htp->send_timeo.tv_usec) {
2037  c_send_timeo = &connection->htp->send_timeo;
2038  } else {
2039  c_send_timeo = NULL;
2040  }
2041 
2042  evhtp_connection_set_timeouts(connection, c_recv_timeo, c_send_timeo);
2043 
2044  connection->resume_ev = event_new(evbase, -1, EV_READ | EV_PERSIST,
2045  _evhtp_connection_resumecb, connection);
2046  event_add(connection->resume_ev, NULL);
2047 
2048  bufferevent_enable(connection->bev, EV_READ);
2049  bufferevent_setcb(connection->bev,
2052  _evhtp_connection_eventcb, connection);
2053 
2054  return 0;
2055 } /* _evhtp_connection_accept */
2056 
2057 static void
2060 }
2061 
2062 static evhtp_connection_t *
2063 _evhtp_connection_new(evhtp_t * htp, evutil_socket_t sock, evhtp_type type) {
2064  evhtp_connection_t * connection;
2065  htp_type ptype;
2066 
2067  switch (type) {
2068  case evhtp_type_client:
2069  ptype = htp_type_response;
2070  break;
2071  case evhtp_type_server:
2072  ptype = htp_type_request;
2073  break;
2074  default:
2075 
2076  return NULL;
2077  }
2078 
2079  if (!(connection = calloc(sizeof(evhtp_connection_t), 1))) {
2080  return NULL;
2081  }
2082 
2083  connection->error = 0;
2084  connection->owner = 1;
2085  connection->paused = 0;
2086  connection->connected = 0;
2087  connection->sock = sock;
2088  connection->htp = htp;
2089  connection->type = type;
2090  connection->parser = htparser_new();
2091 
2092  if (!connection->parser) {
2093  evhtp_safe_free(connection, free);
2094 
2095  return NULL;
2096  }
2097 
2098  htparser_init(connection->parser, ptype);
2099  htparser_set_userdata(connection->parser, connection);
2100 
2101 #ifdef EVHTP_FUTURE_USE
2102  TAILQ_INIT(&connection->pending);
2103 #endif
2104 
2105  return connection;
2106 } /* _evhtp_connection_new */
2107 
2108 #ifdef LIBEVENT_HAS_SHUTDOWN
2109 #ifndef EVHTP_DISABLE_SSL
2110 static void
2111 _evhtp_shutdown_eventcb(evbev_t * bev, short events, void * arg) {
2112 }
2113 
2114 #endif
2115 #endif
2116 
2117 static int
2119  void * args;
2120  evhtp_res res;
2121 
2122  if (htp->defaults.post_accept == NULL) {
2123  return 0;
2124  }
2125 
2126  args = htp->defaults.post_accept_cbarg;
2127  res = htp->defaults.post_accept(connection, args);
2128 
2129  if (res != EVHTP_RES_OK) {
2130  return -1;
2131  }
2132 
2133  return 0;
2134 }
2135 
2136 #ifndef EVHTP_DISABLE_EVTHR
2137 static void
2138 _evhtp_run_in_thread(evthr_t * thr, void * arg, void * shared) {
2139  evhtp_t * htp = shared;
2140  evhtp_connection_t * connection = arg;
2141 
2142  connection->evbase = evthr_get_base(thr);
2143  connection->thread = thr;
2144 
2145  if (_evhtp_connection_accept(connection->evbase, connection) < 0) {
2146  evhtp_connection_free(connection);
2147 
2148  return;
2149  }
2150 
2151  if (_evhtp_run_post_accept(htp, connection) < 0) {
2152  evhtp_connection_free(connection);
2153 
2154  return;
2155  }
2156 }
2157 
2158 #endif
2159 
2160 static void
2161 _evhtp_accept_cb(evserv_t * serv, int fd, struct sockaddr * s, int sl, void * arg) {
2162  evhtp_t * htp = arg;
2163  evhtp_connection_t * connection;
2164 
2165  if (!(connection = _evhtp_connection_new(htp, fd, evhtp_type_server))) {
2166  return;
2167  }
2168 
2169  connection->saddr = malloc(sl);
2170  memcpy(connection->saddr, s, sl);
2171 
2172 #ifndef EVHTP_DISABLE_EVTHR
2173  if (htp->thr_pool != NULL) {
2174  if (evthr_pool_defer(htp->thr_pool, _evhtp_run_in_thread, connection) != EVTHR_RES_OK) {
2175  evutil_closesocket(connection->sock);
2176  evhtp_connection_free(connection);
2177 
2178  return;
2179  }
2180 
2181  return;
2182  }
2183 #endif
2184  connection->evbase = htp->evbase;
2185 
2186  if (_evhtp_connection_accept(htp->evbase, connection) < 0) {
2187  evhtp_connection_free(connection);
2188 
2189  return;
2190  }
2191 
2192  if (_evhtp_run_post_accept(htp, connection) < 0) {
2193  evhtp_connection_free(connection);
2194 
2195  return;
2196  }
2197 }
2198 
2199 #ifndef EVHTP_DISABLE_SSL
2200 #ifndef EVHTP_DISABLE_EVTHR
2201 static unsigned long
2203 #ifndef WIN32
2204 
2205  return (unsigned long)pthread_self();
2206 #else
2207 
2208  return (unsigned long)(pthread_self().p);
2209 #endif
2210 }
2211 
2212 static void
2213 _evhtp_ssl_thread_lock(int mode, int type, const char * file, int line) {
2214  if (type < ssl_num_locks) {
2215  if (mode & CRYPTO_LOCK) {
2216  pthread_mutex_lock(&(ssl_locks[type]));
2217  } else {
2218  pthread_mutex_unlock(&(ssl_locks[type]));
2219  }
2220  }
2221 }
2222 
2223 #endif
2224 static void
2226  evhtp_t * htp;
2227  evhtp_ssl_cfg_t * cfg;
2228  unsigned char * sid;
2229  unsigned int slen;
2230 
2231  htp = (evhtp_t *)SSL_CTX_get_app_data(ctx);
2232  cfg = htp->ssl_cfg;
2233 
2234  sid = sess->session_id;
2235  slen = sess->session_id_length;
2236 
2237  if (cfg->scache_del) {
2238  (cfg->scache_del)(htp, sid, slen);
2239  }
2240 }
2241 
2242 static int
2244  evhtp_connection_t * connection;
2245  evhtp_ssl_cfg_t * cfg;
2246  unsigned char * sid;
2247  int slen;
2248 
2249  connection = (evhtp_connection_t *)SSL_get_app_data(ssl);
2250  cfg = connection->htp->ssl_cfg;
2251 
2252  sid = sess->session_id;
2253  slen = sess->session_id_length;
2254 
2255  SSL_set_timeout(sess, cfg->scache_timeout);
2256 
2257  if (cfg->scache_add) {
2258  return (cfg->scache_add)(connection, sid, slen, sess);
2259  }
2260 
2261  return 0;
2262 }
2263 
2264 static evhtp_ssl_sess_t *
2265 _evhtp_ssl_get_scache_ent(evhtp_ssl_t * ssl, unsigned char * sid, int sid_len, int * copy) {
2266  evhtp_connection_t * connection;
2267  evhtp_ssl_cfg_t * cfg;
2268  evhtp_ssl_sess_t * sess;
2269 
2270  connection = (evhtp_connection_t * )SSL_get_app_data(ssl);
2271  cfg = connection->htp->ssl_cfg;
2272  sess = NULL;
2273 
2274  if (cfg->scache_get) {
2275  sess = (cfg->scache_get)(connection, sid, sid_len);
2276  }
2277 
2278  *copy = 0;
2279 
2280  return sess;
2281 }
2282 
2283 static int
2284 _evhtp_ssl_servername(evhtp_ssl_t * ssl, int * unused, void * arg) {
2285  const char * sname;
2286  evhtp_connection_t * connection;
2287  evhtp_t * evhtp;
2288  evhtp_t * evhtp_vhost;
2289 
2290  if (!(sname = SSL_get_servername(ssl, TLSEXT_NAMETYPE_host_name))) {
2291  return SSL_TLSEXT_ERR_NOACK;
2292  }
2293 
2294  if (!(connection = SSL_get_app_data(ssl))) {
2295  return SSL_TLSEXT_ERR_NOACK;
2296  }
2297 
2298  if (!(evhtp = connection->htp)) {
2299  return SSL_TLSEXT_ERR_NOACK;
2300  }
2301 
2302  if ((evhtp_vhost = _evhtp_request_find_vhost(evhtp, sname))) {
2303  connection->htp = evhtp_vhost;
2304  connection->vhost_via_sni = 1;
2305 
2306  SSL_set_SSL_CTX(ssl, evhtp_vhost->ssl_ctx);
2307  SSL_set_options(ssl, SSL_CTX_get_options(ssl->ctx));
2308 
2309  if ((SSL_get_verify_mode(ssl) == SSL_VERIFY_NONE) ||
2310  (SSL_num_renegotiations(ssl) == 0)) {
2311  SSL_set_verify(ssl, SSL_CTX_get_verify_mode(ssl->ctx),
2312  SSL_CTX_get_verify_callback(ssl->ctx));
2313  }
2314 
2315  return SSL_TLSEXT_ERR_OK;
2316  }
2317 
2318  return SSL_TLSEXT_ERR_NOACK;
2319 } /* _evhtp_ssl_servername */
2320 
2321 #endif
2322 
2323 /*
2324  * PUBLIC FUNCTIONS
2325  */
2326 
2327 htp_method
2329  return htparser_get_method(r->conn->parser);
2330 }
2331 
2337 void
2339  c->paused = 1;
2340 
2341  bufferevent_disable(c->bev, EV_READ | EV_WRITE);
2342 
2343  return;
2344 }
2345 
2351 void
2353  c->paused = 0;
2354 
2355  event_active(c->resume_ev, EV_WRITE, 1);
2356 
2357  return;
2358 }
2359 
2367 void
2369  request->status = EVHTP_RES_PAUSE;
2370  evhtp_connection_pause(request->conn);
2371 }
2372 
2380 void
2382  evhtp_connection_resume(request->conn);
2383 }
2384 
2386 evhtp_header_key_add(evhtp_headers_t * headers, const char * key, char kalloc) {
2387  evhtp_header_t * header;
2388 
2389  if (!(header = evhtp_header_new(key, NULL, kalloc, 0))) {
2390  return NULL;
2391  }
2392 
2393  evhtp_headers_add_header(headers, header);
2394 
2395  return header;
2396 }
2397 
2399 evhtp_header_val_add(evhtp_headers_t * headers, const char * val, char valloc) {
2400  evhtp_header_t * header;
2401 
2402  if (!headers || !val) {
2403  return NULL;
2404  }
2405 
2406  if (!(header = TAILQ_LAST(headers, evhtp_headers_s))) {
2407  return NULL;
2408  }
2409 
2410  if (header->val != NULL) {
2411  return NULL;
2412  }
2413 
2414  header->vlen = strlen(val);
2415 
2416  if (valloc == 1) {
2417  header->val = malloc(header->vlen + 1);
2418  header->val[header->vlen] = '\0';
2419  memcpy(header->val, val, header->vlen);
2420  } else {
2421  header->val = (char *)val;
2422  }
2423 
2424  header->v_heaped = valloc;
2425 
2426  return header;
2427 }
2428 
2429 evhtp_kvs_t *
2431  evhtp_kvs_t * kvs = malloc(sizeof(evhtp_kvs_t));
2432 
2433  TAILQ_INIT(kvs);
2434 
2435  return kvs;
2436 }
2437 
2438 evhtp_kv_t *
2439 evhtp_kv_new(const char * key, const char * val, char kalloc, char valloc) {
2440  evhtp_kv_t * kv;
2441 
2442  if (!(kv = malloc(sizeof(evhtp_kv_t)))) {
2443  return NULL;
2444  }
2445 
2446  kv->k_heaped = kalloc;
2447  kv->v_heaped = valloc;
2448  kv->klen = 0;
2449  kv->vlen = 0;
2450  kv->key = NULL;
2451  kv->val = NULL;
2452 
2453  if (key != NULL) {
2454  kv->klen = strlen(key);
2455 
2456  if (kalloc == 1) {
2457  char * s;
2458 
2459  if (!(s = malloc(kv->klen + 1))) {
2460  evhtp_safe_free(kv, free);
2461 
2462  return NULL;
2463  }
2464 
2465  memcpy(s, key, kv->klen);
2466 
2467  s[kv->klen] = '\0';
2468  kv->key = s;
2469  } else {
2470  kv->key = (char *)key;
2471  }
2472  }
2473 
2474  if (val != NULL) {
2475  kv->vlen = strlen(val);
2476 
2477  if (valloc == 1) {
2478  char * s = malloc(kv->vlen + 1);
2479 
2480  s[kv->vlen] = '\0';
2481  memcpy(s, val, kv->vlen);
2482  kv->val = s;
2483  } else {
2484  kv->val = (char *)val;
2485  }
2486  }
2487 
2488  return kv;
2489 } /* evhtp_kv_new */
2490 
2491 void
2493  if (kv == NULL) {
2494  return;
2495  }
2496 
2497  if (kv->k_heaped) {
2498  evhtp_safe_free(kv->key, free);
2499  }
2500 
2501  if (kv->v_heaped) {
2502  evhtp_safe_free(kv->val, free);
2503  }
2504 
2505  evhtp_safe_free(kv, free);
2506 }
2507 
2508 void
2510  if (kvs == NULL || kv == NULL) {
2511  return;
2512  }
2513 
2514  TAILQ_REMOVE(kvs, kv, next);
2515 
2516  evhtp_kv_free(kv);
2517 }
2518 
2519 void
2521  evhtp_kv_t * kv;
2522  evhtp_kv_t * save;
2523 
2524  if (kvs == NULL) {
2525  return;
2526  }
2527 
2528  for (kv = TAILQ_FIRST(kvs); kv != NULL; kv = save) {
2529  save = TAILQ_NEXT(kv, next);
2530 
2531  TAILQ_REMOVE(kvs, kv, next);
2532 
2533  evhtp_kv_free(kv);
2534  }
2535 
2536  evhtp_safe_free(kvs, free);
2537 }
2538 
2539 int
2541  evhtp_kv_t * kv;
2542 
2543  if (kvs == NULL || cb == NULL) {
2544  return -1;
2545  }
2546 
2547  TAILQ_FOREACH(kv, kvs, next) {
2548  int res;
2549 
2550  if ((res = cb(kv, arg))) {
2551  return res;
2552  }
2553  }
2554 
2555  return 0;
2556 }
2557 
2558 const char *
2559 evhtp_kv_find(evhtp_kvs_t * kvs, const char * key) {
2560  evhtp_kv_t * kv;
2561 
2562  if (kvs == NULL || key == NULL) {
2563  return NULL;
2564  }
2565 
2566  TAILQ_FOREACH(kv, kvs, next) {
2567  if (strcasecmp(kv->key, key) == 0) {
2568  return kv->val;
2569  }
2570  }
2571 
2572  return NULL;
2573 }
2574 
2575 evhtp_kv_t *
2576 evhtp_kvs_find_kv(evhtp_kvs_t * kvs, const char * key) {
2577  evhtp_kv_t * kv;
2578 
2579  if (kvs == NULL || key == NULL) {
2580  return NULL;
2581  }
2582 
2583  TAILQ_FOREACH(kv, kvs, next) {
2584  if (strcasecmp(kv->key, key) == 0) {
2585  return kv;
2586  }
2587  }
2588 
2589  return NULL;
2590 }
2591 
2592 void
2594  if (kvs == NULL || kv == NULL) {
2595  return;
2596  }
2597 
2598  TAILQ_INSERT_TAIL(kvs, kv, next);
2599 }
2600 
2601 void
2603  if (dst == NULL || src == NULL) {
2604  return;
2605  }
2606 
2607  evhtp_kv_t * kv;
2608 
2609  TAILQ_FOREACH(kv, src, next) {
2610  evhtp_kvs_add_kv(dst, evhtp_kv_new(kv->key, kv->val, kv->k_heaped, kv->v_heaped));
2611  }
2612 }
2613 
2614 typedef enum {
2625 
2626 static inline int
2627 evhtp_is_hex_query_char(unsigned char ch) {
2628  switch (ch) {
2629  case 'a': case 'A':
2630  case 'b': case 'B':
2631  case 'c': case 'C':
2632  case 'd': case 'D':
2633  case 'e': case 'E':
2634  case 'f': case 'F':
2635  case '0':
2636  case '1':
2637  case '2':
2638  case '3':
2639  case '4':
2640  case '5':
2641  case '6':
2642  case '7':
2643  case '8':
2644  case '9':
2645 
2646  return 1;
2647  default:
2648 
2649  return 0;
2650  } /* switch */
2651 }
2652 
2657 };
2658 
2659 int
2660 evhtp_unescape_string(unsigned char ** out, unsigned char * str, size_t str_len) {
2661  unsigned char * optr;
2662  unsigned char * sptr;
2663  unsigned char d;
2664  unsigned char ch;
2665  unsigned char c;
2666  size_t i;
2667  enum unscape_state state;
2668 
2669  if (out == NULL || *out == NULL) {
2670  return -1;
2671  }
2672 
2673  state = unscape_state_start;
2674  optr = *out;
2675  sptr = str;
2676  d = 0;
2677 
2678  for (i = 0; i < str_len; i++) {
2679  ch = *sptr++;
2680 
2681  switch (state) {
2682  case unscape_state_start:
2683  if (ch == '%') {
2684  state = unscape_state_hex1;
2685  break;
2686  }
2687 
2688  *optr++ = ch;
2689 
2690  break;
2691  case unscape_state_hex1:
2692  if (ch >= '0' && ch <= '9') {
2693  d = (unsigned char)(ch - '0');
2694  state = unscape_state_hex2;
2695  break;
2696  }
2697 
2698  c = (unsigned char)(ch | 0x20);
2699 
2700  if (c >= 'a' && c <= 'f') {
2701  d = (unsigned char)(c - 'a' + 10);
2702  state = unscape_state_hex2;
2703  break;
2704  }
2705 
2706  state = unscape_state_start;
2707  *optr++ = ch;
2708  break;
2709  case unscape_state_hex2:
2710  state = unscape_state_start;
2711 
2712  if (ch >= '0' && ch <= '9') {
2713  ch = (unsigned char)((d << 4) + ch - '0');
2714 
2715  *optr++ = ch;
2716  break;
2717  }
2718 
2719  c = (unsigned char)(ch | 0x20);
2720 
2721  if (c >= 'a' && c <= 'f') {
2722  ch = (unsigned char)((d << 4) + c - 'a' + 10);
2723  *optr++ = ch;
2724  break;
2725  }
2726 
2727  break;
2728  } /* switch */
2729  }
2730 
2731  return 0;
2732 } /* evhtp_unescape_string */
2733 
2734 evhtp_query_t *
2735 evhtp_parse_query_wflags(const char * query, size_t len, int flags) {
2736  evhtp_query_t * query_args;
2737  query_parser_state state;
2738  size_t key_idx;
2739  size_t val_idx;
2740  unsigned char ch;
2741  size_t i;
2742 
2743 
2744  if (len > (SIZE_MAX - (len + 2))) {
2745  return NULL;
2746  }
2747 
2748  query_args = evhtp_query_new();
2749 
2750  state = s_query_start;
2751  key_idx = 0;
2752  val_idx = 0;
2753 
2754 #ifdef EVHTP_HAS_C99
2755  char key_buf[len + 1];
2756  char val_buf[len + 1];
2757 #else
2758  char * key_buf;
2759  char * val_buf;
2760 
2761  if (!(key_buf = malloc(len + 1))) {
2762  return NULL;
2763  }
2764 
2765  if (!(val_buf = malloc(len + 1))) {
2766  evhtp_safe_free(key_buf, free);
2767 
2768  return NULL;
2769  }
2770 #endif
2771 
2772  for (i = 0; i < len; i++) {
2773  ch = query[i];
2774 
2775  if (key_idx >= len || val_idx >= len) {
2776  goto error;
2777  }
2778 
2779  switch (state) {
2780  case s_query_start:
2781  key_idx = 0;
2782  val_idx = 0;
2783 
2784  key_buf[0] = '\0';
2785  val_buf[0] = '\0';
2786 
2787  state = s_query_key;
2788  /* Fall through. */
2789  case s_query_key:
2790  switch (ch) {
2791  case '=':
2792  state = s_query_val;
2793  break;
2794  case '%':
2795  key_buf[key_idx++] = ch;
2796  key_buf[key_idx] = '\0';
2797 
2798  if (!(flags & EVHTP_PARSE_QUERY_FLAG_IGNORE_HEX)) {
2799  state = s_query_key_hex_1;
2800  }
2801 
2802  break;
2803  case ';':
2805  key_buf[key_idx++] = ch;
2806  key_buf[key_idx] = '\0';
2807  break;
2808  }
2809 
2810  /* otherwise we fallthrough */
2811  case '&':
2812  /* in this state, we have a NULL value */
2813  if (!(flags & EVHTP_PARSE_QUERY_FLAG_ALLOW_NULL_VALS)) {
2814  goto error;
2815  }
2816 
2817  /* insert the key with value of NULL and set the
2818  * state back to parsing s_query_key.
2819  */
2820  evhtp_kvs_add_kv(query_args, evhtp_kv_new(key_buf, NULL, 1, 1));
2821 
2822  key_idx = 0;
2823  val_idx = 0;
2824 
2825  key_buf[0] = '\0';
2826  val_buf[0] = '\0';
2827 
2828  state = s_query_key;
2829  break;
2830  default:
2831  key_buf[key_idx++] = ch;
2832  key_buf[key_idx] = '\0';
2833  break;
2834  } /* switch */
2835  break;
2836  case s_query_key_hex_1:
2837  if (!evhtp_is_hex_query_char(ch)) {
2838  /* not hex, so we treat as a normal key */
2839  if ((key_idx + 2) >= len) {
2840  /* we need to insert \%<ch>, but not enough space */
2841  goto error;
2842  }
2843 
2844  key_buf[key_idx - 1] = '%';
2845  key_buf[key_idx++] = ch;
2846  key_buf[key_idx] = '\0';
2847 
2848  state = s_query_key;
2849  break;
2850  }
2851 
2852  key_buf[key_idx++] = ch;
2853  key_buf[key_idx] = '\0';
2854 
2855  state = s_query_key_hex_2;
2856  break;
2857  case s_query_key_hex_2:
2858  if (!evhtp_is_hex_query_char(ch)) {
2859  goto error;
2860  }
2861 
2862  key_buf[key_idx++] = ch;
2863  key_buf[key_idx] = '\0';
2864 
2865  state = s_query_key;
2866  break;
2867  case s_query_val:
2868  switch (ch) {
2869  case ';':
2871  val_buf[val_idx++] = ch;
2872  val_buf[val_idx] = '\0';
2873  break;
2874  }
2875  case '&':
2876  evhtp_kvs_add_kv(query_args, evhtp_kv_new(key_buf, val_buf, 1, 1));
2877 
2878  key_idx = 0;
2879  val_idx = 0;
2880 
2881  key_buf[0] = '\0';
2882  val_buf[0] = '\0';
2883  state = s_query_key;
2884 
2885  break;
2886  case '%':
2887  val_buf[val_idx++] = ch;
2888  val_buf[val_idx] = '\0';
2889 
2890  if (!(flags & EVHTP_PARSE_QUERY_FLAG_IGNORE_HEX)) {
2891  state = s_query_val_hex_1;
2892  }
2893 
2894  break;
2895  default:
2896  val_buf[val_idx++] = ch;
2897  val_buf[val_idx] = '\0';
2898 
2899  break;
2900  } /* switch */
2901  break;
2902  case s_query_val_hex_1:
2903  if (!evhtp_is_hex_query_char(ch)) {
2904  /* not really a hex val */
2905  if ((val_idx + 2) >= len) {
2906  /* we need to insert \%<ch>, but not enough space */
2907  goto error;
2908  }
2909 
2910  if (val_idx == 0) {
2911  goto error;
2912  }
2913 
2914  val_buf[val_idx - 1] = '%';
2915  val_buf[val_idx++] = ch;
2916  val_buf[val_idx] = '\0';
2917 
2918  state = s_query_val;
2919  break;
2920  }
2921 
2922  val_buf[val_idx++] = ch;
2923  val_buf[val_idx] = '\0';
2924 
2925  state = s_query_val_hex_2;
2926  break;
2927  case s_query_val_hex_2:
2928  if (!evhtp_is_hex_query_char(ch)) {
2929  goto error;
2930  }
2931 
2932  val_buf[val_idx++] = ch;
2933  val_buf[val_idx] = '\0';
2934 
2935  state = s_query_val;
2936  break;
2937  default:
2938  /* bad state */
2939  goto error;
2940  } /* switch */
2941  }
2942 
2943  if (key_idx) {
2944  do {
2945  if (val_idx) {
2946  evhtp_kvs_add_kv(query_args, evhtp_kv_new(key_buf, val_buf, 1, 1));
2947  break;
2948  }
2949 
2950  if (state >= s_query_val) {
2951  if (!(flags & EVHTP_PARSE_QUERY_FLAG_ALLOW_EMPTY_VALS)) {
2952  goto error;
2953  }
2954 
2955  evhtp_kvs_add_kv(query_args, evhtp_kv_new(key_buf, "", 1, 1));
2956  break;
2957  }
2958 
2959  if (!(flags & EVHTP_PARSE_QUERY_FLAG_ALLOW_NULL_VALS)) {
2960  goto error;
2961  }
2962 
2963  evhtp_kvs_add_kv(query_args, evhtp_kv_new(key_buf, NULL, 1, 0));
2964  } while (0);
2965  }
2966 
2967 #ifndef EVHTP_HAS_C99
2968  evhtp_safe_free(key_buf, free);
2969  evhtp_safe_free(val_buf, free);
2970 #endif
2971 
2972  return query_args;
2973 error:
2974 #ifndef EVHTP_HAS_C99
2975  evhtp_safe_free(key_buf, free);
2976  evhtp_safe_free(val_buf, free);
2977 #endif
2978 
2979  return NULL;
2980 } /* evhtp_parse_query */
2981 
2982 evhtp_query_t *
2983 evhtp_parse_query(const char * query, size_t len) {
2985 }
2986 
2987 void
2989  evhtp_connection_t * c;
2990  evbuf_t * reply_buf;
2991 
2992  c = evhtp_request_get_connection(request);
2993 
2994  if (!(reply_buf = _evhtp_create_reply(request, code))) {
2996 
2997  return;
2998  }
2999 
3000  bufferevent_write_buffer(c->bev, reply_buf);
3001  evbuffer_free(reply_buf);
3002 }
3003 
3004 void
3006  evhtp_connection_t * c;
3007 
3008  c = request->conn;
3009 
3010  bufferevent_write_buffer(c->bev, buf);
3011 }
3012 
3013 void
3015  request->finished = 1;
3016 }
3017 
3018 void
3020  evhtp_connection_t * c;
3021  evbuf_t * reply_buf;
3022 
3023  c = evhtp_request_get_connection(request);
3024  request->finished = 1;
3025 
3026  if (!(reply_buf = _evhtp_create_reply(request, code))) {
3027  evhtp_connection_free(request->conn);
3028 
3029  return;
3030  }
3031 
3032  bufferevent_write_buffer(evhtp_connection_get_bev(c), reply_buf);
3033  evbuffer_free(reply_buf);
3034 }
3035 
3036 int
3037 evhtp_response_needs_body(const evhtp_res code, const htp_method method) {
3038  return code != EVHTP_RES_NOCONTENT &&
3039  code != EVHTP_RES_NOTMOD &&
3040  (code < 100 || code >= 200) &&
3041  method != htp_method_HEAD;
3042 }
3043 
3044 void
3046  evhtp_header_t * content_len;
3047 
3048  if (evhtp_response_needs_body(code, request->method)) {
3049  content_len = evhtp_headers_find_header(request->headers_out, "Content-Length");
3050 
3051  switch (request->proto) {
3052  case EVHTP_PROTO_11:
3053 
3054  /*
3055  * prefer HTTP/1.1 chunked encoding to closing the connection;
3056  * note RFC 2616 section 4.4 forbids it with Content-Length:
3057  * and it's not necessary then anyway.
3058  */
3059 
3060  evhtp_kv_rm_and_free(request->headers_out, content_len);
3061  request->chunked = 1;
3062  break;
3063  case EVHTP_PROTO_10:
3064  /*
3065  * HTTP/1.0 can be chunked as long as the Content-Length header
3066  * is set to 0
3067  */
3068  evhtp_kv_rm_and_free(request->headers_out, content_len);
3069 
3071  evhtp_header_new("Content-Length", "0", 0, 0));
3072 
3073  request->chunked = 1;
3074  break;
3075  default:
3076  request->chunked = 0;
3077  break;
3078  } /* switch */
3079  } else {
3080  request->chunked = 0;
3081  }
3082 
3083  if (request->chunked == 1) {
3085  evhtp_header_new("Transfer-Encoding", "chunked", 0, 0));
3086 
3087  /*
3088  * if data already exists on the output buffer, we automagically convert
3089  * it to the first chunk.
3090  */
3091  if (evbuffer_get_length(request->buffer_out) > 0) {
3092  char lstr[128];
3093  int sres;
3094 
3095  sres = snprintf(lstr, sizeof(lstr), "%x\r\n",
3096  (unsigned)evbuffer_get_length(request->buffer_out));
3097 
3098  if (sres >= sizeof(lstr) || sres < 0) {
3099  /* overflow condition, shouldn't ever get here, but lets
3100  * terminate the connection asap */
3101  goto end;
3102  }
3103 
3104  evbuffer_prepend(request->buffer_out, lstr, strlen(lstr));
3105  evbuffer_add(request->buffer_out, "\r\n", 2);
3106  }
3107  }
3108 
3109 end:
3110  evhtp_send_reply_start(request, code);
3111 } /* evhtp_send_reply_chunk_start */
3112 
3113 void
3115  evbuf_t * output;
3116 
3117  output = bufferevent_get_output(request->conn->bev);
3118 
3119  if (evbuffer_get_length(buf) == 0) {
3120  return;
3121  }
3122 
3123  if (request->chunked == 1) {
3124  evbuffer_add_printf(output, "%x\r\n",
3125  (unsigned)evbuffer_get_length(buf));
3126  }
3127 
3128  evhtp_send_reply_body(request, buf);
3129 
3130  if (request->chunked) {
3131  evbuffer_add(output, "\r\n", 2);
3132  }
3133 
3134  bufferevent_flush(request->conn->bev, EV_WRITE, BEV_FLUSH);
3135 }
3136 
3137 void
3139  if (request->chunked == 1) {
3140  evbuffer_add(bufferevent_get_output(evhtp_request_get_bev(request)),
3141  "0\r\n\r\n", 5);
3142  }
3143 
3144  evhtp_send_reply_end(request);
3145 }
3146 
3147 void
3149  evconnlistener_free(htp->server);
3150  htp->server = NULL;
3151 }
3152 
3153 int
3154 evhtp_bind_sockaddr(evhtp_t * htp, struct sockaddr * sa, size_t sin_len, int backlog) {
3155 #ifndef WIN32
3156  signal(SIGPIPE, SIG_IGN);
3157 #endif
3158 
3159  htp->server = evconnlistener_new_bind(htp->evbase, _evhtp_accept_cb, (void *)htp,
3160  LEV_OPT_THREADSAFE | LEV_OPT_CLOSE_ON_FREE | LEV_OPT_REUSEABLE,
3161  backlog, sa, sin_len);
3162  if (!htp->server) {
3163  return -1;
3164  }
3165 
3166 #ifdef USE_DEFER_ACCEPT
3167  {
3168  evutil_socket_t sock;
3169  int one = 1;
3170 
3171  sock = evconnlistener_get_fd(htp->server);
3172 
3173  setsockopt(sock, IPPROTO_TCP, TCP_DEFER_ACCEPT, &one, (ev_socklen_t)sizeof(one));
3174  setsockopt(sock, IPPROTO_TCP, TCP_NODELAY, &one, (ev_socklen_t)sizeof(one));
3175  }
3176 #endif
3177 
3178 #ifndef EVHTP_DISABLE_SSL
3179  if (htp->ssl_ctx != NULL) {
3180  /* if ssl is enabled and we have virtual hosts, set our servername
3181  * callback. We do this here because we want to make sure that this gets
3182  * set after all potential virtualhosts have been set, not just after
3183  * ssl_init.
3184  */
3185  if (TAILQ_FIRST(&htp->vhosts) != NULL) {
3186  SSL_CTX_set_tlsext_servername_callback(htp->ssl_ctx,
3188  }
3189  }
3190 #endif
3191 
3192  return 0;
3193 }
3194 
3195 int
3196 evhtp_bind_socket(evhtp_t * htp, const char * baddr, uint16_t port, int backlog) {
3197 #ifndef NO_SYS_UN
3198  struct sockaddr_un sun;
3199 #endif
3200  struct sockaddr_in6 sin6;
3201  struct sockaddr_in sin;
3202  struct sockaddr * sa;
3203  size_t sin_len;
3204 
3205  memset(&sin, 0, sizeof(sin));
3206 
3207  if (!strncmp(baddr, "ipv6:", 5)) {
3208  memset(&sin6, 0, sizeof(sin6));
3209 
3210  baddr += 5;
3211  sin_len = sizeof(struct sockaddr_in6);
3212  sin6.sin6_port = htons(port);
3213  sin6.sin6_family = AF_INET6;
3214 
3215  evutil_inet_pton(AF_INET6, baddr, &sin6.sin6_addr);
3216  sa = (struct sockaddr *)&sin6;
3217  } else if (!strncmp(baddr, "unix:", 5)) {
3218 #ifndef NO_SYS_UN
3219  baddr += 5;
3220 
3221  if (strlen(baddr) >= sizeof(sun.sun_path)) {
3222  return -1;
3223  }
3224 
3225  memset(&sun, 0, sizeof(sun));
3226 
3227  sin_len = sizeof(struct sockaddr_un);
3228  sun.sun_family = AF_UNIX;
3229 
3230  strncpy(sun.sun_path, baddr, strlen(baddr));
3231 
3232  sa = (struct sockaddr *)&sun;
3233 #else
3234 
3235  return -1;
3236 #endif
3237  } else {
3238  if (!strncmp(baddr, "ipv4:", 5)) {
3239  baddr += 5;
3240  }
3241 
3242  sin_len = sizeof(struct sockaddr_in);
3243 
3244  sin.sin_family = AF_INET;
3245  sin.sin_port = htons(port);
3246  sin.sin_addr.s_addr = inet_addr(baddr);
3247 
3248  sa = (struct sockaddr *)&sin;
3249  }
3250 
3251  return evhtp_bind_sockaddr(htp, sa, sin_len, backlog);
3252 } /* evhtp_bind_socket */
3253 
3254 void
3256  evhtp_callback_t * callback;
3257  evhtp_callback_t * tmp;
3258 
3259  if (callbacks == NULL) {
3260  return;
3261  }
3262 
3263  TAILQ_FOREACH_SAFE(callback, callbacks, next, tmp) {
3264  TAILQ_REMOVE(callbacks, callback, next);
3265 
3266  evhtp_safe_free(callback, evhtp_callback_free);
3267  }
3268 
3269  evhtp_safe_free(callbacks, free);
3270 }
3271 
3273 evhtp_callback_new(const char * path, evhtp_callback_type type, evhtp_callback_cb cb, void * arg) {
3274  evhtp_callback_t * hcb;
3275 
3276  if (!(hcb = calloc(sizeof(evhtp_callback_t), 1))) {
3277  return NULL;
3278  }
3279 
3280  hcb->type = type;
3281  hcb->cb = cb;
3282  hcb->cbarg = arg;
3283 
3284  switch (type) {
3286  hcb->hash = _evhtp_quick_hash(path);
3287  hcb->val.path = strdup(path);
3288  break;
3289 #ifndef EVHTP_DISABLE_REGEX
3291  hcb->val.regex = malloc(sizeof(regex_t));
3292 
3293  if (regcomp(hcb->val.regex, (char *)path, REG_EXTENDED) != 0) {
3294  evhtp_safe_free(hcb->val.regex, free);
3295  evhtp_safe_free(hcb, free);
3296 
3297  return NULL;
3298  }
3299  break;
3300 #endif
3302  hcb->val.glob = strdup(path);
3303  break;
3304  default:
3305  evhtp_safe_free(hcb, free);
3306 
3307  return NULL;
3308  } /* switch */
3309 
3310  return hcb;
3311 }
3312 
3313 void
3315  if (callback == NULL) {
3316  return;
3317  }
3318 
3319  switch (callback->type) {
3321  free(callback->val.path);
3322  break;
3324  evhtp_safe_free(callback->val.glob, free);
3325  break;
3326 #ifndef EVHTP_DISABLE_REGEX
3328  regfree(callback->val.regex);
3329  free(callback->val.regex);
3330  break;
3331 #endif
3332  }
3333 
3334  if (callback->hooks) {
3335  evhtp_safe_free(callback->hooks, free);
3336  }
3337 
3338  evhtp_safe_free(callback, free);
3339 
3340  return;
3341 }
3342 
3343 int
3345  TAILQ_INSERT_TAIL(cbs, cb, next);
3346 
3347  return 0;
3348 }
3349 
3350 int
3351 evhtp_set_hook(evhtp_hooks_t ** hooks, evhtp_hook_type type, evhtp_hook cb, void * arg) {
3352  if (*hooks == NULL) {
3353  if (!(*hooks = calloc(sizeof(evhtp_hooks_t), 1))) {
3354  return -1;
3355  }
3356  }
3357 
3358  switch (type) {
3360  (*hooks)->on_headers_start = (evhtp_hook_headers_start_cb)cb;
3361  (*hooks)->on_headers_start_arg = arg;
3362  break;
3363  case evhtp_hook_on_header:
3364  (*hooks)->on_header = (evhtp_hook_header_cb)cb;
3365  (*hooks)->on_header_arg = arg;
3366  break;
3367  case evhtp_hook_on_headers:
3368  (*hooks)->on_headers = (evhtp_hook_headers_cb)cb;
3369  (*hooks)->on_headers_arg = arg;
3370  break;
3371  case evhtp_hook_on_path:
3372  (*hooks)->on_path = (evhtp_hook_path_cb)cb;
3373  (*hooks)->on_path_arg = arg;
3374  break;
3375  case evhtp_hook_on_read:
3376  (*hooks)->on_read = (evhtp_hook_read_cb)cb;
3377  (*hooks)->on_read_arg = arg;
3378  break;
3380  (*hooks)->on_request_fini = (evhtp_hook_request_fini_cb)cb;
3381  (*hooks)->on_request_fini_arg = arg;
3382  break;
3384  (*hooks)->on_connection_fini = (evhtp_hook_connection_fini_cb)cb;
3385  (*hooks)->on_connection_fini_arg = arg;
3386  break;
3388  (*hooks)->on_connection_error = (evhtp_hook_conn_err_cb)cb;
3389  (*hooks)->on_connection_error_arg = arg;
3390  break;
3391  case evhtp_hook_on_error:
3392  (*hooks)->on_error = (evhtp_hook_err_cb)cb;
3393  (*hooks)->on_error_arg = arg;
3394  break;
3396  (*hooks)->on_new_chunk = (evhtp_hook_chunk_new_cb)cb;
3397  (*hooks)->on_new_chunk_arg = arg;
3398  break;
3400  (*hooks)->on_chunk_fini = (evhtp_hook_chunk_fini_cb)cb;
3401  (*hooks)->on_chunk_fini_arg = arg;
3402  break;
3404  (*hooks)->on_chunks_fini = (evhtp_hook_chunks_fini_cb)cb;
3405  (*hooks)->on_chunks_fini_arg = arg;
3406  break;
3408  (*hooks)->on_hostname = (evhtp_hook_hostname_cb)cb;
3409  (*hooks)->on_hostname_arg = arg;
3410  break;
3411  case evhtp_hook_on_write:
3412  (*hooks)->on_write = (evhtp_hook_write_cb)cb;
3413  (*hooks)->on_write_arg = arg;
3414  break;
3415  case evhtp_hook_on_event:
3416  (*hooks)->on_event = (evhtp_hook_event_cb)cb;
3417  (*hooks)->on_event_arg = arg;
3418  break;
3419  default:
3420 
3421  return -1;
3422  } /* switch */
3423 
3424  return 0;
3425 } /* evhtp_set_hook */
3426 
3427 int
3429  return evhtp_set_hook(hooks, type, NULL, NULL);
3430 }
3431 
3432 int
3434  int res = 0;
3435 
3437  res -= 1;
3438  }
3439 
3440  if (evhtp_unset_hook(hooks, evhtp_hook_on_header)) {
3441  res -= 1;
3442  }
3443 
3445  res -= 1;
3446  }
3447 
3448  if (evhtp_unset_hook(hooks, evhtp_hook_on_path)) {
3449  res -= 1;
3450  }
3451 
3452  if (evhtp_unset_hook(hooks, evhtp_hook_on_read)) {
3453  res -= 1;
3454  }
3455 
3457  res -= 1;
3458  }
3459 
3461  res -= 1;
3462  }
3463 
3465  res -= 1;
3466  }
3467 
3468  if (evhtp_unset_hook(hooks, evhtp_hook_on_error)) {
3469  res -= 1;
3470  }
3471 
3473  res -= 1;
3474  }
3475 
3477  res -= 1;
3478  }
3479 
3481  res -= 1;
3482  }
3483 
3485  res -= 1;
3486  }
3487 
3488  if (evhtp_unset_hook(hooks, evhtp_hook_on_write)) {
3489  return -1;
3490  }
3491 
3492  if (evhtp_unset_hook(hooks, evhtp_hook_on_event)) {
3493  return -1;
3494  }
3495 
3496  return res;
3497 } /* evhtp_unset_all_hooks */
3498 
3500 evhtp_set_cb(evhtp_t * htp, const char * path, evhtp_callback_cb cb, void * arg) {
3501  evhtp_callback_t * hcb;
3502 
3503  _evhtp_lock(htp);
3504 
3505  if (htp->callbacks == NULL) {
3506  if (!(htp->callbacks = calloc(sizeof(evhtp_callbacks_t), 1))) {
3507  _evhtp_unlock(htp);
3508 
3509  return NULL;
3510  }
3511 
3512  TAILQ_INIT(htp->callbacks);
3513  }
3514 
3515  if (!(hcb = evhtp_callback_new(path, evhtp_callback_type_hash, cb, arg))) {
3516  _evhtp_unlock(htp);
3517 
3518  return NULL;
3519  }
3520 
3521  if (evhtp_callbacks_add_callback(htp->callbacks, hcb)) {
3522  evhtp_safe_free(hcb, evhtp_callback_free);
3523  _evhtp_unlock(htp);
3524 
3525  return NULL;
3526  }
3527 
3528  _evhtp_unlock(htp);
3529 
3530  return hcb;
3531 }
3532 
3533 #ifndef EVHTP_DISABLE_EVTHR
3534 static void
3535 _evhtp_thread_init(evthr_t * thr, void * arg) {
3536  evhtp_t * htp = (evhtp_t *)arg;
3537 
3538  if (htp->thread_init_cb) {
3539  htp->thread_init_cb(htp, thr, htp->thread_init_cbarg);
3540  }
3541 }
3542 
3543 int
3544 evhtp_use_threads(evhtp_t * htp, evhtp_thread_init_cb init_cb, int nthreads, void * arg) {
3545  htp->thread_init_cb = init_cb;
3546  htp->thread_init_cbarg = arg;
3547 
3548 #ifndef EVHTP_DISABLE_SSL
3550 #endif
3551 
3552  if (!(htp->thr_pool = evthr_pool_new(nthreads, _evhtp_thread_init, htp))) {
3553  return -1;
3554  }
3555 
3556  evthr_pool_start(htp->thr_pool);
3557 
3558  return 0;
3559 }
3560 
3561 #endif
3562 
3563 #ifndef EVHTP_DISABLE_EVTHR
3564 int
3566  if (htp == NULL) {
3567  return -1;
3568  }
3569 
3570  if (!(htp->lock = malloc(sizeof(pthread_mutex_t)))) {
3571  return -1;
3572  }
3573 
3574  return pthread_mutex_init(htp->lock, NULL);
3575 }
3576 
3577 #endif
3578 
3579 #ifndef EVHTP_DISABLE_REGEX
3581 evhtp_set_regex_cb(evhtp_t * htp, const char * pattern, evhtp_callback_cb cb, void * arg) {
3582  evhtp_callback_t * hcb;
3583 
3584  _evhtp_lock(htp);
3585 
3586  if (htp->callbacks == NULL) {
3587  if (!(htp->callbacks = calloc(sizeof(evhtp_callbacks_t), 1))) {
3588  _evhtp_unlock(htp);
3589 
3590  return NULL;
3591  }
3592 
3593  TAILQ_INIT(htp->callbacks);
3594  }
3595 
3596  if (!(hcb = evhtp_callback_new(pattern, evhtp_callback_type_regex, cb, arg))) {
3597  _evhtp_unlock(htp);
3598 
3599  return NULL;
3600  }
3601 
3602  if (evhtp_callbacks_add_callback(htp->callbacks, hcb)) {
3603  evhtp_safe_free(hcb, evhtp_callback_free);
3604  _evhtp_unlock(htp);
3605 
3606  return NULL;
3607  }
3608 
3609  _evhtp_unlock(htp);
3610 
3611  return hcb;
3612 }
3613 
3614 #endif
3615 
3617 evhtp_set_glob_cb(evhtp_t * htp, const char * pattern, evhtp_callback_cb cb, void * arg) {
3618  evhtp_callback_t * hcb;
3619 
3620  _evhtp_lock(htp);
3621 
3622  if (htp->callbacks == NULL) {
3623  if (!(htp->callbacks = calloc(sizeof(evhtp_callbacks_t), 1))) {
3624  _evhtp_unlock(htp);
3625 
3626  return NULL;
3627  }
3628 
3629  TAILQ_INIT(htp->callbacks);
3630  }
3631 
3632  if (!(hcb = evhtp_callback_new(pattern, evhtp_callback_type_glob, cb, arg))) {
3633  _evhtp_unlock(htp);
3634 
3635  return NULL;
3636  }
3637 
3638  if (evhtp_callbacks_add_callback(htp->callbacks, hcb)) {
3639  evhtp_safe_free(hcb, evhtp_callback_free);
3640  _evhtp_unlock(htp);
3641 
3642  return NULL;
3643  }
3644 
3645  _evhtp_unlock(htp);
3646 
3647  return hcb;
3648 }
3649 
3650 void
3652  htp->defaults.cb = cb;
3653  htp->defaults.cbarg = arg;
3654 }
3655 
3656 void
3658  htp->defaults.pre_accept = cb;
3659  htp->defaults.pre_accept_cbarg = arg;
3660 }
3661 
3662 void
3664  htp->defaults.post_accept = cb;
3665  htp->defaults.post_accept_cbarg = arg;
3666 }
3667 
3668 #ifndef EVHTP_DISABLE_SSL
3669 #ifndef EVHTP_DISABLE_EVTHR
3670 int
3672  int i;
3673 
3674  if (ssl_locks_initialized == 1) {
3675  return 0;
3676  }
3677 
3679 
3680  ssl_num_locks = CRYPTO_num_locks();
3681  ssl_locks = malloc(ssl_num_locks * sizeof(evhtp_mutex_t));
3682 
3683  for (i = 0; i < ssl_num_locks; i++) {
3684  pthread_mutex_init(&(ssl_locks[i]), NULL);
3685  }
3686 
3687  CRYPTO_set_id_callback(_evhtp_ssl_get_thread_id);
3688  CRYPTO_set_locking_callback(_evhtp_ssl_thread_lock);
3689 
3690  return 0;
3691 }
3692 
3693 #endif
3694 
3695 int
3697 #ifdef EVHTP_ENABLE_FUTURE_STUFF
3698  evhtp_ssl_scache_init init_cb = NULL;
3699  evhtp_ssl_scache_add add_cb = NULL;
3700  evhtp_ssl_scache_get get_cb = NULL;
3701  evhtp_ssl_scache_del del_cb = NULL;
3702 #endif
3703  long cache_mode;
3704 
3705  if (cfg == NULL || htp == NULL || cfg->pemfile == NULL) {
3706  return -1;
3707  }
3708 
3709  SSL_library_init();
3710  SSL_load_error_strings();
3711  RAND_poll();
3712 
3713 #if OPENSSL_VERSION_NUMBER < 0x10000000L
3714  STACK_OF(SSL_COMP) * comp_methods = SSL_COMP_get_compression_methods();
3715  sk_SSL_COMP_zero(comp_methods);
3716 #endif
3717 
3718  htp->ssl_cfg = cfg;
3719  htp->ssl_ctx = SSL_CTX_new(SSLv23_server_method());
3720 
3721 #if OPENSSL_VERSION_NUMBER >= 0x10000000L
3722  SSL_CTX_set_options(htp->ssl_ctx, SSL_MODE_RELEASE_BUFFERS | SSL_OP_NO_COMPRESSION);
3723  SSL_CTX_set_timeout(htp->ssl_ctx, cfg->ssl_ctx_timeout);
3724 #endif
3725 
3726  SSL_CTX_set_options(htp->ssl_ctx, cfg->ssl_opts);
3727 
3728 #ifndef OPENSSL_NO_ECDH
3729  if (cfg->named_curve != NULL) {
3730  EC_KEY * ecdh = NULL;
3731  int nid = 0;
3732 
3733  nid = OBJ_sn2nid(cfg->named_curve);
3734  if (nid == 0) {
3735  fprintf(stderr, "ECDH initialization failed: unknown curve %s\n", cfg->named_curve);
3736  }
3737  ecdh = EC_KEY_new_by_curve_name(nid);
3738  if (ecdh == NULL) {
3739  fprintf(stderr, "ECDH initialization failed for curve %s\n", cfg->named_curve);
3740  }
3741  SSL_CTX_set_tmp_ecdh(htp->ssl_ctx, ecdh);
3742  EC_KEY_free(ecdh);
3743  }
3744 #endif /* OPENSSL_NO_ECDH */
3745 #ifndef OPENSSL_NO_DH
3746  if (cfg->dhparams != NULL) {
3747  FILE * fh;
3748  DH * dh;
3749 
3750  fh = fopen(cfg->dhparams, "r");
3751  if (fh != NULL) {
3752  dh = PEM_read_DHparams(fh, NULL, NULL, NULL);
3753  if (dh != NULL) {
3754  SSL_CTX_set_tmp_dh(htp->ssl_ctx, dh);
3755  DH_free(dh);
3756  } else {
3757  fprintf(stderr, "DH initialization failed: unable to parse file %s\n", cfg->dhparams);
3758  }
3759  fclose(fh);
3760  } else {
3761  fprintf(stderr, "DH initialization failed: unable to open file %s\n", cfg->dhparams);
3762  }
3763  }
3764 #endif /* OPENSSL_NO_DH */
3765 
3766  if (cfg->ciphers != NULL) {
3767  SSL_CTX_set_cipher_list(htp->ssl_ctx, cfg->ciphers);
3768  }
3769 
3770  SSL_CTX_load_verify_locations(htp->ssl_ctx, cfg->cafile, cfg->capath);
3771  X509_STORE_set_flags(SSL_CTX_get_cert_store(htp->ssl_ctx), cfg->store_flags);
3772  SSL_CTX_set_verify(htp->ssl_ctx, cfg->verify_peer, cfg->x509_verify_cb);
3773 
3774  if (cfg->x509_chk_issued_cb != NULL) {
3775  htp->ssl_ctx->cert_store->check_issued = cfg->x509_chk_issued_cb;
3776  }
3777 
3778  if (cfg->verify_depth) {
3779  SSL_CTX_set_verify_depth(htp->ssl_ctx, cfg->verify_depth);
3780  }
3781 
3782  switch (cfg->scache_type) {
3784  cache_mode = SSL_SESS_CACHE_OFF;
3785  break;
3786 #ifdef EVHTP_ENABLE_FUTURE_STUFF
3788  cache_mode = SSL_SESS_CACHE_SERVER |
3789  SSL_SESS_CACHE_NO_INTERNAL |
3790  SSL_SESS_CACHE_NO_INTERNAL_LOOKUP;
3791 
3792  init_cb = cfg->scache_init;
3793  add_cb = cfg->scache_add;
3794  get_cb = cfg->scache_get;
3795  del_cb = cfg->scache_del;
3796  break;
3798  cache_mode = SSL_SESS_CACHE_SERVER |
3799  SSL_SESS_CACHE_NO_INTERNAL |
3800  SSL_SESS_CACHE_NO_INTERNAL_LOOKUP;
3801 
3802  init_cb = _evhtp_ssl_builtin_init;
3803  add_cb = _evhtp_ssl_builtin_add;
3804  get_cb = _evhtp_ssl_builtin_get;
3805  del_cb = _evhtp_ssl_builtin_del;
3806  break;
3807 #endif
3809  default:
3810  cache_mode = SSL_SESS_CACHE_SERVER;
3811  break;
3812  } /* switch */
3813 
3814  SSL_CTX_use_certificate_file(htp->ssl_ctx, cfg->pemfile, SSL_FILETYPE_PEM);
3815  SSL_CTX_use_PrivateKey_file(htp->ssl_ctx,
3816  cfg->privfile ? cfg->privfile : cfg->pemfile, SSL_FILETYPE_PEM);
3817 
3818  SSL_CTX_set_session_id_context(htp->ssl_ctx,
3819  (void *)&session_id_context,
3820  sizeof(session_id_context));
3821 
3822  SSL_CTX_set_app_data(htp->ssl_ctx, htp);
3823  SSL_CTX_set_session_cache_mode(htp->ssl_ctx, cache_mode);
3824 
3825  if (cache_mode != SSL_SESS_CACHE_OFF) {
3826  SSL_CTX_sess_set_cache_size(htp->ssl_ctx,
3827  cfg->scache_size ? cfg->scache_size : 1024);
3828 
3831  SSL_CTX_sess_set_new_cb(htp->ssl_ctx, _evhtp_ssl_add_scache_ent);
3832  SSL_CTX_sess_set_get_cb(htp->ssl_ctx, _evhtp_ssl_get_scache_ent);
3833  SSL_CTX_sess_set_remove_cb(htp->ssl_ctx, _evhtp_ssl_delete_scache_ent);
3834 
3835  if (cfg->scache_init) {
3836  cfg->args = (cfg->scache_init)(htp);
3837  }
3838  }
3839  }
3840 
3841  return 0;
3842 } /* evhtp_use_ssl */
3843 
3844 #endif
3845 
3846 evbev_t *
3848  return connection->bev;
3849 }
3850 
3851 evbev_t *
3853  evbev_t * bev = evhtp_connection_get_bev(connection);
3854 
3855  if (connection->hooks) {
3856  evhtp_unset_all_hooks(&connection->hooks);
3857  }
3858 
3859  if (connection->request && connection->request->hooks) {
3860  evhtp_unset_all_hooks(&connection->request->hooks);
3861  }
3862 
3863  evhtp_connection_set_bev(connection, NULL);
3864 
3865  connection->owner = 0;
3866 
3867  bufferevent_disable(bev, EV_READ);
3868  bufferevent_setcb(bev, NULL, NULL, NULL, NULL);
3869 
3870  return bev;
3871 }
3872 
3873 evbev_t *
3875  return evhtp_connection_get_bev(request->conn);
3876 }
3877 
3878 evbev_t *
3881 }
3882 
3883 void
3885  conn->bev = bev;
3886 }
3887 
3888 void
3890  evhtp_connection_set_bev(request->conn, bev);
3891 }
3892 
3895  return request->conn;
3896 }
3897 
3898 inline void
3900  const struct timeval * rtimeo,
3901  const struct timeval * wtimeo) {
3902  if (!c) {
3903  return;
3904  }
3905 
3906  if (rtimeo || wtimeo) {
3907  bufferevent_set_timeouts(c->bev, rtimeo, wtimeo);
3908  }
3909 }
3910 
3911 void
3913  if (len == 0) {
3914  c->max_body_size = c->htp->max_body_size;
3915  } else {
3916  c->max_body_size = len;
3917  }
3918 }
3919 
3920 void
3923 }
3924 
3925 void
3927  if (connection == NULL) {
3928  return;
3929  }
3930 
3931  _evhtp_connection_fini_hook(connection);
3932  evhtp_safe_free(connection->request, _evhtp_request_free);
3933 
3934  evhtp_safe_free(connection->parser, free);
3935  evhtp_safe_free(connection->hooks, free);
3936  evhtp_safe_free(connection->saddr, free);
3937 
3938  if (connection->resume_ev) {
3939  evhtp_safe_free(connection->resume_ev, event_free);
3940  }
3941 
3942  if (connection->bev) {
3943 #ifdef LIBEVENT_HAS_SHUTDOWN
3944  bufferevent_shutdown(connection->bev, _evhtp_shutdown_eventcb);
3945 #else
3946 #ifndef EVHTP_DISABLE_SSL
3947  if (connection->ssl != NULL) {
3948  SSL_set_shutdown(connection->ssl, SSL_RECEIVED_SHUTDOWN);
3949  SSL_shutdown(connection->ssl);
3950  }
3951 #endif
3952  bufferevent_free(connection->bev);
3953 #endif
3954  }
3955 
3956  if (connection->ratelimit_cfg != NULL) {
3957  ev_token_bucket_cfg_free(connection->ratelimit_cfg);
3958  }
3959 
3960  evhtp_safe_free(connection, free);
3961 } /* evhtp_connection_free */
3962 
3963 void
3965  _evhtp_request_free(request);
3966 }
3967 
3968 void
3969 evhtp_set_timeouts(evhtp_t * htp, const struct timeval * r_timeo, const struct timeval * w_timeo) {
3970  if (r_timeo != NULL) {
3971  htp->recv_timeo = *r_timeo;
3972  }
3973 
3974  if (w_timeo != NULL) {
3975  htp->send_timeo = *w_timeo;
3976  }
3977 }
3978 
3979 void
3981  htp->max_keepalive_requests = num;
3982 }
3983 
3990 void
3991 evhtp_set_bev_flags(evhtp_t * htp, int flags) {
3992  htp->bev_flags = flags;
3993 }
3994 
3995 void
3996 evhtp_set_max_body_size(evhtp_t * htp, uint64_t len) {
3997  htp->max_body_size = len;
3998 }
3999 
4000 void
4002  htp->disable_100_cont = 1;
4003 }
4004 
4005 void
4006 evhtp_set_parser_flags(evhtp_t * htp, int flags) {
4007  htp->parser_flags = flags;
4008 }
4009 
4010 int
4011 evhtp_add_alias(evhtp_t * evhtp, const char * name) {
4012  evhtp_alias_t * alias;
4013 
4014  if (evhtp == NULL || name == NULL) {
4015  return -1;
4016  }
4017 
4018  if (!(alias = calloc(sizeof(evhtp_alias_t), 1))) {
4019  return -1;
4020  }
4021 
4022  alias->alias = strdup(name);
4023 
4024  TAILQ_INSERT_TAIL(&evhtp->aliases, alias, next);
4025 
4026  return 0;
4027 }
4028 
4045 int
4046 evhtp_add_vhost(evhtp_t * evhtp, const char * name, evhtp_t * vhost) {
4047  if (evhtp == NULL || name == NULL || vhost == NULL) {
4048  return -1;
4049  }
4050 
4051  if (TAILQ_FIRST(&vhost->vhosts) != NULL) {
4052  /* vhosts cannot have secondary vhosts defined */
4053  return -1;
4054  }
4055 
4056  if (!(vhost->server_name = strdup(name))) {
4057  return -1;
4058  }
4059 
4060  /* set the parent of this vhost so when the request has been completely
4061  * serviced, the vhost can be reset to the original evhtp structure.
4062  *
4063  * This allows for a keep-alive connection to make multiple requests with
4064  * different Host: values.
4065  */
4066  vhost->parent = evhtp;
4067 
4068  /* inherit various flags from the parent evhtp structure */
4069  vhost->bev_flags = evhtp->bev_flags;
4070  vhost->max_body_size = evhtp->max_body_size;
4072  vhost->recv_timeo = evhtp->recv_timeo;
4073  vhost->send_timeo = evhtp->send_timeo;
4074 
4075  TAILQ_INSERT_TAIL(&evhtp->vhosts, vhost, next_vhost);
4076 
4077  return 0;
4078 }
4079 
4080 evhtp_t *
4081 evhtp_new(evbase_t * evbase, void * arg) {
4082  evhtp_t * htp;
4083 
4084  if (evbase == NULL) {
4085  return NULL;
4086  }
4087 
4088  if (!(htp = calloc(sizeof(evhtp_t), 1))) {
4089  return NULL;
4090  }
4091 
4092  htp->arg = arg;
4093  htp->evbase = evbase;
4094  htp->bev_flags = BEV_OPT_CLOSE_ON_FREE;
4095 
4096  TAILQ_INIT(&htp->vhosts);
4097  TAILQ_INIT(&htp->aliases);
4098 
4099  evhtp_set_gencb(htp, _evhtp_default_request_cb, (void *)htp);
4100 
4101  return htp;
4102 }
4103 
4104 void
4106  evhtp_alias_t * evhtp_alias, * tmp;
4107 
4108  if (evhtp == NULL) {
4109  return;
4110  }
4111 
4112 #ifndef EVHTP_DISABLE_EVTHR
4113  if (evhtp->thr_pool) {
4114  evthr_pool_stop(evhtp->thr_pool);
4115  evthr_pool_free(evhtp->thr_pool);
4116  }
4117 #endif
4118 
4119 #ifndef EVHTP_DISABLE_SSL
4120  if (evhtp->ssl_ctx) {
4121  SSL_CTX_free(evhtp->ssl_ctx);
4122  }
4123 #endif
4124 
4125  if (evhtp->server_name) {
4126  free(evhtp->server_name);
4127  }
4128 
4129  if (evhtp->callbacks) {
4131  }
4132 
4133  TAILQ_FOREACH_SAFE(evhtp_alias, &evhtp->aliases, next, tmp) {
4134  if (evhtp_alias->alias != NULL) {
4135  free(evhtp_alias->alias);
4136  }
4137  TAILQ_REMOVE(&evhtp->aliases, evhtp_alias, next);
4138  free(evhtp_alias);
4139  }
4140 
4141 #ifndef EVHTP_DISABLE_SSL
4142  if (evhtp->ssl_ctx) {
4143  SSL_CTX_free(evhtp->ssl_ctx);
4144  }
4145 #endif
4146 
4147  free(evhtp);
4148 } /* evhtp_free */
4149 
4150 int
4152  size_t read_rate, size_t read_burst,
4153  size_t write_rate, size_t write_burst,
4154  const struct timeval * tick) {
4155  struct ev_token_bucket_cfg * tcfg;
4156 
4157  if (conn == NULL || conn->bev == NULL) {
4158  return -1;
4159  }
4160 
4161  tcfg = ev_token_bucket_cfg_new(read_rate, read_burst,
4162  write_rate, write_burst, tick);
4163 
4164  if (tcfg == NULL) {
4165  return -1;
4166  }
4167 
4168  conn->ratelimit_cfg = tcfg;
4169 
4170  return bufferevent_set_rate_limit(conn->bev, tcfg);
4171 }
4172 
4173 /*****************************************************************
4174 * client request functions *
4175 *****************************************************************/
4176 
4178 evhtp_connection_new(evbase_t * evbase, const char * addr, uint16_t port) {
4179  return evhtp_connection_new_dns(evbase, NULL, addr, port);
4180 }
4181 
4183 evhtp_connection_new_dns(evbase_t * evbase, struct evdns_base * dns_base,
4184  const char * addr, uint16_t port) {
4185  evhtp_connection_t * conn;
4186  int err;
4187 
4188  if (evbase == NULL) {
4189  return NULL;
4190  }
4191 
4192  if (!(conn = _evhtp_connection_new(NULL, -1, evhtp_type_client))) {
4193  return NULL;
4194  }
4195 
4196  conn->evbase = evbase;
4197  conn->bev = bufferevent_socket_new(evbase, -1, BEV_OPT_CLOSE_ON_FREE);
4198 
4199  if (conn->bev == NULL) {
4200  evhtp_connection_free(conn);
4201 
4202  return NULL;
4203  }
4204 
4205  bufferevent_enable(conn->bev, EV_READ);
4206  bufferevent_setcb(conn->bev, NULL, NULL,
4208 
4209  if (dns_base != NULL) {
4210  err = bufferevent_socket_connect_hostname(conn->bev, dns_base,
4211  AF_UNSPEC, addr, port);
4212  } else {
4213  struct sockaddr_in sin4;
4214  struct sockaddr_in6 sin6;
4215  struct sockaddr * sin;
4216  int salen;
4217 
4218  if (inet_pton(AF_INET, addr, &sin4.sin_addr)) {
4219  sin4.sin_family = AF_INET;
4220  sin4.sin_port = htons(port);
4221  sin = (struct sockaddr *)&sin4;
4222  salen = sizeof(sin4);
4223  } else if (inet_pton(AF_INET6, addr, &sin6.sin6_addr)) {
4224  sin6.sin6_family = AF_INET6;
4225  sin6.sin6_port = htons(port);
4226  sin = (struct sockaddr *)&sin6;
4227  salen = sizeof(sin6);
4228  } else {
4229  /* Not a valid IP. */
4230  evhtp_connection_free(conn);
4231 
4232  return NULL;
4233  }
4234 
4235  err = bufferevent_socket_connect(conn->bev, sin, salen);
4236  }
4237 
4238  /* not needed since any of the bufferevent errors will go straight to
4239  * the eventcb
4240  */
4241  if (err) {
4242  return NULL;
4243  }
4244 
4245  return conn;
4246 } /* evhtp_connection_new_dns */
4247 
4248 #ifndef EVHTP_DISABLE_SSL
4250 evhtp_connection_ssl_new(evbase_t * evbase, const char * addr, uint16_t port, evhtp_ssl_ctx_t * ctx) {
4251  evhtp_connection_t * conn;
4252  struct sockaddr_in sin;
4253 
4254  if (evbase == NULL) {
4255  return NULL;
4256  }
4257 
4258  if (!(conn = _evhtp_connection_new(NULL, -1, evhtp_type_client))) {
4259  return NULL;
4260  }
4261 
4262  sin.sin_family = AF_INET;
4263  sin.sin_addr.s_addr = inet_addr(addr);
4264  sin.sin_port = htons(port);
4265 
4266  conn->ssl = SSL_new(ctx);
4267  conn->evbase = evbase;
4268  conn->bev = bufferevent_openssl_socket_new(evbase, -1, conn->ssl, BUFFEREVENT_SSL_CONNECTING, BEV_OPT_CLOSE_ON_FREE);
4269 
4270  bufferevent_enable(conn->bev, EV_READ);
4271 
4272  bufferevent_setcb(conn->bev, NULL, NULL,
4274 
4275  bufferevent_socket_connect(conn->bev,
4276  (struct sockaddr *)&sin, sizeof(sin));
4277 
4278 
4279  return conn;
4280 }
4281 
4282 #endif
4283 
4284 
4287  evhtp_request_t * r;
4288 
4289  if (!(r = _evhtp_request_new(NULL))) {
4290  return NULL;
4291  }
4292 
4293  r->cb = cb;
4294  r->cbarg = arg;
4295  r->proto = EVHTP_PROTO_11;
4296 
4297  return r;
4298 }
4299 
4300 int
4302  htp_method meth, const char * uri) {
4303  evbuf_t * obuf;
4304  char * proto;
4305 
4306  obuf = bufferevent_get_output(c->bev);
4307  r->conn = c;
4308  c->request = r;
4309 
4310  switch (r->proto) {
4311  case EVHTP_PROTO_10:
4312  proto = "1.0";
4313  break;
4314  case EVHTP_PROTO_11:
4315  default:
4316  proto = "1.1";
4317  break;
4318  }
4319 
4320  evbuffer_add_printf(obuf, "%s %s HTTP/%s\r\n",
4321  htparser_get_methodstr_m(meth), uri, proto);
4322 
4324  evbuffer_add_reference(obuf, "\r\n", 2, NULL, NULL);
4325 
4326  return 0;
4327 }
4328 
4329 unsigned int
4331  return htparser_get_status(r->conn->parser);
4332 }
4333 
char * key
Definition: evhtp.h:350
evhtp_callbacks_t * callbacks
Definition: evhtp.h:301
#define EVHTP_RES_SWITCHPROXY
Definition: evhtp.h:224
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:3344
evhtp_query_t * evhtp_parse_query_wflags(const char *query, size_t len, int flags)
Parses the query portion of the uri into a set of key/values.
Definition: evhtp.c:2735
#define EVHTP_RES_300
Definition: evhtp.h:217
uint16_t evhtp_res
Definition: evhtp.h:84
#define EVHTP_PARSE_QUERY_FLAG_ALLOW_EMPTY_VALS
Definition: evhtp.h:997
#define EVHTP_RES_SERVUNAVAIL
Definition: evhtp.h:252
int evhtp_bind_socket(evhtp_t *htp, const char *baddr, uint16_t port, int backlog)
bind to a socket, optionally with specific protocol support formatting. The addr can be defined as on...
Definition: evhtp.c:3196
EVHTP_EXPORT void evhtp_headers_add_header(evhtp_headers_t *headers, evhtp_header_t *header)
adds an evhtp_header_t to the end of the evhtp_headers_t tailq
static evhtp_res _evhtp_header_hook(evhtp_request_t *request, evhtp_header_t *header)
runs the user-defined on_header hook for a request
Definition: evhtp.c:398
#define EVHTP_PARSE_QUERY_FLAG_IGNORE_FRAGMENTS
Definition: evhtp.h:1000
evhtp_res(* evhtp_hook_request_fini_cb)(evhtp_request_t *req, void *arg)
Definition: evhtp.h:165
evhtp_ssl_scache_init scache_init
Definition: evhtp.h:525
#define _evhtp_lock(h)
Definition: evhtp.c:106
static htparse_hooks request_psets
callback definitions for request processing from libhtparse
Definition: evhtp.c:234
int evhtp_use_threads(evhtp_t *htp, evhtp_thread_init_cb init_cb, int nthreads, void *arg)
Enable thread-pool support for an evhtp_t context. Connectios are distributed across 'nthreads'...
Definition: evhtp.c:3544
evhtp_proto proto
Definition: evhtp.h:420
static unsigned int _evhtp_quick_hash(const char *str)
a weak hash function
Definition: evhtp.c:315
long store_flags
Definition: evhtp.h:521
#define evhtp_query_free
Definition: evhtp.h:1113
#define EVHTP_RES_METHNALLOWED
Definition: evhtp.h:233
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:3980
evhtp_ssl_scache_del scache_del
Definition: evhtp.h:528
void * on_connection_fini_arg
Definition: evhtp.h:495
int evhtp_add_vhost(evhtp_t *evhtp, const char *name, evhtp_t *vhost)
add a virtual host.
Definition: evhtp.c:4046
#define EVHTP_RES_ENTOOLARGE
Definition: evhtp.h:241
evhtp_ssl_chk_issued_cb x509_chk_issued_cb
Definition: evhtp.h:520
evbase_t * evbase
Definition: evhtp.h:439
evhtp_header_t * evhtp_header_val_add(evhtp_headers_t *headers, const char *val, char valloc)
finds the last header in the headers tailq and adds the value
Definition: evhtp.c:2399
#define EVHTP_RES_SWITCH_PROTO
Definition: evhtp.h:203
struct evbuffer evbuf_t
Definition: evhtp.h:55
void evhtp_send_reply_chunk_end(evhtp_request_t *request)
call when all chunks have been sent and you wish to send the last bits. This will add the last 0CRLFC...
Definition: evhtp.c:3138
void evhtp_disable_100_continue(evhtp_t *htp)
when a client sends an Expect: 100-continue, if this is function is called, evhtp will not send a HTT...
Definition: evhtp.c:4001
uint8_t chunked
Definition: evhtp.h:423
evbev_t * evhtp_connection_take_ownership(evhtp_connection_t *connection)
let a user take ownership of the underlying bufferevent and free all other underlying resources...
Definition: evhtp.c:3852
uint8_t error
Definition: evhtp.h:423
uint8_t paused
Definition: evhtp.h:457
void *(* evhtp_ssl_scache_init)(evhtp_t *)
Definition: evhtp.h:184
static evhtp_res _evhtp_connection_write_hook(evhtp_connection_t *connection)
Definition: evhtp.c:536
evhtp_res(* evhtp_post_accept_cb)(evhtp_connection_t *conn, void *arg)
Definition: evhtp.h:160
#define EVHTP_RES_IAMATEAPOT
Definition: evhtp.h:246
#define EVHTP_RES_BADGATEWAY
Definition: evhtp.h:251
#define EVHTP_RES_TMPREDIR
Definition: evhtp.h:225
uint8_t finished
Definition: evhtp.h:423
static int _evhtp_request_parser_hostname(htparser *p, const char *data, size_t len)
Definition: evhtp.c:1297
#define EVHTP_RES_PRECONDFAIL
Definition: evhtp.h:240
static int _evhtp_request_parser_host(htparser *p, const char *data, size_t len)
Definition: evhtp.c:1362
uint8_t keepalive
Definition: evhtp.h:423
static evhtp_connection_t * _evhtp_connection_new(evhtp_t *htp, evutil_socket_t sock, evhtp_type type)
Definition: evhtp.c:2063
char * alias
Definition: evhtp.h:267
int evhtp_unset_hook(evhtp_hooks_t **hooks, evhtp_hook_type type)
remove a specific hook from being called.
Definition: evhtp.c:3428
void evhtp_send_reply_chunk(evhtp_request_t *request, evbuf_t *buf)
send a chunk reply.
Definition: evhtp.c:3114
unsigned char * query_raw
Definition: evhtp.h:373
evhtp_ssl_t * ssl
Definition: evhtp.h:443
char * privfile
Definition: evhtp.h:509
evhtp_thread_init_cb thread_init_cb
Definition: evhtp.h:298
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:3565
evhtp_ssl_verify_cb x509_verify_cb
Definition: evhtp.h:519
#define EVHTP_RES_SERVERR
Definition: evhtp.h:249
evhtp_connection_t * evhtp_connection_ssl_new(evbase_t *evbase, const char *addr, uint16_t port, evhtp_ssl_ctx_t *ctx)
Definition: evhtp.c:4250
char * glob
Definition: evhtp.h:335
evbase_t * evbase
Definition: evhtp.h:277
#define evhtp_query_new
Definition: evhtp.h:1112
void * cbarg
Definition: evhtp.h:261
void evhtp_send_reply_end(evhtp_request_t *request)
Definition: evhtp.c:3014
evhtp_hook_write_cb on_write
Definition: evhtp.h:486
char * path
Definition: evhtp.h:334
evhtp_ssl_cfg_t * ssl_cfg
Definition: evhtp.h:289
#define EVHTP_PARSE_QUERY_FLAG_ALLOW_NULL_VALS
Definition: evhtp.h:998
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:3581
unsigned char * fragment
Definition: evhtp.h:372
evhtp_res(* evhtp_hook_header_cb)(evhtp_request_t *req, evhtp_header_t *hdr, void *arg)
Definition: evhtp.h:161
htp_method evhtp_request_get_method(evhtp_request_t *r)
returns the htp_method enum version of the request method.
Definition: evhtp.c:2328
int parser_flags
Definition: evhtp.h:285
static int _evhtp_request_parser_chunk_new(htparser *p)
Definition: evhtp.c:1501
static int evhtp_is_hex_query_char(unsigned char ch)
Definition: evhtp.c:2627
evhtp_defaults_t defaults
Definition: evhtp.h:302
evbuf_t * buffer_out
Definition: evhtp.h:417
#define _evhtp_is_http_10(_major, _minor)
helper function to determine if http version is HTTP/1.1
Definition: evhtp.c:346
regex_t * regex
Definition: evhtp.h:337
void * thread_init_cbarg
Definition: evhtp.h:299
#define EVHTP_PARSE_QUERY_FLAG_STRICT
Definition: evhtp.h:995
char k_heaped
Definition: evhtp.h:356
uint8_t error
Definition: evhtp.h:457
uint64_t max_body_size
Definition: evhtp.h:282
static int _evhtp_request_parser_path(htparser *p, const char *data, size_t len)
Definition: evhtp.c:1408
static int _evhtp_request_parser_port(htparser *p, const char *data, size_t len)
Definition: evhtp.c:1383
main structure containing all configuration information
Definition: evhtp.h:275
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:3019
void evhtp_set_timeouts(evhtp_t *htp, const struct timeval *r_timeo, const struct timeval *w_timeo)
set a read/write timeout on all things evhtp_t. When the timeout expires your error hook will be call...
Definition: evhtp.c:3969
SSL evhtp_ssl_t
Definition: evhtp.h:43
#define EVHTP_PARSE_QUERY_FLAG_TREAT_SEMICOLON_AS_SEP
Definition: evhtp.h:999
evhtp_callback_cb cb
Definition: evhtp.h:429
evhtp_res(* evhtp_hook_chunk_fini_cb)(evhtp_request_t *r, void *arg)
Definition: evhtp.h:168
char * hostname
Definition: evhtp.h:385
#define HOOK_REQUEST_RUN(request, hook_name,...)
Definition: evhtp.c:66
static int _evhtp_request_set_callbacks(evhtp_request_t *request)
Definition: evhtp.c:1204
evhtp_res(* evhtp_hook_headers_cb)(evhtp_request_t *req, evhtp_headers_t *hdr, void *arg)
Definition: evhtp.h:162
void evhtp_request_pause(evhtp_request_t *request)
Wrapper around evhtp_connection_pause.
Definition: evhtp.c:2368
uint64_t num_requests
Definition: evhtp.h:455
int evhtp_ssl_init(evhtp_t *htp, evhtp_ssl_cfg_t *cfg)
Definition: evhtp.c:3696
void * args
Definition: evhtp.h:529
#define evhtp_headers_t
Definition: evhtp.h:93
evhtp_request_t * request
Definition: evhtp.h:452
void * on_error_arg
Definition: evhtp.h:497
evhtp_connection_t * evhtp_request_get_connection(evhtp_request_t *request)
returns the underlying evhtp_connection_t structure from a request
Definition: evhtp.c:3894
static int _evhtp_run_pre_accept(evhtp_t *htp, evhtp_connection_t *conn)
Definition: evhtp.c:1975
#define EVHTP_RES_UNSUPPORTED
Definition: evhtp.h:243
void evhtp_connection_set_bev(evhtp_connection_t *conn, evbev_t *bev)
Sets the connections underlying bufferevent.
Definition: evhtp.c:3884
struct evhtp_callbacks_s evhtp_callbacks_t
Definition: evhtp.h:71
static evhtp_uri_t * _evhtp_uri_new(void)
create an overlay URI structure
Definition: evhtp.c:827
#define EVHTP_RES_GWTIMEOUT
Definition: evhtp.h:253
#define EVHTP_RES_SEEOTHER
Definition: evhtp.h:221
void(* evhtp_callback_cb)(evhtp_request_t *req, void *arg)
Definition: evhtp.h:151
static evhtp_t * _evhtp_request_find_vhost(evhtp_t *evhtp, const char *name)
Definition: evhtp.c:1176
static evhtp_res _evhtp_hostname_hook(evhtp_request_t *r, const char *hostname)
Definition: evhtp.c:529
static int _evhtp_ssl_add_scache_ent(evhtp_ssl_t *ssl, evhtp_ssl_sess_t *sess)
Definition: evhtp.c:2243
uint64_t body_bytes_read
Definition: evhtp.h:454
char * path
Definition: evhtp.h:395
int evhtp_connection_set_rate_limit(evhtp_connection_t *conn, size_t read_rate, size_t read_burst, size_t write_rate, size_t write_burst, const struct timeval *tick)
Definition: evhtp.c:4151
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:2540
SSL_SESSION evhtp_ssl_sess_t
Definition: evhtp.h:42
evhtp_headers_t * headers_in
Definition: evhtp.h:418
void * on_event_arg
Definition: evhtp.h:503
#define EVHTP_RES_EXPECTFAIL
Definition: evhtp.h:245
evhtp_callback_cb cb
Definition: evhtp.h:328
void evhtp_request_free(evhtp_request_t *request)
Definition: evhtp.c:3964
#define EVHTP_RES_ERROR
Definition: evhtp.h:194
evhtp_ssl_scache_type scache_type
Definition: evhtp.h:522
#define EVHTP_RES_CREATED
Definition: evhtp.h:208
SSL_CTX evhtp_ssl_ctx_t
Definition: evhtp.h:44
void evhtp_kv_free(evhtp_kv_t *kv)
frees resources allocated for a single key/value
Definition: evhtp.c:2492
struct ev_token_bucket_cfg * ratelimit_cfg
Definition: evhtp.h:465
#define EVHTP_RES_FATAL
Definition: evhtp.h:196
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:4006
char * password
Definition: evhtp.h:384
#define EVHTP_RES_MOVEDPERM
Definition: evhtp.h:219
#define HOOK_CONN_RUN(conn, hook_name,...)
Definition: evhtp.c:90
unsigned int evhtp_request_status(evhtp_request_t *r)
Definition: evhtp.c:4330
#define EVHTP_RES_MSTATUS
Definition: evhtp.h:214
evutil_socket_t sock
Definition: evhtp.h:451
evhtp_connection_t * evhtp_connection_new(evbase_t *evbase, const char *addr, uint16_t port)
allocate a new connection
Definition: evhtp.c:4178
#define _evhtp_is_http_11(_major, _minor)
helper macro to determine if http version is HTTP/1.0
Definition: evhtp.c:335
struct evhtp_kvs_s evhtp_kvs_t
Definition: evhtp.h:75
static void _evhtp_error_hook(evhtp_request_t *request, evhtp_error_flags errtype)
runs the user-defined hook when a connection error occurs
Definition: evhtp.c:505
static evhtp_res _evhtp_chunk_fini_hook(evhtp_request_t *request)
Definition: evhtp.c:460
long scache_timeout
Definition: evhtp.h:523
static int _evhtp_request_parser_chunk_fini(htparser *p)
Definition: evhtp.c:1513
#define EVHTP_RES_NOTMOD
Definition: evhtp.h:222
uint8_t evhtp_error_flags
Definition: evhtp.h:85
#define EVHTP_RES_NAUTHINFO
Definition: evhtp.h:210
EVHTP_EXPORT const char * evhtp_header_find(evhtp_headers_t *headers, const char *key)
finds the value of a key in a evhtp_headers_t structure
void evhtp_unbind_socket(evhtp_t *htp)
stops the listening socket.
Definition: evhtp.c:3148
static evhtp_mutex_t * ssl_locks
Definition: evhtp.c:259
evhtp_t * parent
Definition: evhtp.h:276
evhtp_headers_t * headers_out
Definition: evhtp.h:419
#define EVHTP_RES_DATA_TOO_LONG
Definition: evhtp.h:198
void * pre_accept_cbarg
Definition: evhtp.h:262
#define evhtp_headers_s
Definition: evhtp.h:89
uint16_t port
Definition: evhtp.h:386
static int _evhtp_create_headers(evhtp_header_t *header, void *arg)
Definition: evhtp.c:1626
long ssl_ctx_timeout
Definition: evhtp.h:516
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:3154
a generic key/value structure
Definition: evhtp.h:349
a structure containing all information for a http request.
Definition: evhtp.h:411
#define EVHTP_RES_LENREQ
Definition: evhtp.h:239
evhtp_callback_cb cb
Definition: evhtp.h:258
htp_scheme scheme
Definition: evhtp.h:375
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:2660
struct timeval send_timeo
Definition: evhtp.h:305
void evhtp_callback_free(evhtp_callback_t *callback)
frees information associated with a ainflwx callback.
Definition: evhtp.c:3314
int verify_depth
Definition: evhtp.h:518
static int session_id_context
Definition: evhtp.c:256
uint64_t max_body_size
Definition: evhtp.h:453
struct sockaddr * saddr
Definition: evhtp.h:448
evhtp_request_t * evhtp_request_new(evhtp_callback_cb cb, void *arg)
allocate a new request
Definition: evhtp.c:4286
#define evhtp_headers_find_header
Definition: evhtp.h:1103
void evhtp_request_resume(evhtp_request_t *request)
Wrapper around evhtp_connection_resume.
Definition: evhtp.c:2381
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:3651
void evhtp_callbacks_free(evhtp_callbacks_t *callbacks)
Definition: evhtp.c:3255
#define EVHTP_RES_NOCONTENT
Definition: evhtp.h:211
unscape_state
Definition: evhtp.c:2653
evhtp_hook_type
types associated with where a developer can hook into during the request processing cycle...
Definition: evhtp.h:107
htparser * parser
Definition: evhtp.h:446
static int _evhtp_glob_match(const char *pattern, size_t pat_len, const char *string, size_t str_len)
glob/wildcard type pattern matching.
Definition: evhtp.c:612
union evhtp_callback_s::@0 val
evhtp_res(* evhtp_hook_headers_start_cb)(evhtp_request_t *r, void *arg)
Definition: evhtp.h:170
evhtp_pre_accept_cb pre_accept
Definition: evhtp.h:259
#define EVHTP_RES_PROXYAUTHREQ
Definition: evhtp.h:235
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:3996
static evhtp_ssl_sess_t * _evhtp_ssl_get_scache_ent(evhtp_ssl_t *ssl, unsigned char *sid, int sid_len, int *copy)
Definition: evhtp.c:2265
evhtp_res(* evhtp_hook_read_cb)(evhtp_request_t *req, evbuf_t *buf, void *arg)
Definition: evhtp.h:164
static evhtp_authority_t * _evhtp_authority_new(void)
create an authority structure
Definition: evhtp.c:869
void evhtp_set_pre_accept_cb(evhtp_t *htp, evhtp_pre_accept_cb cb, void *arg)
Definition: evhtp.c:3657
structure containing a single callback and configuration
Definition: evhtp.h:326
evhtp_res(* evhtp_hook_conn_err_cb)(evhtp_connection_t *connection, evhtp_error_flags errtype, void *arg)
Definition: evhtp.h:158
evhtp_proto
Definition: evhtp.h:133
void * cbarg
Definition: evhtp.h:330
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:3899
char * cafile
Definition: evhtp.h:510
long scache_size
Definition: evhtp.h:524
#define EVHTP_RES_RANGENOTSC
Definition: evhtp.h:244
evhtp_type type
Definition: evhtp.h:456
#define EVHTP_PARSE_QUERY_FLAG_IGNORE_HEX
Definition: evhtp.h:996
void evhtp_free(evhtp_t *evhtp)
Definition: evhtp.c:4105
evhtp_res(* evhtp_hook_path_cb)(evhtp_request_t *req, evhtp_path_t *path, void *arg)
Definition: evhtp.h:163
size_t vlen
Definition: evhtp.h:354
void evhtp_send_reply_start(evhtp_request_t *request, evhtp_res code)
Definition: evhtp.c:2988
evhtp_post_accept_cb post_accept
Definition: evhtp.h:260
#define EVHTP_RES_UNAUTH
Definition: evhtp.h:229
evthr_t * thread
Definition: evhtp.h:441
static void _evhtp_thread_init(evthr_t *thr, void *arg)
Definition: evhtp.c:3535
evhtp_query_t * query
Definition: evhtp.h:374
static int _evhtp_request_parser_headers(htparser *p)
Definition: evhtp.c:1440
static int _evhtp_request_parser_header_key(htparser *p, const char *data, size_t len)
Definition: evhtp.c:1129
query_parser_state
Definition: evhtp.c:2614
evhtp_ssl_ctx_t * ssl_ctx
Definition: evhtp.h:288
void evhtp_connection_resume(evhtp_connection_t *c)
resumes a connection (enables reading) and activates resume event.
Definition: evhtp.c:2352
static void _evhtp_run_in_thread(evthr_t *thr, void *arg, void *shared)
Definition: evhtp.c:2138
uint8_t owner
Definition: evhtp.h:457
int evhtp_set_hook(evhtp_hooks_t **hooks, evhtp_hook_type type, evhtp_hook cb, void *arg)
sets a callback hook for either a connection or a path/regex .
Definition: evhtp.c:3351
evhtp_path_t * path
Definition: evhtp.h:371
static int _evhtp_run_post_accept(evhtp_t *htp, evhtp_connection_t *connection)
Definition: evhtp.c:2118
static int _evhtp_request_parser_start(htparser *p)
Definition: evhtp.c:1021
#define EVHTP_RES_CONFLICT
Definition: evhtp.h:237
static void _evhtp_connection_eventcb(evbev_t *bev, short events, void *arg)
Definition: evhtp.c:1915
char * full
Definition: evhtp.h:394
evhtp_callback_type
Definition: evhtp.h:125
static evhtp_res _evhtp_connection_error_hook(evhtp_connection_t *connection, evhtp_error_flags errtype)
runs the user-defined hook when a connection error occurs
Definition: evhtp.c:519
evhtp_res(* evhtp_hook_hostname_cb)(evhtp_request_t *r, const char *hostname, void *arg)
Definition: evhtp.h:171
#define EVHTP_RES_FOUND
Definition: evhtp.h:220
static int _evhtp_connection_accept(evbase_t *evbase, evhtp_connection_t *connection)
Definition: evhtp.c:1994
static void _evhtp_connection_resumecb(int fd, short events, void *arg)
Definition: evhtp.c:1751
evhtp_type
Definition: evhtp.h:139
static evhtp_path_t * _evhtp_path_new(const char *data, size_t len)
parses the path and file from an input buffer
Definition: evhtp.c:916
uint8_t free_connection
Definition: evhtp.h:457
#define EVHTP_RES_URITOOLARGE
Definition: evhtp.h:242
char * dhparams
Definition: evhtp.h:514
a generic container representing an entire URI strucutre
Definition: evhtp.h:369
evhtp_ssl_scache_get scache_get
Definition: evhtp.h:527
struct evconnlistener evserv_t
Definition: evhtp.h:57
static unsigned long _evhtp_ssl_get_thread_id(void)
Definition: evhtp.c:2202
static int _evhtp_should_parse_query_body(evhtp_request_t *req)
determines if the request body contains the query arguments. if the query is NULL and the contenet le...
Definition: evhtp.c:1545
void evhtp_set_bev_flags(evhtp_t *htp, int flags)
set bufferevent flags, defaults to BEV_OPT_CLOSE_ON_FREE
Definition: evhtp.c:3991
#define EVHTP_RES_TIMEOUT
Definition: evhtp.h:236
uint8_t vhost_via_sni
Definition: evhtp.h:457
static int ssl_locks_initialized
Definition: evhtp.c:260
event_t * resume_ev
Definition: evhtp.h:447
evbev_t * evhtp_request_get_bev(evhtp_request_t *request)
returns the underlying requests bufferevent
Definition: evhtp.c:3874
#define EVHTP_RES_IMUSED
Definition: evhtp.h:215
#define EVHTP_RES_PROCESSING
Definition: evhtp.h:204
static evhtp_res _evhtp_chunks_fini_hook(evhtp_request_t *request)
Definition: evhtp.c:467
evbev_t * evhtp_connection_get_bev(evhtp_connection_t *connection)
returns the underlying connections bufferevent
Definition: evhtp.c:3847
void * post_accept_cbarg
Definition: evhtp.h:263
static evhtp_request_t * _evhtp_request_new(evhtp_connection_t *c)
Creates a new evhtp_request_t.
Definition: evhtp.c:743
static void _evhtp_request_free(evhtp_request_t *)
frees all data in an evhtp_request_t along with calling finished hooks
Definition: evhtp.c:794
evhtp_res(* evhtp_hook)()
Definition: evhtp.h:156
static evbuf_t * _evhtp_create_reply(evhtp_request_t *request, evhtp_res code)
Definition: evhtp.c:1639
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:3500
void evhtp_send_reply_body(evhtp_request_t *request, evbuf_t *buf)
Definition: evhtp.c:3005
pthread_mutex_t * lock
Definition: evhtp.h:297
static int _evhtp_request_parser_args(htparser *p, const char *data, size_t len)
Definition: evhtp.c:1048
void evhtp_kvs_free(evhtp_kvs_t *kvs)
frees a the list of key/values, and all underlying entries
Definition: evhtp.c:2520
pthread_mutex_t evhtp_mutex_t
Definition: evhtp.h:66
#define EVHTP_RES_FORBIDDEN
Definition: evhtp.h:231
evbev_t * evhtp_request_take_ownership(evhtp_request_t *request)
Definition: evhtp.c:3879
evhtp_connection_t * conn
Definition: evhtp.h:413
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:2593
static evhtp_res _evhtp_path_hook(evhtp_request_t *request, evhtp_path_t *path)
runs the user-defined on_path hook for a request
Definition: evhtp.c:381
static int _evhtp_ssl_servername(evhtp_ssl_t *ssl, int *unused, void *arg)
Definition: evhtp.c:2284
static evhtp_res _evhtp_connection_fini_hook(evhtp_connection_t *connection)
runs the user-definedhook called just prior to a connection being closed
Definition: evhtp.c:489
#define EVHTP_RES_GONE
Definition: evhtp.h:238
int bev_flags
Definition: evhtp.h:281
int evhtp_add_alias(evhtp_t *evhtp, const char *name)
Add an alias hostname for a virtual-host specific evhtp_t. This avoids having multiple evhtp_t virtua...
Definition: evhtp.c:4011
#define EVHTP_RES_RSTCONTENT
Definition: evhtp.h:212
void * arg
Definition: evhtp.h:280
struct bufferevent evbev_t
Definition: evhtp.h:58
void evhtp_set_post_accept_cb(evhtp_t *htp, evhtp_post_accept_cb cb, void *arg)
Definition: evhtp.c:3663
#define evhtp_query_t
Definition: evhtp.h:94
evhtp_hook_connection_fini_cb on_connection_fini
Definition: evhtp.h:479
#define EVHTP_RES_PARTIAL
Definition: evhtp.h:213
char * capath
Definition: evhtp.h:511
void(* evhtp_ssl_scache_del)(evhtp_t *htp, unsigned char *sid, int sid_len)
Definition: evhtp.h:182
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:3921
static evhtp_res _evhtp_headers_start_hook(evhtp_request_t *request)
Definition: evhtp.c:474
struct timeval send_timeo
Definition: evhtp.h:450
static evhtp_res _evhtp_chunk_new_hook(evhtp_request_t *request, uint64_t len)
Definition: evhtp.c:453
char * username
Definition: evhtp.h:383
void evhtp_send_reply_chunk_start(evhtp_request_t *request, evhtp_res code)
start a chunked response. If data already exists on the output buffer, this will be converted to the ...
Definition: evhtp.c:3045
unsigned int hash
Definition: evhtp.h:329
struct timeval recv_timeo
Definition: evhtp.h:449
static int _evhtp_glob_match2(const char *pattern, size_t plen, const char *string, size_t str_len)
Definition: evhtp.c:546
evhtp_res(* evhtp_pre_accept_cb)(evhtp_connection_t *conn, void *arg)
Definition: evhtp.h:159
static evhtp_callback_t * _evhtp_callback_find(evhtp_callbacks_t *cbs, const char *path, unsigned int *start_offset, unsigned int *end_offset)
Definition: evhtp.c:680
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:3912
evhtp_hooks_t * hooks
Definition: evhtp.h:445
#define evhtp_header_t
Definition: evhtp.h:92
#define HOOK_REQUEST_RUN_NARGS(request, hook_name)
Definition: evhtp.c:78
evhtp_res(* evhtp_hook_chunk_new_cb)(evhtp_request_t *r, uint64_t len, void *arg)
Definition: evhtp.h:167
static void _evhtp_connection_writecb(evbev_t *bev, void *arg)
Definition: evhtp.c:1840
static evhtp_res _evhtp_headers_hook(evhtp_request_t *request, evhtp_headers_t *headers)
runs the user-defined on_Headers hook for a request after all headers have been parsed.
Definition: evhtp.c:414
static void _evhtp_path_free(evhtp_path_t *path)
Definition: evhtp.c:1005
unsigned int matched_soff
Definition: evhtp.h:399
unsigned int matched_eoff
Definition: evhtp.h:402
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:3273
char * file
Definition: evhtp.h:396
#define EVHTP_RES_NOTFOUND
Definition: evhtp.h:232
evhtp_res(* evhtp_hook_write_cb)(evhtp_connection_t *conn, void *arg)
Definition: evhtp.h:172
static void _evhtp_ssl_thread_lock(int mode, int type, const char *file, int line)
Definition: evhtp.c:2213
evhtp_hook_err_cb on_error
Definition: evhtp.h:481
evhtp_callback_type type
Definition: evhtp.h:327
char * named_curve
Definition: evhtp.h:513
char * match_end
Definition: evhtp.h:398
int evhtp_ssl_use_threads(void)
Definition: evhtp.c:3671
evhtp_uri_t * uri
Definition: evhtp.h:415
static int ssl_num_locks
Definition: evhtp.c:258
char * server_name
Definition: evhtp.h:279
#define evhtp_headers_for_each
Definition: evhtp.h:1104
void evhtp_connection_pause(evhtp_connection_t *c)
pauses a connection (disables reading)
Definition: evhtp.c:2338
#define EVHTP_RES_PAYREQ
Definition: evhtp.h:230
evthr_pool_t * thr_pool
Definition: evhtp.h:293
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:2509
char * val
Definition: evhtp.h:351
static void _evhtp_connection_readcb(evbev_t *bev, void *arg)
Definition: evhtp.c:1783
static evhtp_res _evhtp_body_hook(evhtp_request_t *request, evbuf_t *buf)
runs the user-defined on_body hook for requests containing a body. the data is stored in the request-...
Definition: evhtp.c:431
#define EVHTP_RES_NOTIMPL
Definition: evhtp.h:250
evhtp_hook_event_cb on_event
Definition: evhtp.h:487
evserv_t * server
Definition: evhtp.h:278
static void _evhtp_default_request_cb(evhtp_request_t *request, void *arg)
Definition: evhtp.c:2058
void evhtp_request_set_bev(evhtp_request_t *request, evbev_t *bev)
sets the underlying bufferevent for a evhtp_request
Definition: evhtp.c:3889
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:3926
evhtp_t * htp
Definition: evhtp.h:438
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:2576
int evhtp_unset_all_hooks(evhtp_hooks_t **hooks)
removes all hooks.
Definition: evhtp.c:3433
#define evhtp_headers_free
Definition: evhtp.h:1108
#define EVHTP_RES_BWEXEED
Definition: evhtp.h:255
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:2559
evhtp_res(* evhtp_hook_connection_fini_cb)(evhtp_connection_t *connection, void *arg)
Definition: evhtp.h:166
uint64_t max_keepalive_requests
Definition: evhtp.h:283
void(* evhtp_hook_err_cb)(evhtp_request_t *req, evhtp_error_flags errtype, void *arg)
Definition: evhtp.h:152
uint8_t waiting
Definition: evhtp.h:457
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:3617
#define EVHTP_RES_NACCEPTABLE
Definition: evhtp.h:234
static void _evhtp_uri_free(evhtp_uri_t *uri)
frees an overlay URI structure
Definition: evhtp.c:885
#define EVHTP_RES_200
Definition: evhtp.h:207
static void _evhtp_ssl_delete_scache_ent(evhtp_ssl_ctx_t *ctx, evhtp_ssl_sess_t *sess)
Definition: evhtp.c:2225
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:4301
static int _evhtp_require_uri(evhtp_connection_t *c)
Definition: evhtp.c:1349
evbev_t * bev
Definition: evhtp.h:440
evhtp_hooks_t * hooks
Definition: evhtp.h:331
size_t klen
Definition: evhtp.h:353
static void _evhtp_authority_free(evhtp_authority_t *authority)
frees an authority structure
Definition: evhtp.c:851
int evhtp_response_needs_body(const evhtp_res code, const htp_method method)
Determine if a response should have a body. Follows the rules in RFC 2616 section 4...
Definition: evhtp.c:3037
uint8_t connected
Definition: evhtp.h:457
htp_method method
Definition: evhtp.h:421
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:2983
static int _evhtp_request_parser_headers_start(htparser *p)
Definition: evhtp.c:1118
char * pemfile
Definition: evhtp.h:508
#define EVHTP_RES_VERNSUPPORT
Definition: evhtp.h:254
evhtp_ssl_sess_t *(* evhtp_ssl_scache_get)(evhtp_connection_t *connection, unsigned char *sid, int sid_len)
Definition: evhtp.h:183
evhtp_header_t * evhtp_header_key_add(evhtp_headers_t *headers, const char *key, char kalloc)
creates a new evhtp_header_t, sets only the key, and adds to the evhtp_headers TAILQ ...
Definition: evhtp.c:2386
#define EVHTP_RES_CONTINUE
Definition: evhtp.h:202
static void _evhtp_accept_cb(evserv_t *serv, int fd, struct sockaddr *s, int sl, void *arg)
Definition: evhtp.c:2161
static int _evhtp_request_parser_chunks_fini(htparser *p)
Definition: evhtp.c:1524
evhtp_kv_t * evhtp_kv_new(const char *key, const char *val, char kalloc, char valloc)
Allocates a new key/value structure.
Definition: evhtp.c:2439
evhtp_res(* evhtp_hook_chunks_fini_cb)(evhtp_request_t *r, void *arg)
Definition: evhtp.h:169
evbuf_t * buffer_in
Definition: evhtp.h:416
evhtp_hooks_t * hooks
Definition: evhtp.h:414
static int _evhtp_request_parser_fini(htparser *p)
Definition: evhtp.c:1579
void * cbarg
Definition: evhtp.h:430
#define EVHTP_RES_400
Definition: evhtp.h:227
#define EVHTP_RES_OK
Definition: evhtp.h:199
static evhtp_res _evhtp_request_fini_hook(evhtp_request_t *request)
runs the user-defined hook called just prior to a request been free()'d
Definition: evhtp.c:446
static int _evhtp_request_parser_body(htparser *p, const char *data, size_t len)
Definition: evhtp.c:1470
void(* evhtp_hook_event_cb)(evhtp_connection_t *conn, short events, void *arg)
Definition: evhtp.h:153
EVHTP_EXPORT evhtp_header_t * evhtp_header_new(const char *key, const char *val, char kalloc, char valloc)
creates a new evhtp_header_t key/val structure
evhtp_ssl_scache_add scache_add
Definition: evhtp.h:526
char * ciphers
Definition: evhtp.h:512
struct timeval recv_timeo
Definition: evhtp.h:304
void * on_write_arg
Definition: evhtp.h:502
static evhtp_proto _evhtp_protocol(const char major, const char minor)
returns the HTTP protocol version
Definition: evhtp.c:360
evhtp_kvs_t * evhtp_kvs_new(void)
creates an empty list of key/values
Definition: evhtp.c:2430
static const char * status_code_to_str(evhtp_res code)
Definition: evhtp.c:130
#define _evhtp_unlock(h)
Definition: evhtp.c:112
#define EVHTP_RES_ACCEPTED
Definition: evhtp.h:209
uint8_t keepalive
Definition: evhtp.h:457
evhtp_t * htp
Definition: evhtp.h:412
static int _evhtp_request_parser_header_val(htparser *p, const char *data, size_t len)
Definition: evhtp.c:1150
structure which represents a URI path and or file
Definition: evhtp.h:393
int(* evhtp_kvs_iterator)(evhtp_kv_t *kv, void *arg)
Definition: evhtp.h:174
int(* evhtp_ssl_scache_add)(evhtp_connection_t *connection, unsigned char *sid, int sid_len, evhtp_ssl_sess_t *sess)
Definition: evhtp.h:181
char * match_start
Definition: evhtp.h:397
evhtp_connection_t * evhtp_connection_new_dns(evbase_t *evbase, struct evdns_base *dns_base, const char *addr, uint16_t port)
allocate a new connection
Definition: evhtp.c:4183
#define EVHTP_RES_PAUSE
Definition: evhtp.h:195
int disable_100_cont
Definition: evhtp.h:284
char v_heaped
Definition: evhtp.h:357
int verify_peer
Definition: evhtp.h:517
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:2602
structure which represents authority information in a URI
Definition: evhtp.h:382
evhtp_t * evhtp_new(evbase_t *evbase, void *arg)
creates a new evhtp_t instance
Definition: evhtp.c:4081
evhtp_res status
Definition: evhtp.h:422
void(* evhtp_thread_init_cb)(evhtp_t *htp, evthr_t *thr, void *arg)
Definition: evhtp.h:150
evhtp_authority_t * authority
Definition: evhtp.h:370
long ssl_opts
Definition: evhtp.h:515
#define evhtp_request_content_len(r)
Definition: evhtp.h:435
#define EVHTP_RES_USEPROXY
Definition: evhtp.h:223
#define EVHTP_RES_URI_TOOLONG
Definition: evhtp.h:205