https-client.c revision 1.1.1.2 1 1.1 christos /* $NetBSD: https-client.c,v 1.1.1.2 2021/04/07 02:43:15 christos Exp $ */
2 1.1 christos /*
3 1.1 christos This is an example of how to hook up evhttp with bufferevent_ssl
4 1.1 christos
5 1.1 christos It just GETs an https URL given on the command-line and prints the response
6 1.1 christos body to stdout.
7 1.1 christos
8 1.1 christos Actually, it also accepts plain http URLs to make it easy to compare http vs
9 1.1 christos https code paths.
10 1.1 christos
11 1.1 christos Loosely based on le-proxy.c.
12 1.1 christos */
13 1.1 christos
14 1.1 christos // Get rid of OSX 10.7 and greater deprecation warnings.
15 1.1 christos #if defined(__APPLE__) && defined(__clang__)
16 1.1 christos #pragma clang diagnostic ignored "-Wdeprecated-declarations"
17 1.1 christos #endif
18 1.1 christos
19 1.1 christos #include <stdio.h>
20 1.1 christos #include <assert.h>
21 1.1 christos #include <stdlib.h>
22 1.1 christos #include <string.h>
23 1.1 christos #include <errno.h>
24 1.1 christos
25 1.1 christos #ifdef _WIN32
26 1.1 christos #include <winsock2.h>
27 1.1 christos #include <ws2tcpip.h>
28 1.1 christos
29 1.1 christos #define snprintf _snprintf
30 1.1 christos #define strcasecmp _stricmp
31 1.1 christos #else
32 1.1 christos #include <sys/socket.h>
33 1.1 christos #include <netinet/in.h>
34 1.1 christos #endif
35 1.1 christos
36 1.1 christos #include <event2/bufferevent_ssl.h>
37 1.1 christos #include <event2/bufferevent.h>
38 1.1 christos #include <event2/buffer.h>
39 1.1 christos #include <event2/listener.h>
40 1.1 christos #include <event2/util.h>
41 1.1 christos #include <event2/http.h>
42 1.1 christos
43 1.1 christos #include <openssl/ssl.h>
44 1.1 christos #include <openssl/err.h>
45 1.1 christos #include <openssl/rand.h>
46 1.1 christos
47 1.1 christos #include "openssl_hostname_validation.h"
48 1.1 christos
49 1.1 christos static int ignore_cert = 0;
50 1.1 christos
51 1.1 christos static void
52 1.1 christos http_request_done(struct evhttp_request *req, void *ctx)
53 1.1 christos {
54 1.1 christos char buffer[256];
55 1.1 christos int nread;
56 1.1 christos
57 1.1.1.2 christos if (!req || !evhttp_request_get_response_code(req)) {
58 1.1 christos /* If req is NULL, it means an error occurred, but
59 1.1 christos * sadly we are mostly left guessing what the error
60 1.1 christos * might have been. We'll do our best... */
61 1.1 christos struct bufferevent *bev = (struct bufferevent *) ctx;
62 1.1 christos unsigned long oslerr;
63 1.1 christos int printed_err = 0;
64 1.1 christos int errcode = EVUTIL_SOCKET_ERROR();
65 1.1 christos fprintf(stderr, "some request failed - no idea which one though!\n");
66 1.1 christos /* Print out the OpenSSL error queue that libevent
67 1.1 christos * squirreled away for us, if any. */
68 1.1 christos while ((oslerr = bufferevent_get_openssl_error(bev))) {
69 1.1 christos ERR_error_string_n(oslerr, buffer, sizeof(buffer));
70 1.1 christos fprintf(stderr, "%s\n", buffer);
71 1.1 christos printed_err = 1;
72 1.1 christos }
73 1.1 christos /* If the OpenSSL error queue was empty, maybe it was a
74 1.1 christos * socket error; let's try printing that. */
75 1.1 christos if (! printed_err)
76 1.1 christos fprintf(stderr, "socket error = %s (%d)\n",
77 1.1 christos evutil_socket_error_to_string(errcode),
78 1.1 christos errcode);
79 1.1 christos return;
80 1.1 christos }
81 1.1 christos
82 1.1 christos fprintf(stderr, "Response line: %d %s\n",
83 1.1 christos evhttp_request_get_response_code(req),
84 1.1 christos evhttp_request_get_response_code_line(req));
85 1.1 christos
86 1.1 christos while ((nread = evbuffer_remove(evhttp_request_get_input_buffer(req),
87 1.1 christos buffer, sizeof(buffer)))
88 1.1 christos > 0) {
89 1.1 christos /* These are just arbitrary chunks of 256 bytes.
90 1.1 christos * They are not lines, so we can't treat them as such. */
91 1.1 christos fwrite(buffer, nread, 1, stdout);
92 1.1 christos }
93 1.1 christos }
94 1.1 christos
95 1.1 christos static void
96 1.1 christos syntax(void)
97 1.1 christos {
98 1.1 christos fputs("Syntax:\n", stderr);
99 1.1 christos fputs(" https-client -url <https-url> [-data data-file.bin] [-ignore-cert] [-retries num] [-timeout sec] [-crt crt]\n", stderr);
100 1.1 christos fputs("Example:\n", stderr);
101 1.1 christos fputs(" https-client -url https://ip.appspot.com/\n", stderr);
102 1.1 christos }
103 1.1 christos
104 1.1 christos static void
105 1.1 christos err(const char *msg)
106 1.1 christos {
107 1.1 christos fputs(msg, stderr);
108 1.1 christos }
109 1.1 christos
110 1.1 christos static void
111 1.1 christos err_openssl(const char *func)
112 1.1 christos {
113 1.1 christos fprintf (stderr, "%s failed:\n", func);
114 1.1 christos
115 1.1 christos /* This is the OpenSSL function that prints the contents of the
116 1.1 christos * error stack to the specified file handle. */
117 1.1 christos ERR_print_errors_fp (stderr);
118 1.1 christos
119 1.1 christos exit(1);
120 1.1 christos }
121 1.1 christos
122 1.1 christos /* See http://archives.seul.org/libevent/users/Jan-2013/msg00039.html */
123 1.1 christos static int cert_verify_callback(X509_STORE_CTX *x509_ctx, void *arg)
124 1.1 christos {
125 1.1 christos char cert_str[256];
126 1.1 christos const char *host = (const char *) arg;
127 1.1 christos const char *res_str = "X509_verify_cert failed";
128 1.1 christos HostnameValidationResult res = Error;
129 1.1 christos
130 1.1 christos /* This is the function that OpenSSL would call if we hadn't called
131 1.1 christos * SSL_CTX_set_cert_verify_callback(). Therefore, we are "wrapping"
132 1.1 christos * the default functionality, rather than replacing it. */
133 1.1 christos int ok_so_far = 0;
134 1.1 christos
135 1.1 christos X509 *server_cert = NULL;
136 1.1 christos
137 1.1 christos if (ignore_cert) {
138 1.1 christos return 1;
139 1.1 christos }
140 1.1 christos
141 1.1 christos ok_so_far = X509_verify_cert(x509_ctx);
142 1.1 christos
143 1.1 christos server_cert = X509_STORE_CTX_get_current_cert(x509_ctx);
144 1.1 christos
145 1.1 christos if (ok_so_far) {
146 1.1 christos res = validate_hostname(host, server_cert);
147 1.1 christos
148 1.1 christos switch (res) {
149 1.1 christos case MatchFound:
150 1.1 christos res_str = "MatchFound";
151 1.1 christos break;
152 1.1 christos case MatchNotFound:
153 1.1 christos res_str = "MatchNotFound";
154 1.1 christos break;
155 1.1 christos case NoSANPresent:
156 1.1 christos res_str = "NoSANPresent";
157 1.1 christos break;
158 1.1 christos case MalformedCertificate:
159 1.1 christos res_str = "MalformedCertificate";
160 1.1 christos break;
161 1.1 christos case Error:
162 1.1 christos res_str = "Error";
163 1.1 christos break;
164 1.1 christos default:
165 1.1 christos res_str = "WTF!";
166 1.1 christos break;
167 1.1 christos }
168 1.1 christos }
169 1.1 christos
170 1.1 christos X509_NAME_oneline(X509_get_subject_name (server_cert),
171 1.1 christos cert_str, sizeof (cert_str));
172 1.1 christos
173 1.1 christos if (res == MatchFound) {
174 1.1 christos printf("https server '%s' has this certificate, "
175 1.1 christos "which looks good to me:\n%s\n",
176 1.1 christos host, cert_str);
177 1.1 christos return 1;
178 1.1 christos } else {
179 1.1 christos printf("Got '%s' for hostname '%s' and certificate:\n%s\n",
180 1.1 christos res_str, host, cert_str);
181 1.1 christos return 0;
182 1.1 christos }
183 1.1 christos }
184 1.1.1.2 christos
185 1.1.1.2 christos #ifdef _WIN32
186 1.1.1.2 christos static int
187 1.1.1.2 christos add_cert_for_store(X509_STORE *store, const char *name)
188 1.1.1.2 christos {
189 1.1.1.2 christos HCERTSTORE sys_store = NULL;
190 1.1.1.2 christos PCCERT_CONTEXT ctx = NULL;
191 1.1.1.2 christos int r = 0;
192 1.1.1.2 christos
193 1.1.1.2 christos sys_store = CertOpenSystemStore(0, name);
194 1.1.1.2 christos if (!sys_store) {
195 1.1.1.2 christos err("failed to open system certificate store");
196 1.1.1.2 christos return -1;
197 1.1.1.2 christos }
198 1.1.1.2 christos while ((ctx = CertEnumCertificatesInStore(sys_store, ctx))) {
199 1.1.1.2 christos X509 *x509 = d2i_X509(NULL, (unsigned char const **)&ctx->pbCertEncoded,
200 1.1.1.2 christos ctx->cbCertEncoded);
201 1.1.1.2 christos if (x509) {
202 1.1.1.2 christos X509_STORE_add_cert(store, x509);
203 1.1.1.2 christos X509_free(x509);
204 1.1.1.2 christos } else {
205 1.1.1.2 christos r = -1;
206 1.1.1.2 christos err_openssl("d2i_X509");
207 1.1.1.2 christos break;
208 1.1.1.2 christos }
209 1.1.1.2 christos }
210 1.1.1.2 christos CertCloseStore(sys_store, 0);
211 1.1.1.2 christos return r;
212 1.1.1.2 christos }
213 1.1 christos #endif
214 1.1 christos
215 1.1 christos int
216 1.1 christos main(int argc, char **argv)
217 1.1 christos {
218 1.1 christos int r;
219 1.1.1.2 christos struct event_base *base = NULL;
220 1.1 christos struct evhttp_uri *http_uri = NULL;
221 1.1 christos const char *url = NULL, *data_file = NULL;
222 1.1.1.2 christos const char *crt = NULL;
223 1.1 christos const char *scheme, *host, *path, *query;
224 1.1 christos char uri[256];
225 1.1 christos int port;
226 1.1 christos int retries = 0;
227 1.1 christos int timeout = -1;
228 1.1 christos
229 1.1 christos SSL_CTX *ssl_ctx = NULL;
230 1.1 christos SSL *ssl = NULL;
231 1.1 christos struct bufferevent *bev;
232 1.1 christos struct evhttp_connection *evcon = NULL;
233 1.1 christos struct evhttp_request *req;
234 1.1 christos struct evkeyvalq *output_headers;
235 1.1 christos struct evbuffer *output_buffer;
236 1.1 christos
237 1.1 christos int i;
238 1.1 christos int ret = 0;
239 1.1 christos enum { HTTP, HTTPS } type = HTTP;
240 1.1 christos
241 1.1 christos for (i = 1; i < argc; i++) {
242 1.1 christos if (!strcmp("-url", argv[i])) {
243 1.1 christos if (i < argc - 1) {
244 1.1 christos url = argv[i + 1];
245 1.1 christos } else {
246 1.1 christos syntax();
247 1.1 christos goto error;
248 1.1 christos }
249 1.1 christos } else if (!strcmp("-crt", argv[i])) {
250 1.1 christos if (i < argc - 1) {
251 1.1 christos crt = argv[i + 1];
252 1.1 christos } else {
253 1.1 christos syntax();
254 1.1 christos goto error;
255 1.1 christos }
256 1.1 christos } else if (!strcmp("-ignore-cert", argv[i])) {
257 1.1 christos ignore_cert = 1;
258 1.1 christos } else if (!strcmp("-data", argv[i])) {
259 1.1 christos if (i < argc - 1) {
260 1.1 christos data_file = argv[i + 1];
261 1.1 christos } else {
262 1.1 christos syntax();
263 1.1 christos goto error;
264 1.1 christos }
265 1.1 christos } else if (!strcmp("-retries", argv[i])) {
266 1.1 christos if (i < argc - 1) {
267 1.1 christos retries = atoi(argv[i + 1]);
268 1.1 christos } else {
269 1.1 christos syntax();
270 1.1 christos goto error;
271 1.1 christos }
272 1.1 christos } else if (!strcmp("-timeout", argv[i])) {
273 1.1 christos if (i < argc - 1) {
274 1.1 christos timeout = atoi(argv[i + 1]);
275 1.1 christos } else {
276 1.1 christos syntax();
277 1.1 christos goto error;
278 1.1 christos }
279 1.1 christos } else if (!strcmp("-help", argv[i])) {
280 1.1 christos syntax();
281 1.1 christos goto error;
282 1.1 christos }
283 1.1 christos }
284 1.1 christos
285 1.1 christos if (!url) {
286 1.1 christos syntax();
287 1.1 christos goto error;
288 1.1 christos }
289 1.1 christos
290 1.1 christos #ifdef _WIN32
291 1.1 christos {
292 1.1 christos WORD wVersionRequested;
293 1.1 christos WSADATA wsaData;
294 1.1 christos int err;
295 1.1 christos
296 1.1 christos wVersionRequested = MAKEWORD(2, 2);
297 1.1 christos
298 1.1 christos err = WSAStartup(wVersionRequested, &wsaData);
299 1.1 christos if (err != 0) {
300 1.1 christos printf("WSAStartup failed with error: %d\n", err);
301 1.1 christos goto error;
302 1.1 christos }
303 1.1 christos }
304 1.1 christos #endif // _WIN32
305 1.1 christos
306 1.1 christos http_uri = evhttp_uri_parse(url);
307 1.1 christos if (http_uri == NULL) {
308 1.1 christos err("malformed url");
309 1.1 christos goto error;
310 1.1 christos }
311 1.1 christos
312 1.1 christos scheme = evhttp_uri_get_scheme(http_uri);
313 1.1 christos if (scheme == NULL || (strcasecmp(scheme, "https") != 0 &&
314 1.1 christos strcasecmp(scheme, "http") != 0)) {
315 1.1 christos err("url must be http or https");
316 1.1 christos goto error;
317 1.1 christos }
318 1.1 christos
319 1.1 christos host = evhttp_uri_get_host(http_uri);
320 1.1 christos if (host == NULL) {
321 1.1 christos err("url must have a host");
322 1.1 christos goto error;
323 1.1 christos }
324 1.1 christos
325 1.1 christos port = evhttp_uri_get_port(http_uri);
326 1.1 christos if (port == -1) {
327 1.1 christos port = (strcasecmp(scheme, "http") == 0) ? 80 : 443;
328 1.1 christos }
329 1.1 christos
330 1.1 christos path = evhttp_uri_get_path(http_uri);
331 1.1 christos if (strlen(path) == 0) {
332 1.1 christos path = "/";
333 1.1 christos }
334 1.1 christos
335 1.1 christos query = evhttp_uri_get_query(http_uri);
336 1.1 christos if (query == NULL) {
337 1.1 christos snprintf(uri, sizeof(uri) - 1, "%s", path);
338 1.1 christos } else {
339 1.1 christos snprintf(uri, sizeof(uri) - 1, "%s?%s", path, query);
340 1.1 christos }
341 1.1 christos uri[sizeof(uri) - 1] = '\0';
342 1.1 christos
343 1.1.1.2 christos #if (OPENSSL_VERSION_NUMBER < 0x10100000L) || \
344 1.1.1.2 christos (defined(LIBRESSL_VERSION_NUMBER) && LIBRESSL_VERSION_NUMBER < 0x20700000L)
345 1.1 christos // Initialize OpenSSL
346 1.1 christos SSL_library_init();
347 1.1 christos ERR_load_crypto_strings();
348 1.1 christos SSL_load_error_strings();
349 1.1 christos OpenSSL_add_all_algorithms();
350 1.1 christos #endif
351 1.1 christos
352 1.1 christos /* This isn't strictly necessary... OpenSSL performs RAND_poll
353 1.1 christos * automatically on first use of random number generator. */
354 1.1 christos r = RAND_poll();
355 1.1 christos if (r == 0) {
356 1.1 christos err_openssl("RAND_poll");
357 1.1 christos goto error;
358 1.1 christos }
359 1.1 christos
360 1.1 christos /* Create a new OpenSSL context */
361 1.1 christos ssl_ctx = SSL_CTX_new(SSLv23_method());
362 1.1 christos if (!ssl_ctx) {
363 1.1 christos err_openssl("SSL_CTX_new");
364 1.1 christos goto error;
365 1.1 christos }
366 1.1 christos
367 1.1.1.2 christos if (crt == NULL) {
368 1.1.1.2 christos X509_STORE *store;
369 1.1.1.2 christos /* Attempt to use the system's trusted root certificates. */
370 1.1.1.2 christos store = SSL_CTX_get_cert_store(ssl_ctx);
371 1.1.1.2 christos #ifdef _WIN32
372 1.1.1.2 christos if (add_cert_for_store(store, "CA") < 0 ||
373 1.1.1.2 christos add_cert_for_store(store, "AuthRoot") < 0 ||
374 1.1.1.2 christos add_cert_for_store(store, "ROOT") < 0) {
375 1.1.1.2 christos goto error;
376 1.1.1.2 christos }
377 1.1.1.2 christos #else // _WIN32
378 1.1.1.2 christos if (X509_STORE_set_default_paths(store) != 1) {
379 1.1.1.2 christos err_openssl("X509_STORE_set_default_paths");
380 1.1.1.2 christos goto error;
381 1.1.1.2 christos }
382 1.1.1.2 christos #endif // _WIN32
383 1.1.1.2 christos } else {
384 1.1.1.2 christos if (SSL_CTX_load_verify_locations(ssl_ctx, crt, NULL) != 1) {
385 1.1.1.2 christos err_openssl("SSL_CTX_load_verify_locations");
386 1.1.1.2 christos goto error;
387 1.1.1.2 christos }
388 1.1 christos }
389 1.1 christos /* Ask OpenSSL to verify the server certificate. Note that this
390 1.1 christos * does NOT include verifying that the hostname is correct.
391 1.1 christos * So, by itself, this means anyone with any legitimate
392 1.1 christos * CA-issued certificate for any website, can impersonate any
393 1.1 christos * other website in the world. This is not good. See "The
394 1.1 christos * Most Dangerous Code in the World" article at
395 1.1 christos * https://crypto.stanford.edu/~dabo/pubs/abstracts/ssl-client-bugs.html
396 1.1 christos */
397 1.1 christos SSL_CTX_set_verify(ssl_ctx, SSL_VERIFY_PEER, NULL);
398 1.1 christos /* This is how we solve the problem mentioned in the previous
399 1.1 christos * comment. We "wrap" OpenSSL's validation routine in our
400 1.1 christos * own routine, which also validates the hostname by calling
401 1.1 christos * the code provided by iSECPartners. Note that even though
402 1.1 christos * the "Everything You've Always Wanted to Know About
403 1.1 christos * Certificate Validation With OpenSSL (But Were Afraid to
404 1.1 christos * Ask)" paper from iSECPartners says very explicitly not to
405 1.1 christos * call SSL_CTX_set_cert_verify_callback (at the bottom of
406 1.1 christos * page 2), what we're doing here is safe because our
407 1.1 christos * cert_verify_callback() calls X509_verify_cert(), which is
408 1.1 christos * OpenSSL's built-in routine which would have been called if
409 1.1 christos * we hadn't set the callback. Therefore, we're just
410 1.1 christos * "wrapping" OpenSSL's routine, not replacing it. */
411 1.1 christos SSL_CTX_set_cert_verify_callback(ssl_ctx, cert_verify_callback,
412 1.1 christos (void *) host);
413 1.1 christos
414 1.1 christos // Create event base
415 1.1 christos base = event_base_new();
416 1.1 christos if (!base) {
417 1.1 christos perror("event_base_new()");
418 1.1 christos goto error;
419 1.1 christos }
420 1.1 christos
421 1.1 christos // Create OpenSSL bufferevent and stack evhttp on top of it
422 1.1 christos ssl = SSL_new(ssl_ctx);
423 1.1 christos if (ssl == NULL) {
424 1.1 christos err_openssl("SSL_new()");
425 1.1 christos goto error;
426 1.1 christos }
427 1.1 christos
428 1.1 christos #ifdef SSL_CTRL_SET_TLSEXT_HOSTNAME
429 1.1 christos // Set hostname for SNI extension
430 1.1 christos SSL_set_tlsext_host_name(ssl, host);
431 1.1 christos #endif
432 1.1 christos
433 1.1 christos if (strcasecmp(scheme, "http") == 0) {
434 1.1 christos bev = bufferevent_socket_new(base, -1, BEV_OPT_CLOSE_ON_FREE);
435 1.1 christos } else {
436 1.1 christos type = HTTPS;
437 1.1 christos bev = bufferevent_openssl_socket_new(base, -1, ssl,
438 1.1 christos BUFFEREVENT_SSL_CONNECTING,
439 1.1 christos BEV_OPT_CLOSE_ON_FREE|BEV_OPT_DEFER_CALLBACKS);
440 1.1 christos }
441 1.1 christos
442 1.1 christos if (bev == NULL) {
443 1.1 christos fprintf(stderr, "bufferevent_openssl_socket_new() failed\n");
444 1.1 christos goto error;
445 1.1 christos }
446 1.1 christos
447 1.1 christos bufferevent_openssl_set_allow_dirty_shutdown(bev, 1);
448 1.1 christos
449 1.1 christos // For simplicity, we let DNS resolution block. Everything else should be
450 1.1 christos // asynchronous though.
451 1.1 christos evcon = evhttp_connection_base_bufferevent_new(base, NULL, bev,
452 1.1 christos host, port);
453 1.1 christos if (evcon == NULL) {
454 1.1 christos fprintf(stderr, "evhttp_connection_base_bufferevent_new() failed\n");
455 1.1 christos goto error;
456 1.1 christos }
457 1.1 christos
458 1.1 christos if (retries > 0) {
459 1.1 christos evhttp_connection_set_retries(evcon, retries);
460 1.1 christos }
461 1.1 christos if (timeout >= 0) {
462 1.1 christos evhttp_connection_set_timeout(evcon, timeout);
463 1.1 christos }
464 1.1 christos
465 1.1 christos // Fire off the request
466 1.1 christos req = evhttp_request_new(http_request_done, bev);
467 1.1 christos if (req == NULL) {
468 1.1 christos fprintf(stderr, "evhttp_request_new() failed\n");
469 1.1 christos goto error;
470 1.1 christos }
471 1.1 christos
472 1.1 christos output_headers = evhttp_request_get_output_headers(req);
473 1.1 christos evhttp_add_header(output_headers, "Host", host);
474 1.1 christos evhttp_add_header(output_headers, "Connection", "close");
475 1.1 christos
476 1.1 christos if (data_file) {
477 1.1 christos /* NOTE: In production code, you'd probably want to use
478 1.1 christos * evbuffer_add_file() or evbuffer_add_file_segment(), to
479 1.1 christos * avoid needless copying. */
480 1.1 christos FILE * f = fopen(data_file, "rb");
481 1.1 christos char buf[1024];
482 1.1 christos size_t s;
483 1.1 christos size_t bytes = 0;
484 1.1 christos
485 1.1 christos if (!f) {
486 1.1 christos syntax();
487 1.1 christos goto error;
488 1.1 christos }
489 1.1 christos
490 1.1 christos output_buffer = evhttp_request_get_output_buffer(req);
491 1.1 christos while ((s = fread(buf, 1, sizeof(buf), f)) > 0) {
492 1.1 christos evbuffer_add(output_buffer, buf, s);
493 1.1 christos bytes += s;
494 1.1 christos }
495 1.1 christos evutil_snprintf(buf, sizeof(buf)-1, "%lu", (unsigned long)bytes);
496 1.1 christos evhttp_add_header(output_headers, "Content-Length", buf);
497 1.1 christos fclose(f);
498 1.1 christos }
499 1.1 christos
500 1.1 christos r = evhttp_make_request(evcon, req, data_file ? EVHTTP_REQ_POST : EVHTTP_REQ_GET, uri);
501 1.1 christos if (r != 0) {
502 1.1 christos fprintf(stderr, "evhttp_make_request() failed\n");
503 1.1 christos goto error;
504 1.1 christos }
505 1.1 christos
506 1.1 christos event_base_dispatch(base);
507 1.1 christos goto cleanup;
508 1.1 christos
509 1.1 christos error:
510 1.1 christos ret = 1;
511 1.1 christos cleanup:
512 1.1 christos if (evcon)
513 1.1 christos evhttp_connection_free(evcon);
514 1.1 christos if (http_uri)
515 1.1 christos evhttp_uri_free(http_uri);
516 1.1.1.2 christos if (base)
517 1.1.1.2 christos event_base_free(base);
518 1.1 christos
519 1.1 christos if (ssl_ctx)
520 1.1 christos SSL_CTX_free(ssl_ctx);
521 1.1 christos if (type == HTTP && ssl)
522 1.1 christos SSL_free(ssl);
523 1.1.1.2 christos #if (OPENSSL_VERSION_NUMBER < 0x10100000L) || \
524 1.1.1.2 christos (defined(LIBRESSL_VERSION_NUMBER) && LIBRESSL_VERSION_NUMBER < 0x20700000L)
525 1.1 christos EVP_cleanup();
526 1.1 christos ERR_free_strings();
527 1.1 christos
528 1.1.1.2 christos #if OPENSSL_VERSION_NUMBER < 0x10000000L
529 1.1 christos ERR_remove_state(0);
530 1.1.1.2 christos #else
531 1.1.1.2 christos ERR_remove_thread_state(NULL);
532 1.1 christos #endif
533 1.1.1.2 christos
534 1.1 christos CRYPTO_cleanup_all_ex_data();
535 1.1 christos
536 1.1 christos sk_SSL_COMP_free(SSL_COMP_get_compression_methods());
537 1.1.1.2 christos #endif /* (OPENSSL_VERSION_NUMBER < 0x10100000L) || \
538 1.1.1.2 christos (defined(LIBRESSL_VERSION_NUMBER) && LIBRESSL_VERSION_NUMBER < 0x20700000L) */
539 1.1 christos
540 1.1 christos #ifdef _WIN32
541 1.1 christos WSACleanup();
542 1.1 christos #endif
543 1.1 christos
544 1.1 christos return ret;
545 1.1 christos }
546