xref: /libevent-2.1.12/sample/https-client.c (revision 462e6b60)
1be46c99bSCatalin Patulea /*
2be46c99bSCatalin Patulea   This is an example of how to hook up evhttp with bufferevent_ssl
3be46c99bSCatalin Patulea 
4be46c99bSCatalin Patulea   It just GETs an https URL given on the command-line and prints the response
5be46c99bSCatalin Patulea   body to stdout.
6be46c99bSCatalin Patulea 
7be46c99bSCatalin Patulea   Actually, it also accepts plain http URLs to make it easy to compare http vs
8be46c99bSCatalin Patulea   https code paths.
9be46c99bSCatalin Patulea 
10be46c99bSCatalin Patulea   Loosely based on le-proxy.c.
11be46c99bSCatalin Patulea  */
12be46c99bSCatalin Patulea 
1369c3516bSJoakim Söderberg // Get rid of OSX 10.7 and greater deprecation warnings.
14d7be7887SJoakim Soderberg #if defined(__APPLE__) && defined(__clang__)
1569c3516bSJoakim Söderberg #pragma clang diagnostic ignored "-Wdeprecated-declarations"
160ef1d04eSJoakim Soderberg #endif
1769c3516bSJoakim Söderberg 
18be46c99bSCatalin Patulea #include <stdio.h>
19be46c99bSCatalin Patulea #include <assert.h>
20be46c99bSCatalin Patulea #include <stdlib.h>
21be46c99bSCatalin Patulea #include <string.h>
22be46c99bSCatalin Patulea #include <errno.h>
23be46c99bSCatalin Patulea 
2488ecda3bSNick Mathewson #ifdef _WIN32
25be46c99bSCatalin Patulea #include <winsock2.h>
26be46c99bSCatalin Patulea #include <ws2tcpip.h>
2719222e52SJoakim Soderberg 
2819222e52SJoakim Soderberg #define snprintf _snprintf
2919222e52SJoakim Soderberg #define strcasecmp _stricmp
30be46c99bSCatalin Patulea #else
31be46c99bSCatalin Patulea #include <sys/socket.h>
32be46c99bSCatalin Patulea #include <netinet/in.h>
33be46c99bSCatalin Patulea #endif
34be46c99bSCatalin Patulea 
35be46c99bSCatalin Patulea #include <event2/bufferevent_ssl.h>
36be46c99bSCatalin Patulea #include <event2/bufferevent.h>
37be46c99bSCatalin Patulea #include <event2/buffer.h>
38be46c99bSCatalin Patulea #include <event2/listener.h>
39be46c99bSCatalin Patulea #include <event2/util.h>
40be46c99bSCatalin Patulea #include <event2/http.h>
41be46c99bSCatalin Patulea 
42be46c99bSCatalin Patulea #include <openssl/ssl.h>
43be46c99bSCatalin Patulea #include <openssl/err.h>
44be46c99bSCatalin Patulea #include <openssl/rand.h>
45be46c99bSCatalin Patulea 
4664d9f161SPatrick Pelletier #include "openssl_hostname_validation.h"
4764d9f161SPatrick Pelletier 
48be46c99bSCatalin Patulea static struct event_base *base;
49c5887f73SAlexey Ozeritsky static int ignore_cert = 0;
50be46c99bSCatalin Patulea 
51be46c99bSCatalin Patulea static void
52be46c99bSCatalin Patulea http_request_done(struct evhttp_request *req, void *ctx)
53be46c99bSCatalin Patulea {
54be46c99bSCatalin Patulea 	char buffer[256];
55be46c99bSCatalin Patulea 	int nread;
56be46c99bSCatalin Patulea 
57be46c99bSCatalin Patulea 	if (req == NULL) {
585754d96aSPatrick Pelletier 		/* If req is NULL, it means an error occurred, but
595754d96aSPatrick Pelletier 		 * sadly we are mostly left guessing what the error
605754d96aSPatrick Pelletier 		 * might have been.  We'll do our best... */
615754d96aSPatrick Pelletier 		struct bufferevent *bev = (struct bufferevent *) ctx;
625754d96aSPatrick Pelletier 		unsigned long oslerr;
635754d96aSPatrick Pelletier 		int printed_err = 0;
645754d96aSPatrick Pelletier 		int errcode = EVUTIL_SOCKET_ERROR();
65be46c99bSCatalin Patulea 		fprintf(stderr, "some request failed - no idea which one though!\n");
665754d96aSPatrick Pelletier 		/* Print out the OpenSSL error queue that libevent
675754d96aSPatrick Pelletier 		 * squirreled away for us, if any. */
685754d96aSPatrick Pelletier 		while ((oslerr = bufferevent_get_openssl_error(bev))) {
695754d96aSPatrick Pelletier 			ERR_error_string_n(oslerr, buffer, sizeof(buffer));
705754d96aSPatrick Pelletier 			fprintf(stderr, "%s\n", buffer);
715754d96aSPatrick Pelletier 			printed_err = 1;
725754d96aSPatrick Pelletier 		}
735754d96aSPatrick Pelletier 		/* If the OpenSSL error queue was empty, maybe it was a
745754d96aSPatrick Pelletier 		 * socket error; let's try printing that. */
755754d96aSPatrick Pelletier 		if (! printed_err)
765754d96aSPatrick Pelletier 			fprintf(stderr, "socket error = %s (%d)\n",
775754d96aSPatrick Pelletier 				evutil_socket_error_to_string(errcode),
785754d96aSPatrick Pelletier 				errcode);
79be46c99bSCatalin Patulea 		return;
80be46c99bSCatalin Patulea 	}
81be46c99bSCatalin Patulea 
82be46c99bSCatalin Patulea 	fprintf(stderr, "Response line: %d %s\n",
838a90a850SNick Mathewson 	    evhttp_request_get_response_code(req),
848a90a850SNick Mathewson 	    evhttp_request_get_response_code_line(req));
85be46c99bSCatalin Patulea 
8695acdaa3SNick Mathewson 	while ((nread = evbuffer_remove(evhttp_request_get_input_buffer(req),
8795acdaa3SNick Mathewson 		    buffer, sizeof(buffer)))
88be46c99bSCatalin Patulea 	       > 0) {
8942d7441aSPatrick Pelletier 		/* These are just arbitrary chunks of 256 bytes.
9042d7441aSPatrick Pelletier 		 * They are not lines, so we can't treat them as such. */
91be46c99bSCatalin Patulea 		fwrite(buffer, nread, 1, stdout);
92be46c99bSCatalin Patulea 	}
93be46c99bSCatalin Patulea }
94be46c99bSCatalin Patulea 
95be46c99bSCatalin Patulea static void
96be46c99bSCatalin Patulea syntax(void)
97be46c99bSCatalin Patulea {
98be46c99bSCatalin Patulea 	fputs("Syntax:\n", stderr);
99c5887f73SAlexey Ozeritsky 	fputs("   https-client -url <https-url> [-data data-file.bin] [-ignore-cert]\n", stderr);
100be46c99bSCatalin Patulea 	fputs("Example:\n", stderr);
101c5887f73SAlexey Ozeritsky 	fputs("   https-client -url https://ip.appspot.com/\n", stderr);
102be46c99bSCatalin Patulea 
103be46c99bSCatalin Patulea 	exit(1);
104be46c99bSCatalin Patulea }
105be46c99bSCatalin Patulea 
106be46c99bSCatalin Patulea static void
107be46c99bSCatalin Patulea die(const char *msg)
108be46c99bSCatalin Patulea {
109be46c99bSCatalin Patulea 	fputs(msg, stderr);
110be46c99bSCatalin Patulea 	exit(1);
111be46c99bSCatalin Patulea }
112be46c99bSCatalin Patulea 
1135754d96aSPatrick Pelletier static void
1145754d96aSPatrick Pelletier die_openssl(const char *func)
1155754d96aSPatrick Pelletier {
1165754d96aSPatrick Pelletier 	fprintf (stderr, "%s failed:\n", func);
1175754d96aSPatrick Pelletier 
1185754d96aSPatrick Pelletier 	/* This is the OpenSSL function that prints the contents of the
1195754d96aSPatrick Pelletier 	 * error stack to the specified file handle. */
1205754d96aSPatrick Pelletier 	ERR_print_errors_fp (stderr);
1215754d96aSPatrick Pelletier 
1225754d96aSPatrick Pelletier 	exit(1);
1235754d96aSPatrick Pelletier }
1245754d96aSPatrick Pelletier 
12564d9f161SPatrick Pelletier /* See http://archives.seul.org/libevent/users/Jan-2013/msg00039.html */
12664d9f161SPatrick Pelletier static int cert_verify_callback(X509_STORE_CTX *x509_ctx, void *arg)
12764d9f161SPatrick Pelletier {
12864d9f161SPatrick Pelletier 	char cert_str[256];
12964d9f161SPatrick Pelletier 	const char *host = (const char *) arg;
13064d9f161SPatrick Pelletier 	const char *res_str = "X509_verify_cert failed";
13164d9f161SPatrick Pelletier 	HostnameValidationResult res = Error;
13264d9f161SPatrick Pelletier 
13364d9f161SPatrick Pelletier 	/* This is the function that OpenSSL would call if we hadn't called
13464d9f161SPatrick Pelletier 	 * SSL_CTX_set_cert_verify_callback().  Therefore, we are "wrapping"
13564d9f161SPatrick Pelletier 	 * the default functionality, rather than replacing it. */
13629af65ebSAlexey Ozeritsky 	int ok_so_far = 0;
13764d9f161SPatrick Pelletier 
13829af65ebSAlexey Ozeritsky 	X509 *server_cert = NULL;
13929af65ebSAlexey Ozeritsky 
14029af65ebSAlexey Ozeritsky 	if (ignore_cert) {
14129af65ebSAlexey Ozeritsky 		return 1;
14229af65ebSAlexey Ozeritsky 	}
14329af65ebSAlexey Ozeritsky 
14429af65ebSAlexey Ozeritsky 	ok_so_far = X509_verify_cert(x509_ctx);
14529af65ebSAlexey Ozeritsky 
14629af65ebSAlexey Ozeritsky 	server_cert = X509_STORE_CTX_get_current_cert(x509_ctx);
14764d9f161SPatrick Pelletier 
14864d9f161SPatrick Pelletier 	if (ok_so_far) {
14964d9f161SPatrick Pelletier 		res = validate_hostname(host, server_cert);
15064d9f161SPatrick Pelletier 
15164d9f161SPatrick Pelletier 		switch (res) {
15264d9f161SPatrick Pelletier 		case MatchFound:
15364d9f161SPatrick Pelletier 			res_str = "MatchFound";
15464d9f161SPatrick Pelletier 			break;
15564d9f161SPatrick Pelletier 		case MatchNotFound:
15664d9f161SPatrick Pelletier 			res_str = "MatchNotFound";
15764d9f161SPatrick Pelletier 			break;
15864d9f161SPatrick Pelletier 		case NoSANPresent:
15964d9f161SPatrick Pelletier 			res_str = "NoSANPresent";
16064d9f161SPatrick Pelletier 			break;
16164d9f161SPatrick Pelletier 		case MalformedCertificate:
16264d9f161SPatrick Pelletier 			res_str = "MalformedCertificate";
16364d9f161SPatrick Pelletier 			break;
16464d9f161SPatrick Pelletier 		case Error:
16564d9f161SPatrick Pelletier 			res_str = "Error";
16664d9f161SPatrick Pelletier 			break;
16764d9f161SPatrick Pelletier 		default:
16864d9f161SPatrick Pelletier 			res_str = "WTF!";
16964d9f161SPatrick Pelletier 			break;
17064d9f161SPatrick Pelletier 		}
17164d9f161SPatrick Pelletier 	}
17264d9f161SPatrick Pelletier 
17364d9f161SPatrick Pelletier 	X509_NAME_oneline(X509_get_subject_name (server_cert),
17464d9f161SPatrick Pelletier 			  cert_str, sizeof (cert_str));
17564d9f161SPatrick Pelletier 
17664d9f161SPatrick Pelletier 	if (res == MatchFound) {
17764d9f161SPatrick Pelletier 		printf("https server '%s' has this certificate, "
17864d9f161SPatrick Pelletier 		       "which looks good to me:\n%s\n",
17964d9f161SPatrick Pelletier 		       host, cert_str);
18064d9f161SPatrick Pelletier 		return 1;
18164d9f161SPatrick Pelletier 	} else {
18264d9f161SPatrick Pelletier 		printf("Got '%s' for hostname '%s' and certificate:\n%s\n",
18364d9f161SPatrick Pelletier 		       res_str, host, cert_str);
18464d9f161SPatrick Pelletier 		return 0;
18564d9f161SPatrick Pelletier 	}
18664d9f161SPatrick Pelletier }
18764d9f161SPatrick Pelletier 
188be46c99bSCatalin Patulea int
189be46c99bSCatalin Patulea main(int argc, char **argv)
190be46c99bSCatalin Patulea {
191be46c99bSCatalin Patulea 	int r;
192be46c99bSCatalin Patulea 
193be46c99bSCatalin Patulea 	struct evhttp_uri *http_uri;
19490786eb0SNick Mathewson 	const char *url = NULL, *data_file = NULL;
19590786eb0SNick Mathewson 	const char *scheme, *host, *path, *query;
196be46c99bSCatalin Patulea 	char uri[256];
197be46c99bSCatalin Patulea 	int port;
198be46c99bSCatalin Patulea 
199be46c99bSCatalin Patulea 	SSL_CTX *ssl_ctx;
200be46c99bSCatalin Patulea 	SSL *ssl;
201be46c99bSCatalin Patulea 	struct bufferevent *bev;
202be46c99bSCatalin Patulea 	struct evhttp_connection *evcon;
203be46c99bSCatalin Patulea 	struct evhttp_request *req;
2048a90a850SNick Mathewson 	struct evkeyvalq *output_headers;
20529af65ebSAlexey Ozeritsky 	struct evbuffer * output_buffer;
206be46c99bSCatalin Patulea 
207c5887f73SAlexey Ozeritsky 	int i;
208be46c99bSCatalin Patulea 
209c5887f73SAlexey Ozeritsky 	for (i = 1; i < argc; i++) {
210c5887f73SAlexey Ozeritsky 		if (!strcmp("-url", argv[i])) {
211c5887f73SAlexey Ozeritsky 			if (i < argc - 1) {
212c5887f73SAlexey Ozeritsky 				url = argv[i + 1];
213c5887f73SAlexey Ozeritsky 			} else {
214c5887f73SAlexey Ozeritsky 				syntax();
215c5887f73SAlexey Ozeritsky 			}
216c5887f73SAlexey Ozeritsky 		} else if (!strcmp("-ignore-cert", argv[i])) {
217c5887f73SAlexey Ozeritsky 			ignore_cert = 1;
218c5887f73SAlexey Ozeritsky 		} else if (!strcmp("-data", argv[i])) {
219c5887f73SAlexey Ozeritsky 			if (i < argc - 1) {
220c5887f73SAlexey Ozeritsky 				data_file = argv[i + 1];
221c5887f73SAlexey Ozeritsky 			} else {
222c5887f73SAlexey Ozeritsky 				syntax();
223c5887f73SAlexey Ozeritsky 			}
224c5887f73SAlexey Ozeritsky 		} else if (!strcmp("-help", argv[i])) {
225c5887f73SAlexey Ozeritsky 			syntax();
226c5887f73SAlexey Ozeritsky 		}
227c5887f73SAlexey Ozeritsky 	}
228c5887f73SAlexey Ozeritsky 
229c5887f73SAlexey Ozeritsky 	if (!url) {
230c5887f73SAlexey Ozeritsky 		syntax();
231c5887f73SAlexey Ozeritsky 	}
232c5887f73SAlexey Ozeritsky 
2334e143958SJoakim Söderberg #ifdef _WIN32
23419222e52SJoakim Soderberg 	{
23519222e52SJoakim Soderberg 		WORD wVersionRequested;
23619222e52SJoakim Soderberg 		WSADATA wsaData;
23719222e52SJoakim Soderberg 		int err;
23819222e52SJoakim Soderberg 
23919222e52SJoakim Soderberg 		wVersionRequested = MAKEWORD(2, 2);
24019222e52SJoakim Soderberg 
24119222e52SJoakim Soderberg 		err = WSAStartup(wVersionRequested, &wsaData);
24219222e52SJoakim Soderberg 		if (err != 0) {
24319222e52SJoakim Soderberg 			printf("WSAStartup failed with error: %d\n", err);
24419222e52SJoakim Soderberg 			return 1;
24519222e52SJoakim Soderberg 		}
24619222e52SJoakim Soderberg 	}
2474e143958SJoakim Söderberg #endif // _WIN32
24819222e52SJoakim Soderberg 
249be46c99bSCatalin Patulea 	http_uri = evhttp_uri_parse(url);
250be46c99bSCatalin Patulea 	if (http_uri == NULL) {
251be46c99bSCatalin Patulea 		die("malformed url");
252be46c99bSCatalin Patulea 	}
253be46c99bSCatalin Patulea 
254be46c99bSCatalin Patulea 	scheme = evhttp_uri_get_scheme(http_uri);
255be46c99bSCatalin Patulea 	if (scheme == NULL || (strcasecmp(scheme, "https") != 0 &&
256be46c99bSCatalin Patulea 	                       strcasecmp(scheme, "http") != 0)) {
257be46c99bSCatalin Patulea 		die("url must be http or https");
258be46c99bSCatalin Patulea 	}
259be46c99bSCatalin Patulea 
260be46c99bSCatalin Patulea 	host = evhttp_uri_get_host(http_uri);
261be46c99bSCatalin Patulea 	if (host == NULL) {
262be46c99bSCatalin Patulea 		die("url must have a host");
263be46c99bSCatalin Patulea 	}
264be46c99bSCatalin Patulea 
265be46c99bSCatalin Patulea 	port = evhttp_uri_get_port(http_uri);
266be46c99bSCatalin Patulea 	if (port == -1) {
267be46c99bSCatalin Patulea 		port = (strcasecmp(scheme, "http") == 0) ? 80 : 443;
268be46c99bSCatalin Patulea 	}
269be46c99bSCatalin Patulea 
270be46c99bSCatalin Patulea 	path = evhttp_uri_get_path(http_uri);
271be46c99bSCatalin Patulea 	if (path == NULL) {
272be46c99bSCatalin Patulea 		path = "/";
273be46c99bSCatalin Patulea 	}
274be46c99bSCatalin Patulea 
275be46c99bSCatalin Patulea 	query = evhttp_uri_get_query(http_uri);
276be46c99bSCatalin Patulea 	if (query == NULL) {
277be46c99bSCatalin Patulea 		snprintf(uri, sizeof(uri) - 1, "%s", path);
278be46c99bSCatalin Patulea 	} else {
279be46c99bSCatalin Patulea 		snprintf(uri, sizeof(uri) - 1, "%s?%s", path, query);
280be46c99bSCatalin Patulea 	}
281be46c99bSCatalin Patulea 	uri[sizeof(uri) - 1] = '\0';
282be46c99bSCatalin Patulea 
283be46c99bSCatalin Patulea 	// Initialize OpenSSL
284be46c99bSCatalin Patulea 	SSL_library_init();
285be46c99bSCatalin Patulea 	ERR_load_crypto_strings();
286be46c99bSCatalin Patulea 	SSL_load_error_strings();
287be46c99bSCatalin Patulea 	OpenSSL_add_all_algorithms();
2885754d96aSPatrick Pelletier 
2895754d96aSPatrick Pelletier 	/* This isn't strictly necessary... OpenSSL performs RAND_poll
2905754d96aSPatrick Pelletier 	 * automatically on first use of random number generator. */
291be46c99bSCatalin Patulea 	r = RAND_poll();
292be46c99bSCatalin Patulea 	if (r == 0) {
2935754d96aSPatrick Pelletier 		die_openssl("RAND_poll");
294be46c99bSCatalin Patulea 	}
2955754d96aSPatrick Pelletier 
2965754d96aSPatrick Pelletier 	/* Create a new OpenSSL context */
297be46c99bSCatalin Patulea 	ssl_ctx = SSL_CTX_new(SSLv23_method());
2985754d96aSPatrick Pelletier 	if (!ssl_ctx)
2995754d96aSPatrick Pelletier 		die_openssl("SSL_CTX_new");
300be46c99bSCatalin Patulea 
3014e143958SJoakim Söderberg 	#ifndef _WIN32
30219222e52SJoakim Soderberg 	/* TODO: Add certificate loading on Windows as well */
30319222e52SJoakim Soderberg 
304aacd674cSPatrick Pelletier 	/* Attempt to use the system's trusted root certificates.
305aacd674cSPatrick Pelletier 	 * (This path is only valid for Debian-based systems.) */
306aacd674cSPatrick Pelletier 	if (1 != SSL_CTX_load_verify_locations(ssl_ctx,
307aacd674cSPatrick Pelletier 					       "/etc/ssl/certs/ca-certificates.crt",
308aacd674cSPatrick Pelletier 					       NULL))
309aacd674cSPatrick Pelletier 		die_openssl("SSL_CTX_load_verify_locations");
31064d9f161SPatrick Pelletier 	/* Ask OpenSSL to verify the server certificate.  Note that this
31164d9f161SPatrick Pelletier 	 * does NOT include verifying that the hostname is correct.
31264d9f161SPatrick Pelletier 	 * So, by itself, this means anyone with any legitimate
31364d9f161SPatrick Pelletier 	 * CA-issued certificate for any website, can impersonate any
31464d9f161SPatrick Pelletier 	 * other website in the world.  This is not good.  See "The
31564d9f161SPatrick Pelletier 	 * Most Dangerous Code in the World" article at
31664d9f161SPatrick Pelletier 	 * https://crypto.stanford.edu/~dabo/pubs/abstracts/ssl-client-bugs.html
31764d9f161SPatrick Pelletier 	 */
318aacd674cSPatrick Pelletier 	SSL_CTX_set_verify(ssl_ctx, SSL_VERIFY_PEER, NULL);
31964d9f161SPatrick Pelletier 	/* This is how we solve the problem mentioned in the previous
32064d9f161SPatrick Pelletier 	 * comment.  We "wrap" OpenSSL's validation routine in our
32164d9f161SPatrick Pelletier 	 * own routine, which also validates the hostname by calling
32264d9f161SPatrick Pelletier 	 * the code provided by iSECPartners.  Note that even though
32364d9f161SPatrick Pelletier 	 * the "Everything You've Always Wanted to Know About
32464d9f161SPatrick Pelletier 	 * Certificate Validation With OpenSSL (But Were Afraid to
32564d9f161SPatrick Pelletier 	 * Ask)" paper from iSECPartners says very explicitly not to
32664d9f161SPatrick Pelletier 	 * call SSL_CTX_set_cert_verify_callback (at the bottom of
32764d9f161SPatrick Pelletier 	 * page 2), what we're doing here is safe because our
32864d9f161SPatrick Pelletier 	 * cert_verify_callback() calls X509_verify_cert(), which is
32964d9f161SPatrick Pelletier 	 * OpenSSL's built-in routine which would have been called if
33064d9f161SPatrick Pelletier 	 * we hadn't set the callback.  Therefore, we're just
33164d9f161SPatrick Pelletier 	 * "wrapping" OpenSSL's routine, not replacing it. */
33264d9f161SPatrick Pelletier 	SSL_CTX_set_cert_verify_callback (ssl_ctx, cert_verify_callback,
33364d9f161SPatrick Pelletier 					  (void *) host);
3344e143958SJoakim Söderberg 	#endif // not _WIN32
335aacd674cSPatrick Pelletier 
336be46c99bSCatalin Patulea 	// Create event base
337be46c99bSCatalin Patulea 	base = event_base_new();
338be46c99bSCatalin Patulea 	if (!base) {
339be46c99bSCatalin Patulea 		perror("event_base_new()");
340be46c99bSCatalin Patulea 		return 1;
341be46c99bSCatalin Patulea 	}
342be46c99bSCatalin Patulea 
343be46c99bSCatalin Patulea 	// Create OpenSSL bufferevent and stack evhttp on top of it
344be46c99bSCatalin Patulea 	ssl = SSL_new(ssl_ctx);
345be46c99bSCatalin Patulea 	if (ssl == NULL) {
3465754d96aSPatrick Pelletier 		die_openssl("SSL_new()");
347be46c99bSCatalin Patulea 	}
348be46c99bSCatalin Patulea 
349d1976f8eSNick Mathewson 	// Set hostname for SNI extension
350d1976f8eSNick Mathewson 	SSL_set_tlsext_host_name(ssl, host);
351d1976f8eSNick Mathewson 
352be46c99bSCatalin Patulea 	if (strcasecmp(scheme, "http") == 0) {
353be46c99bSCatalin Patulea 		bev = bufferevent_socket_new(base, -1, BEV_OPT_CLOSE_ON_FREE);
354be46c99bSCatalin Patulea 	} else {
355be46c99bSCatalin Patulea 		bev = bufferevent_openssl_socket_new(base, -1, ssl,
356be46c99bSCatalin Patulea 			BUFFEREVENT_SSL_CONNECTING,
357be46c99bSCatalin Patulea 			BEV_OPT_CLOSE_ON_FREE|BEV_OPT_DEFER_CALLBACKS);
358be46c99bSCatalin Patulea 	}
359be46c99bSCatalin Patulea 
360be46c99bSCatalin Patulea 	if (bev == NULL) {
361be46c99bSCatalin Patulea 		fprintf(stderr, "bufferevent_openssl_socket_new() failed\n");
362be46c99bSCatalin Patulea 		return 1;
363be46c99bSCatalin Patulea 	}
364be46c99bSCatalin Patulea 
365be46c99bSCatalin Patulea 	bufferevent_openssl_set_allow_dirty_shutdown(bev, 1);
366be46c99bSCatalin Patulea 
367be46c99bSCatalin Patulea 	// For simplicity, we let DNS resolution block. Everything else should be
368be46c99bSCatalin Patulea 	// asynchronous though.
369be46c99bSCatalin Patulea 	evcon = evhttp_connection_base_bufferevent_new(base, NULL, bev,
370be46c99bSCatalin Patulea 		host, port);
371be46c99bSCatalin Patulea 	if (evcon == NULL) {
372be46c99bSCatalin Patulea 		fprintf(stderr, "evhttp_connection_base_bufferevent_new() failed\n");
373be46c99bSCatalin Patulea 		return 1;
374be46c99bSCatalin Patulea 	}
375be46c99bSCatalin Patulea 
376be46c99bSCatalin Patulea 	// Fire off the request
3775754d96aSPatrick Pelletier 	req = evhttp_request_new(http_request_done, bev);
378be46c99bSCatalin Patulea 	if (req == NULL) {
379be46c99bSCatalin Patulea 		fprintf(stderr, "evhttp_request_new() failed\n");
380be46c99bSCatalin Patulea 		return 1;
381be46c99bSCatalin Patulea 	}
382be46c99bSCatalin Patulea 
3838a90a850SNick Mathewson 	output_headers = evhttp_request_get_output_headers(req);
3848a90a850SNick Mathewson 	evhttp_add_header(output_headers, "Host", host);
3858a90a850SNick Mathewson 	evhttp_add_header(output_headers, "Connection", "close");
386be46c99bSCatalin Patulea 
387c5887f73SAlexey Ozeritsky 	if (data_file) {
38890786eb0SNick Mathewson 		/* NOTE: In production code, you'd probably want to use
38990786eb0SNick Mathewson 		 * evbuffer_add_file() or evbuffer_add_file_segment(), to
39090786eb0SNick Mathewson 		 * avoid needless copying. */
391c5887f73SAlexey Ozeritsky 		FILE * f = fopen(data_file, "rb");
392c5887f73SAlexey Ozeritsky 		char buf[1024];
393d7be7887SJoakim Soderberg 		size_t s;
394c5887f73SAlexey Ozeritsky 		size_t bytes = 0;
395c5887f73SAlexey Ozeritsky 
396c5887f73SAlexey Ozeritsky 		if (!f) {
397c5887f73SAlexey Ozeritsky 			syntax();
398c5887f73SAlexey Ozeritsky 		}
399c5887f73SAlexey Ozeritsky 
40029af65ebSAlexey Ozeritsky 		output_buffer = evhttp_request_get_output_buffer(req);
401c5887f73SAlexey Ozeritsky 		while ((s = fread(buf, 1, sizeof(buf), f)) > 0) {
40229af65ebSAlexey Ozeritsky 			evbuffer_add(output_buffer, buf, s);
403c5887f73SAlexey Ozeritsky 			bytes += s;
404c5887f73SAlexey Ozeritsky 		}
405*462e6b60SNick Mathewson 		evutil_snprintf(buf, sizeof(buf)-1, "%lu", (unsigned long)bytes);
40629af65ebSAlexey Ozeritsky 		evhttp_add_header(output_headers, "Content-Length", buf);
407c5887f73SAlexey Ozeritsky 		fclose(f);
408c5887f73SAlexey Ozeritsky 	}
409c5887f73SAlexey Ozeritsky 
410c5887f73SAlexey Ozeritsky 	r = evhttp_make_request(evcon, req, data_file ? EVHTTP_REQ_POST : EVHTTP_REQ_GET, uri);
411be46c99bSCatalin Patulea 	if (r != 0) {
412be46c99bSCatalin Patulea 		fprintf(stderr, "evhttp_make_request() failed\n");
413be46c99bSCatalin Patulea 		return 1;
414be46c99bSCatalin Patulea 	}
415be46c99bSCatalin Patulea 
416be46c99bSCatalin Patulea 	event_base_dispatch(base);
417be46c99bSCatalin Patulea 
418be46c99bSCatalin Patulea 	evhttp_connection_free(evcon);
419be46c99bSCatalin Patulea 	event_base_free(base);
420be46c99bSCatalin Patulea 
4214e143958SJoakim Söderberg #ifdef _WIN32
42219222e52SJoakim Soderberg 	WSACleanup();
42319222e52SJoakim Soderberg #endif
42419222e52SJoakim Soderberg 
425be46c99bSCatalin Patulea 	return 0;
426be46c99bSCatalin Patulea }
427