xref: /libevent-2.1.12/sample/https-client.c (revision 29af65eb)
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 
13be46c99bSCatalin Patulea #include <stdio.h>
14be46c99bSCatalin Patulea #include <assert.h>
15be46c99bSCatalin Patulea #include <stdlib.h>
16be46c99bSCatalin Patulea #include <string.h>
17be46c99bSCatalin Patulea #include <errno.h>
18be46c99bSCatalin Patulea 
19be46c99bSCatalin Patulea #ifdef WIN32
20be46c99bSCatalin Patulea #include <winsock2.h>
21be46c99bSCatalin Patulea #include <ws2tcpip.h>
22be46c99bSCatalin Patulea #else
23be46c99bSCatalin Patulea #include <sys/socket.h>
24be46c99bSCatalin Patulea #include <netinet/in.h>
25be46c99bSCatalin Patulea #endif
26be46c99bSCatalin Patulea 
27be46c99bSCatalin Patulea #include <event2/bufferevent_ssl.h>
28be46c99bSCatalin Patulea #include <event2/bufferevent.h>
29be46c99bSCatalin Patulea #include <event2/buffer.h>
30be46c99bSCatalin Patulea #include <event2/listener.h>
31be46c99bSCatalin Patulea #include <event2/util.h>
32be46c99bSCatalin Patulea #include <event2/http.h>
33be46c99bSCatalin Patulea 
34be46c99bSCatalin Patulea #include <openssl/ssl.h>
35be46c99bSCatalin Patulea #include <openssl/err.h>
36be46c99bSCatalin Patulea #include <openssl/rand.h>
37be46c99bSCatalin Patulea 
3864d9f161SPatrick Pelletier #include "openssl_hostname_validation.h"
3964d9f161SPatrick Pelletier 
40be46c99bSCatalin Patulea static struct event_base *base;
41c5887f73SAlexey Ozeritsky static int ignore_cert = 0;
42be46c99bSCatalin Patulea 
43be46c99bSCatalin Patulea static void
44be46c99bSCatalin Patulea http_request_done(struct evhttp_request *req, void *ctx)
45be46c99bSCatalin Patulea {
46be46c99bSCatalin Patulea 	char buffer[256];
47be46c99bSCatalin Patulea 	int nread;
48be46c99bSCatalin Patulea 
49be46c99bSCatalin Patulea 	if (req == NULL) {
505754d96aSPatrick Pelletier 		/* If req is NULL, it means an error occurred, but
515754d96aSPatrick Pelletier 		 * sadly we are mostly left guessing what the error
525754d96aSPatrick Pelletier 		 * might have been.  We'll do our best... */
535754d96aSPatrick Pelletier 		struct bufferevent *bev = (struct bufferevent *) ctx;
545754d96aSPatrick Pelletier 		unsigned long oslerr;
555754d96aSPatrick Pelletier 		int printed_err = 0;
565754d96aSPatrick Pelletier 		int errcode = EVUTIL_SOCKET_ERROR();
57be46c99bSCatalin Patulea 		fprintf(stderr, "some request failed - no idea which one though!\n");
585754d96aSPatrick Pelletier 		/* Print out the OpenSSL error queue that libevent
595754d96aSPatrick Pelletier 		 * squirreled away for us, if any. */
605754d96aSPatrick Pelletier 		while ((oslerr = bufferevent_get_openssl_error(bev))) {
615754d96aSPatrick Pelletier 			ERR_error_string_n(oslerr, buffer, sizeof(buffer));
625754d96aSPatrick Pelletier 			fprintf(stderr, "%s\n", buffer);
635754d96aSPatrick Pelletier 			printed_err = 1;
645754d96aSPatrick Pelletier 		}
655754d96aSPatrick Pelletier 		/* If the OpenSSL error queue was empty, maybe it was a
665754d96aSPatrick Pelletier 		 * socket error; let's try printing that. */
675754d96aSPatrick Pelletier 		if (! printed_err)
685754d96aSPatrick Pelletier 			fprintf(stderr, "socket error = %s (%d)\n",
695754d96aSPatrick Pelletier 				evutil_socket_error_to_string(errcode),
705754d96aSPatrick Pelletier 				errcode);
71be46c99bSCatalin Patulea 		return;
72be46c99bSCatalin Patulea 	}
73be46c99bSCatalin Patulea 
74be46c99bSCatalin Patulea 	fprintf(stderr, "Response line: %d %s\n",
758a90a850SNick Mathewson 	    evhttp_request_get_response_code(req),
768a90a850SNick Mathewson 	    evhttp_request_get_response_code_line(req));
77be46c99bSCatalin Patulea 
7895acdaa3SNick Mathewson 	while ((nread = evbuffer_remove(evhttp_request_get_input_buffer(req),
7995acdaa3SNick Mathewson 		    buffer, sizeof(buffer)))
80be46c99bSCatalin Patulea 	       > 0) {
8142d7441aSPatrick Pelletier 		/* These are just arbitrary chunks of 256 bytes.
8242d7441aSPatrick Pelletier 		 * They are not lines, so we can't treat them as such. */
83be46c99bSCatalin Patulea 		fwrite(buffer, nread, 1, stdout);
84be46c99bSCatalin Patulea 	}
85be46c99bSCatalin Patulea }
86be46c99bSCatalin Patulea 
87be46c99bSCatalin Patulea static void
88be46c99bSCatalin Patulea syntax(void)
89be46c99bSCatalin Patulea {
90be46c99bSCatalin Patulea 	fputs("Syntax:\n", stderr);
91c5887f73SAlexey Ozeritsky 	fputs("   https-client -url <https-url> [-data data-file.bin] [-ignore-cert]\n", stderr);
92be46c99bSCatalin Patulea 	fputs("Example:\n", stderr);
93c5887f73SAlexey Ozeritsky 	fputs("   https-client -url https://ip.appspot.com/\n", stderr);
94be46c99bSCatalin Patulea 
95be46c99bSCatalin Patulea 	exit(1);
96be46c99bSCatalin Patulea }
97be46c99bSCatalin Patulea 
98be46c99bSCatalin Patulea static void
99be46c99bSCatalin Patulea die(const char *msg)
100be46c99bSCatalin Patulea {
101be46c99bSCatalin Patulea 	fputs(msg, stderr);
102be46c99bSCatalin Patulea 	exit(1);
103be46c99bSCatalin Patulea }
104be46c99bSCatalin Patulea 
1055754d96aSPatrick Pelletier static void
1065754d96aSPatrick Pelletier die_openssl(const char *func)
1075754d96aSPatrick Pelletier {
1085754d96aSPatrick Pelletier 	fprintf (stderr, "%s failed:\n", func);
1095754d96aSPatrick Pelletier 
1105754d96aSPatrick Pelletier 	/* This is the OpenSSL function that prints the contents of the
1115754d96aSPatrick Pelletier 	 * error stack to the specified file handle. */
1125754d96aSPatrick Pelletier 	ERR_print_errors_fp (stderr);
1135754d96aSPatrick Pelletier 
1145754d96aSPatrick Pelletier 	exit(1);
1155754d96aSPatrick Pelletier }
1165754d96aSPatrick Pelletier 
11764d9f161SPatrick Pelletier /* See http://archives.seul.org/libevent/users/Jan-2013/msg00039.html */
11864d9f161SPatrick Pelletier static int cert_verify_callback(X509_STORE_CTX *x509_ctx, void *arg)
11964d9f161SPatrick Pelletier {
12064d9f161SPatrick Pelletier 	char cert_str[256];
12164d9f161SPatrick Pelletier 	const char *host = (const char *) arg;
12264d9f161SPatrick Pelletier 	const char *res_str = "X509_verify_cert failed";
12364d9f161SPatrick Pelletier 	HostnameValidationResult res = Error;
12464d9f161SPatrick Pelletier 
12564d9f161SPatrick Pelletier 	/* This is the function that OpenSSL would call if we hadn't called
12664d9f161SPatrick Pelletier 	 * SSL_CTX_set_cert_verify_callback().  Therefore, we are "wrapping"
12764d9f161SPatrick Pelletier 	 * the default functionality, rather than replacing it. */
128*29af65ebSAlexey Ozeritsky 	int ok_so_far = 0;
12964d9f161SPatrick Pelletier 
130*29af65ebSAlexey Ozeritsky 	X509 *server_cert = NULL;
131*29af65ebSAlexey Ozeritsky 
132*29af65ebSAlexey Ozeritsky 	if (ignore_cert) {
133*29af65ebSAlexey Ozeritsky 		return 1;
134*29af65ebSAlexey Ozeritsky 	}
135*29af65ebSAlexey Ozeritsky 
136*29af65ebSAlexey Ozeritsky 	ok_so_far = X509_verify_cert(x509_ctx);
137*29af65ebSAlexey Ozeritsky 
138*29af65ebSAlexey Ozeritsky 	server_cert = X509_STORE_CTX_get_current_cert(x509_ctx);
13964d9f161SPatrick Pelletier 
14064d9f161SPatrick Pelletier 	if (ok_so_far) {
14164d9f161SPatrick Pelletier 		res = validate_hostname(host, server_cert);
14264d9f161SPatrick Pelletier 
14364d9f161SPatrick Pelletier 		switch (res) {
14464d9f161SPatrick Pelletier 		case MatchFound:
14564d9f161SPatrick Pelletier 			res_str = "MatchFound";
14664d9f161SPatrick Pelletier 			break;
14764d9f161SPatrick Pelletier 		case MatchNotFound:
14864d9f161SPatrick Pelletier 			res_str = "MatchNotFound";
14964d9f161SPatrick Pelletier 			break;
15064d9f161SPatrick Pelletier 		case NoSANPresent:
15164d9f161SPatrick Pelletier 			res_str = "NoSANPresent";
15264d9f161SPatrick Pelletier 			break;
15364d9f161SPatrick Pelletier 		case MalformedCertificate:
15464d9f161SPatrick Pelletier 			res_str = "MalformedCertificate";
15564d9f161SPatrick Pelletier 			break;
15664d9f161SPatrick Pelletier 		case Error:
15764d9f161SPatrick Pelletier 			res_str = "Error";
15864d9f161SPatrick Pelletier 			break;
15964d9f161SPatrick Pelletier 		default:
16064d9f161SPatrick Pelletier 			res_str = "WTF!";
16164d9f161SPatrick Pelletier 			break;
16264d9f161SPatrick Pelletier 		}
16364d9f161SPatrick Pelletier 	}
16464d9f161SPatrick Pelletier 
16564d9f161SPatrick Pelletier 	X509_NAME_oneline(X509_get_subject_name (server_cert),
16664d9f161SPatrick Pelletier 			  cert_str, sizeof (cert_str));
16764d9f161SPatrick Pelletier 
16864d9f161SPatrick Pelletier 	if (res == MatchFound) {
16964d9f161SPatrick Pelletier 		printf("https server '%s' has this certificate, "
17064d9f161SPatrick Pelletier 		       "which looks good to me:\n%s\n",
17164d9f161SPatrick Pelletier 		       host, cert_str);
17264d9f161SPatrick Pelletier 		return 1;
17364d9f161SPatrick Pelletier 	} else {
17464d9f161SPatrick Pelletier 		printf("Got '%s' for hostname '%s' and certificate:\n%s\n",
17564d9f161SPatrick Pelletier 		       res_str, host, cert_str);
17664d9f161SPatrick Pelletier 		return 0;
17764d9f161SPatrick Pelletier 	}
17864d9f161SPatrick Pelletier }
17964d9f161SPatrick Pelletier 
180be46c99bSCatalin Patulea int
181be46c99bSCatalin Patulea main(int argc, char **argv)
182be46c99bSCatalin Patulea {
183be46c99bSCatalin Patulea 	int r;
184be46c99bSCatalin Patulea 
185be46c99bSCatalin Patulea 	struct evhttp_uri *http_uri;
186c5887f73SAlexey Ozeritsky 	const char *url = 0, *scheme, *host, *path, *query, *data_file = 0;
187be46c99bSCatalin Patulea 	char uri[256];
188be46c99bSCatalin Patulea 	int port;
189be46c99bSCatalin Patulea 
190be46c99bSCatalin Patulea 	SSL_CTX *ssl_ctx;
191be46c99bSCatalin Patulea 	SSL *ssl;
192be46c99bSCatalin Patulea 	struct bufferevent *bev;
193be46c99bSCatalin Patulea 	struct evhttp_connection *evcon;
194be46c99bSCatalin Patulea 	struct evhttp_request *req;
1958a90a850SNick Mathewson 	struct evkeyvalq *output_headers;
196*29af65ebSAlexey Ozeritsky 	struct evbuffer * output_buffer;
197be46c99bSCatalin Patulea 
198c5887f73SAlexey Ozeritsky 	int i;
199be46c99bSCatalin Patulea 
200c5887f73SAlexey Ozeritsky 	for (i = 1; i < argc; i++) {
201c5887f73SAlexey Ozeritsky 		if (!strcmp("-url", argv[i])) {
202c5887f73SAlexey Ozeritsky 			if (i < argc - 1) {
203c5887f73SAlexey Ozeritsky 				url = argv[i + 1];
204c5887f73SAlexey Ozeritsky 			} else {
205c5887f73SAlexey Ozeritsky 				syntax();
206c5887f73SAlexey Ozeritsky 			}
207c5887f73SAlexey Ozeritsky 		} else if (!strcmp("-ignore-cert", argv[i])) {
208c5887f73SAlexey Ozeritsky 			ignore_cert = 1;
209c5887f73SAlexey Ozeritsky 		} else if (!strcmp("-data", argv[i])) {
210c5887f73SAlexey Ozeritsky 			if (i < argc - 1) {
211c5887f73SAlexey Ozeritsky 				data_file = argv[i + 1];
212c5887f73SAlexey Ozeritsky 			} else {
213c5887f73SAlexey Ozeritsky 				syntax();
214c5887f73SAlexey Ozeritsky 			}
215c5887f73SAlexey Ozeritsky 		} else if (!strcmp("-help", argv[i])) {
216c5887f73SAlexey Ozeritsky 			syntax();
217c5887f73SAlexey Ozeritsky 		}
218c5887f73SAlexey Ozeritsky 	}
219c5887f73SAlexey Ozeritsky 
220c5887f73SAlexey Ozeritsky 	if (!url) {
221c5887f73SAlexey Ozeritsky 		syntax();
222c5887f73SAlexey Ozeritsky 	}
223c5887f73SAlexey Ozeritsky 
224be46c99bSCatalin Patulea 	http_uri = evhttp_uri_parse(url);
225be46c99bSCatalin Patulea 	if (http_uri == NULL) {
226be46c99bSCatalin Patulea 		die("malformed url");
227be46c99bSCatalin Patulea 	}
228be46c99bSCatalin Patulea 
229be46c99bSCatalin Patulea 	scheme = evhttp_uri_get_scheme(http_uri);
230be46c99bSCatalin Patulea 	if (scheme == NULL || (strcasecmp(scheme, "https") != 0 &&
231be46c99bSCatalin Patulea 	                       strcasecmp(scheme, "http") != 0)) {
232be46c99bSCatalin Patulea 		die("url must be http or https");
233be46c99bSCatalin Patulea 	}
234be46c99bSCatalin Patulea 
235be46c99bSCatalin Patulea 	host = evhttp_uri_get_host(http_uri);
236be46c99bSCatalin Patulea 	if (host == NULL) {
237be46c99bSCatalin Patulea 		die("url must have a host");
238be46c99bSCatalin Patulea 	}
239be46c99bSCatalin Patulea 
240be46c99bSCatalin Patulea 	port = evhttp_uri_get_port(http_uri);
241be46c99bSCatalin Patulea 	if (port == -1) {
242be46c99bSCatalin Patulea 		port = (strcasecmp(scheme, "http") == 0) ? 80 : 443;
243be46c99bSCatalin Patulea 	}
244be46c99bSCatalin Patulea 
245be46c99bSCatalin Patulea 	path = evhttp_uri_get_path(http_uri);
246be46c99bSCatalin Patulea 	if (path == NULL) {
247be46c99bSCatalin Patulea 		path = "/";
248be46c99bSCatalin Patulea 	}
249be46c99bSCatalin Patulea 
250be46c99bSCatalin Patulea 	query = evhttp_uri_get_query(http_uri);
251be46c99bSCatalin Patulea 	if (query == NULL) {
252be46c99bSCatalin Patulea 		snprintf(uri, sizeof(uri) - 1, "%s", path);
253be46c99bSCatalin Patulea 	} else {
254be46c99bSCatalin Patulea 		snprintf(uri, sizeof(uri) - 1, "%s?%s", path, query);
255be46c99bSCatalin Patulea 	}
256be46c99bSCatalin Patulea 	uri[sizeof(uri) - 1] = '\0';
257be46c99bSCatalin Patulea 
258be46c99bSCatalin Patulea 	// Initialize OpenSSL
259be46c99bSCatalin Patulea 	SSL_library_init();
260be46c99bSCatalin Patulea 	ERR_load_crypto_strings();
261be46c99bSCatalin Patulea 	SSL_load_error_strings();
262be46c99bSCatalin Patulea 	OpenSSL_add_all_algorithms();
2635754d96aSPatrick Pelletier 
2645754d96aSPatrick Pelletier 	/* This isn't strictly necessary... OpenSSL performs RAND_poll
2655754d96aSPatrick Pelletier 	 * automatically on first use of random number generator. */
266be46c99bSCatalin Patulea 	r = RAND_poll();
267be46c99bSCatalin Patulea 	if (r == 0) {
2685754d96aSPatrick Pelletier 		die_openssl("RAND_poll");
269be46c99bSCatalin Patulea 	}
2705754d96aSPatrick Pelletier 
2715754d96aSPatrick Pelletier 	/* Create a new OpenSSL context */
272be46c99bSCatalin Patulea 	ssl_ctx = SSL_CTX_new(SSLv23_method());
2735754d96aSPatrick Pelletier 	if (!ssl_ctx)
2745754d96aSPatrick Pelletier 		die_openssl("SSL_CTX_new");
275be46c99bSCatalin Patulea 
276aacd674cSPatrick Pelletier 	/* Attempt to use the system's trusted root certificates.
277aacd674cSPatrick Pelletier 	 * (This path is only valid for Debian-based systems.) */
278aacd674cSPatrick Pelletier 	if (1 != SSL_CTX_load_verify_locations(ssl_ctx,
279aacd674cSPatrick Pelletier 					       "/etc/ssl/certs/ca-certificates.crt",
280aacd674cSPatrick Pelletier 					       NULL))
281aacd674cSPatrick Pelletier 		die_openssl("SSL_CTX_load_verify_locations");
28264d9f161SPatrick Pelletier 	/* Ask OpenSSL to verify the server certificate.  Note that this
28364d9f161SPatrick Pelletier 	 * does NOT include verifying that the hostname is correct.
28464d9f161SPatrick Pelletier 	 * So, by itself, this means anyone with any legitimate
28564d9f161SPatrick Pelletier 	 * CA-issued certificate for any website, can impersonate any
28664d9f161SPatrick Pelletier 	 * other website in the world.  This is not good.  See "The
28764d9f161SPatrick Pelletier 	 * Most Dangerous Code in the World" article at
28864d9f161SPatrick Pelletier 	 * https://crypto.stanford.edu/~dabo/pubs/abstracts/ssl-client-bugs.html
28964d9f161SPatrick Pelletier 	 */
290aacd674cSPatrick Pelletier 	SSL_CTX_set_verify(ssl_ctx, SSL_VERIFY_PEER, NULL);
29164d9f161SPatrick Pelletier 	/* This is how we solve the problem mentioned in the previous
29264d9f161SPatrick Pelletier 	 * comment.  We "wrap" OpenSSL's validation routine in our
29364d9f161SPatrick Pelletier 	 * own routine, which also validates the hostname by calling
29464d9f161SPatrick Pelletier 	 * the code provided by iSECPartners.  Note that even though
29564d9f161SPatrick Pelletier 	 * the "Everything You've Always Wanted to Know About
29664d9f161SPatrick Pelletier 	 * Certificate Validation With OpenSSL (But Were Afraid to
29764d9f161SPatrick Pelletier 	 * Ask)" paper from iSECPartners says very explicitly not to
29864d9f161SPatrick Pelletier 	 * call SSL_CTX_set_cert_verify_callback (at the bottom of
29964d9f161SPatrick Pelletier 	 * page 2), what we're doing here is safe because our
30064d9f161SPatrick Pelletier 	 * cert_verify_callback() calls X509_verify_cert(), which is
30164d9f161SPatrick Pelletier 	 * OpenSSL's built-in routine which would have been called if
30264d9f161SPatrick Pelletier 	 * we hadn't set the callback.  Therefore, we're just
30364d9f161SPatrick Pelletier 	 * "wrapping" OpenSSL's routine, not replacing it. */
30464d9f161SPatrick Pelletier 	SSL_CTX_set_cert_verify_callback (ssl_ctx, cert_verify_callback,
30564d9f161SPatrick Pelletier 					  (void *) host);
306aacd674cSPatrick Pelletier 
307be46c99bSCatalin Patulea 	// Create event base
308be46c99bSCatalin Patulea 	base = event_base_new();
309be46c99bSCatalin Patulea 	if (!base) {
310be46c99bSCatalin Patulea 		perror("event_base_new()");
311be46c99bSCatalin Patulea 		return 1;
312be46c99bSCatalin Patulea 	}
313be46c99bSCatalin Patulea 
314be46c99bSCatalin Patulea 	// Create OpenSSL bufferevent and stack evhttp on top of it
315be46c99bSCatalin Patulea 	ssl = SSL_new(ssl_ctx);
316be46c99bSCatalin Patulea 	if (ssl == NULL) {
3175754d96aSPatrick Pelletier 		die_openssl("SSL_new()");
318be46c99bSCatalin Patulea 	}
319be46c99bSCatalin Patulea 
320be46c99bSCatalin Patulea 	if (strcasecmp(scheme, "http") == 0) {
321be46c99bSCatalin Patulea 		bev = bufferevent_socket_new(base, -1, BEV_OPT_CLOSE_ON_FREE);
322be46c99bSCatalin Patulea 	} else {
323be46c99bSCatalin Patulea 		bev = bufferevent_openssl_socket_new(base, -1, ssl,
324be46c99bSCatalin Patulea 			BUFFEREVENT_SSL_CONNECTING,
325be46c99bSCatalin Patulea 			BEV_OPT_CLOSE_ON_FREE|BEV_OPT_DEFER_CALLBACKS);
326be46c99bSCatalin Patulea 	}
327be46c99bSCatalin Patulea 
328be46c99bSCatalin Patulea 	if (bev == NULL) {
329be46c99bSCatalin Patulea 		fprintf(stderr, "bufferevent_openssl_socket_new() failed\n");
330be46c99bSCatalin Patulea 		return 1;
331be46c99bSCatalin Patulea 	}
332be46c99bSCatalin Patulea 
333be46c99bSCatalin Patulea 	bufferevent_openssl_set_allow_dirty_shutdown(bev, 1);
334be46c99bSCatalin Patulea 
335be46c99bSCatalin Patulea 	// For simplicity, we let DNS resolution block. Everything else should be
336be46c99bSCatalin Patulea 	// asynchronous though.
337be46c99bSCatalin Patulea 	evcon = evhttp_connection_base_bufferevent_new(base, NULL, bev,
338be46c99bSCatalin Patulea 		host, port);
339be46c99bSCatalin Patulea 	if (evcon == NULL) {
340be46c99bSCatalin Patulea 		fprintf(stderr, "evhttp_connection_base_bufferevent_new() failed\n");
341be46c99bSCatalin Patulea 		return 1;
342be46c99bSCatalin Patulea 	}
343be46c99bSCatalin Patulea 
344be46c99bSCatalin Patulea 	// Fire off the request
3455754d96aSPatrick Pelletier 	req = evhttp_request_new(http_request_done, bev);
346be46c99bSCatalin Patulea 	if (req == NULL) {
347be46c99bSCatalin Patulea 		fprintf(stderr, "evhttp_request_new() failed\n");
348be46c99bSCatalin Patulea 		return 1;
349be46c99bSCatalin Patulea 	}
350be46c99bSCatalin Patulea 
3518a90a850SNick Mathewson 	output_headers = evhttp_request_get_output_headers(req);
3528a90a850SNick Mathewson 	evhttp_add_header(output_headers, "Host", host);
3538a90a850SNick Mathewson 	evhttp_add_header(output_headers, "Connection", "close");
354be46c99bSCatalin Patulea 
355c5887f73SAlexey Ozeritsky 	if (data_file) {
356c5887f73SAlexey Ozeritsky 		FILE * f = fopen(data_file, "rb");
357c5887f73SAlexey Ozeritsky 		char buf[1024];
358c5887f73SAlexey Ozeritsky 		ssize_t s;
359c5887f73SAlexey Ozeritsky 		size_t bytes = 0;
360c5887f73SAlexey Ozeritsky 
361c5887f73SAlexey Ozeritsky 		if (!f) {
362c5887f73SAlexey Ozeritsky 			syntax();
363c5887f73SAlexey Ozeritsky 		}
364c5887f73SAlexey Ozeritsky 
365*29af65ebSAlexey Ozeritsky 		output_buffer = evhttp_request_get_output_buffer(req);
366c5887f73SAlexey Ozeritsky 		while ((s = fread(buf, 1, sizeof(buf), f)) > 0) {
367*29af65ebSAlexey Ozeritsky 			evbuffer_add(output_buffer, buf, s);
368c5887f73SAlexey Ozeritsky 			bytes += s;
369c5887f73SAlexey Ozeritsky 		}
370*29af65ebSAlexey Ozeritsky 		evutil_snprintf(buf, sizeof(buf)-1, "%lu", bytes);
371*29af65ebSAlexey Ozeritsky 		evhttp_add_header(output_headers, "Content-Length", buf);
372c5887f73SAlexey Ozeritsky 		fclose(f);
373c5887f73SAlexey Ozeritsky 	}
374c5887f73SAlexey Ozeritsky 
375c5887f73SAlexey Ozeritsky 	r = evhttp_make_request(evcon, req, data_file ? EVHTTP_REQ_POST : EVHTTP_REQ_GET, uri);
376be46c99bSCatalin Patulea 	if (r != 0) {
377be46c99bSCatalin Patulea 		fprintf(stderr, "evhttp_make_request() failed\n");
378be46c99bSCatalin Patulea 		return 1;
379be46c99bSCatalin Patulea 	}
380be46c99bSCatalin Patulea 
381be46c99bSCatalin Patulea 	event_base_dispatch(base);
382be46c99bSCatalin Patulea 
383be46c99bSCatalin Patulea 	evhttp_connection_free(evcon);
384be46c99bSCatalin Patulea 	event_base_free(base);
385be46c99bSCatalin Patulea 
386be46c99bSCatalin Patulea 	return 0;
387be46c99bSCatalin Patulea }
388