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); 99*d9da8443SAzat Khuzhin fputs(" https-client -url <https-url> [-data data-file.bin] [-ignore-cert] [-retries num]\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; 198*d9da8443SAzat Khuzhin int retries = 0; 199be46c99bSCatalin Patulea 200be46c99bSCatalin Patulea SSL_CTX *ssl_ctx; 201be46c99bSCatalin Patulea SSL *ssl; 202be46c99bSCatalin Patulea struct bufferevent *bev; 203be46c99bSCatalin Patulea struct evhttp_connection *evcon; 204be46c99bSCatalin Patulea struct evhttp_request *req; 2058a90a850SNick Mathewson struct evkeyvalq *output_headers; 20629af65ebSAlexey Ozeritsky struct evbuffer * output_buffer; 207be46c99bSCatalin Patulea 208c5887f73SAlexey Ozeritsky int i; 209be46c99bSCatalin Patulea 210c5887f73SAlexey Ozeritsky for (i = 1; i < argc; i++) { 211c5887f73SAlexey Ozeritsky if (!strcmp("-url", argv[i])) { 212c5887f73SAlexey Ozeritsky if (i < argc - 1) { 213c5887f73SAlexey Ozeritsky url = argv[i + 1]; 214c5887f73SAlexey Ozeritsky } else { 215c5887f73SAlexey Ozeritsky syntax(); 216c5887f73SAlexey Ozeritsky } 217c5887f73SAlexey Ozeritsky } else if (!strcmp("-ignore-cert", argv[i])) { 218c5887f73SAlexey Ozeritsky ignore_cert = 1; 219c5887f73SAlexey Ozeritsky } else if (!strcmp("-data", argv[i])) { 220c5887f73SAlexey Ozeritsky if (i < argc - 1) { 221c5887f73SAlexey Ozeritsky data_file = argv[i + 1]; 222c5887f73SAlexey Ozeritsky } else { 223c5887f73SAlexey Ozeritsky syntax(); 224c5887f73SAlexey Ozeritsky } 225*d9da8443SAzat Khuzhin } else if (!strcmp("-retries", argv[i])) { 226*d9da8443SAzat Khuzhin if (i < argc - 1) { 227*d9da8443SAzat Khuzhin retries = atoi(argv[i + 1]); 228*d9da8443SAzat Khuzhin } else { 229*d9da8443SAzat Khuzhin syntax(); 230*d9da8443SAzat Khuzhin } 231c5887f73SAlexey Ozeritsky } else if (!strcmp("-help", argv[i])) { 232c5887f73SAlexey Ozeritsky syntax(); 233c5887f73SAlexey Ozeritsky } 234c5887f73SAlexey Ozeritsky } 235c5887f73SAlexey Ozeritsky 236c5887f73SAlexey Ozeritsky if (!url) { 237c5887f73SAlexey Ozeritsky syntax(); 238c5887f73SAlexey Ozeritsky } 239c5887f73SAlexey Ozeritsky 2404e143958SJoakim Söderberg #ifdef _WIN32 24119222e52SJoakim Soderberg { 24219222e52SJoakim Soderberg WORD wVersionRequested; 24319222e52SJoakim Soderberg WSADATA wsaData; 24419222e52SJoakim Soderberg int err; 24519222e52SJoakim Soderberg 24619222e52SJoakim Soderberg wVersionRequested = MAKEWORD(2, 2); 24719222e52SJoakim Soderberg 24819222e52SJoakim Soderberg err = WSAStartup(wVersionRequested, &wsaData); 24919222e52SJoakim Soderberg if (err != 0) { 25019222e52SJoakim Soderberg printf("WSAStartup failed with error: %d\n", err); 25119222e52SJoakim Soderberg return 1; 25219222e52SJoakim Soderberg } 25319222e52SJoakim Soderberg } 2544e143958SJoakim Söderberg #endif // _WIN32 25519222e52SJoakim Soderberg 256be46c99bSCatalin Patulea http_uri = evhttp_uri_parse(url); 257be46c99bSCatalin Patulea if (http_uri == NULL) { 258be46c99bSCatalin Patulea die("malformed url"); 259be46c99bSCatalin Patulea } 260be46c99bSCatalin Patulea 261be46c99bSCatalin Patulea scheme = evhttp_uri_get_scheme(http_uri); 262be46c99bSCatalin Patulea if (scheme == NULL || (strcasecmp(scheme, "https") != 0 && 263be46c99bSCatalin Patulea strcasecmp(scheme, "http") != 0)) { 264be46c99bSCatalin Patulea die("url must be http or https"); 265be46c99bSCatalin Patulea } 266be46c99bSCatalin Patulea 267be46c99bSCatalin Patulea host = evhttp_uri_get_host(http_uri); 268be46c99bSCatalin Patulea if (host == NULL) { 269be46c99bSCatalin Patulea die("url must have a host"); 270be46c99bSCatalin Patulea } 271be46c99bSCatalin Patulea 272be46c99bSCatalin Patulea port = evhttp_uri_get_port(http_uri); 273be46c99bSCatalin Patulea if (port == -1) { 274be46c99bSCatalin Patulea port = (strcasecmp(scheme, "http") == 0) ? 80 : 443; 275be46c99bSCatalin Patulea } 276be46c99bSCatalin Patulea 277be46c99bSCatalin Patulea path = evhttp_uri_get_path(http_uri); 278be46c99bSCatalin Patulea if (path == NULL) { 279be46c99bSCatalin Patulea path = "/"; 280be46c99bSCatalin Patulea } 281be46c99bSCatalin Patulea 282be46c99bSCatalin Patulea query = evhttp_uri_get_query(http_uri); 283be46c99bSCatalin Patulea if (query == NULL) { 284be46c99bSCatalin Patulea snprintf(uri, sizeof(uri) - 1, "%s", path); 285be46c99bSCatalin Patulea } else { 286be46c99bSCatalin Patulea snprintf(uri, sizeof(uri) - 1, "%s?%s", path, query); 287be46c99bSCatalin Patulea } 288be46c99bSCatalin Patulea uri[sizeof(uri) - 1] = '\0'; 289be46c99bSCatalin Patulea 290be46c99bSCatalin Patulea // Initialize OpenSSL 291be46c99bSCatalin Patulea SSL_library_init(); 292be46c99bSCatalin Patulea ERR_load_crypto_strings(); 293be46c99bSCatalin Patulea SSL_load_error_strings(); 294be46c99bSCatalin Patulea OpenSSL_add_all_algorithms(); 2955754d96aSPatrick Pelletier 2965754d96aSPatrick Pelletier /* This isn't strictly necessary... OpenSSL performs RAND_poll 2975754d96aSPatrick Pelletier * automatically on first use of random number generator. */ 298be46c99bSCatalin Patulea r = RAND_poll(); 299be46c99bSCatalin Patulea if (r == 0) { 3005754d96aSPatrick Pelletier die_openssl("RAND_poll"); 301be46c99bSCatalin Patulea } 3025754d96aSPatrick Pelletier 3035754d96aSPatrick Pelletier /* Create a new OpenSSL context */ 304be46c99bSCatalin Patulea ssl_ctx = SSL_CTX_new(SSLv23_method()); 3055754d96aSPatrick Pelletier if (!ssl_ctx) 3065754d96aSPatrick Pelletier die_openssl("SSL_CTX_new"); 307be46c99bSCatalin Patulea 3084e143958SJoakim Söderberg #ifndef _WIN32 30919222e52SJoakim Soderberg /* TODO: Add certificate loading on Windows as well */ 31019222e52SJoakim Soderberg 311aacd674cSPatrick Pelletier /* Attempt to use the system's trusted root certificates. 312aacd674cSPatrick Pelletier * (This path is only valid for Debian-based systems.) */ 313aacd674cSPatrick Pelletier if (1 != SSL_CTX_load_verify_locations(ssl_ctx, 314aacd674cSPatrick Pelletier "/etc/ssl/certs/ca-certificates.crt", 315aacd674cSPatrick Pelletier NULL)) 316aacd674cSPatrick Pelletier die_openssl("SSL_CTX_load_verify_locations"); 31764d9f161SPatrick Pelletier /* Ask OpenSSL to verify the server certificate. Note that this 31864d9f161SPatrick Pelletier * does NOT include verifying that the hostname is correct. 31964d9f161SPatrick Pelletier * So, by itself, this means anyone with any legitimate 32064d9f161SPatrick Pelletier * CA-issued certificate for any website, can impersonate any 32164d9f161SPatrick Pelletier * other website in the world. This is not good. See "The 32264d9f161SPatrick Pelletier * Most Dangerous Code in the World" article at 32364d9f161SPatrick Pelletier * https://crypto.stanford.edu/~dabo/pubs/abstracts/ssl-client-bugs.html 32464d9f161SPatrick Pelletier */ 325aacd674cSPatrick Pelletier SSL_CTX_set_verify(ssl_ctx, SSL_VERIFY_PEER, NULL); 32664d9f161SPatrick Pelletier /* This is how we solve the problem mentioned in the previous 32764d9f161SPatrick Pelletier * comment. We "wrap" OpenSSL's validation routine in our 32864d9f161SPatrick Pelletier * own routine, which also validates the hostname by calling 32964d9f161SPatrick Pelletier * the code provided by iSECPartners. Note that even though 33064d9f161SPatrick Pelletier * the "Everything You've Always Wanted to Know About 33164d9f161SPatrick Pelletier * Certificate Validation With OpenSSL (But Were Afraid to 33264d9f161SPatrick Pelletier * Ask)" paper from iSECPartners says very explicitly not to 33364d9f161SPatrick Pelletier * call SSL_CTX_set_cert_verify_callback (at the bottom of 33464d9f161SPatrick Pelletier * page 2), what we're doing here is safe because our 33564d9f161SPatrick Pelletier * cert_verify_callback() calls X509_verify_cert(), which is 33664d9f161SPatrick Pelletier * OpenSSL's built-in routine which would have been called if 33764d9f161SPatrick Pelletier * we hadn't set the callback. Therefore, we're just 33864d9f161SPatrick Pelletier * "wrapping" OpenSSL's routine, not replacing it. */ 33964d9f161SPatrick Pelletier SSL_CTX_set_cert_verify_callback (ssl_ctx, cert_verify_callback, 34064d9f161SPatrick Pelletier (void *) host); 3414e143958SJoakim Söderberg #endif // not _WIN32 342aacd674cSPatrick Pelletier 343be46c99bSCatalin Patulea // Create event base 344be46c99bSCatalin Patulea base = event_base_new(); 345be46c99bSCatalin Patulea if (!base) { 346be46c99bSCatalin Patulea perror("event_base_new()"); 347be46c99bSCatalin Patulea return 1; 348be46c99bSCatalin Patulea } 349be46c99bSCatalin Patulea 350be46c99bSCatalin Patulea // Create OpenSSL bufferevent and stack evhttp on top of it 351be46c99bSCatalin Patulea ssl = SSL_new(ssl_ctx); 352be46c99bSCatalin Patulea if (ssl == NULL) { 3535754d96aSPatrick Pelletier die_openssl("SSL_new()"); 354be46c99bSCatalin Patulea } 355be46c99bSCatalin Patulea 356d1976f8eSNick Mathewson // Set hostname for SNI extension 357d1976f8eSNick Mathewson SSL_set_tlsext_host_name(ssl, host); 358d1976f8eSNick Mathewson 359be46c99bSCatalin Patulea if (strcasecmp(scheme, "http") == 0) { 360be46c99bSCatalin Patulea bev = bufferevent_socket_new(base, -1, BEV_OPT_CLOSE_ON_FREE); 361be46c99bSCatalin Patulea } else { 362be46c99bSCatalin Patulea bev = bufferevent_openssl_socket_new(base, -1, ssl, 363be46c99bSCatalin Patulea BUFFEREVENT_SSL_CONNECTING, 364be46c99bSCatalin Patulea BEV_OPT_CLOSE_ON_FREE|BEV_OPT_DEFER_CALLBACKS); 365be46c99bSCatalin Patulea } 366be46c99bSCatalin Patulea 367be46c99bSCatalin Patulea if (bev == NULL) { 368be46c99bSCatalin Patulea fprintf(stderr, "bufferevent_openssl_socket_new() failed\n"); 369be46c99bSCatalin Patulea return 1; 370be46c99bSCatalin Patulea } 371be46c99bSCatalin Patulea 372be46c99bSCatalin Patulea bufferevent_openssl_set_allow_dirty_shutdown(bev, 1); 373be46c99bSCatalin Patulea 374be46c99bSCatalin Patulea // For simplicity, we let DNS resolution block. Everything else should be 375be46c99bSCatalin Patulea // asynchronous though. 376be46c99bSCatalin Patulea evcon = evhttp_connection_base_bufferevent_new(base, NULL, bev, 377be46c99bSCatalin Patulea host, port); 378be46c99bSCatalin Patulea if (evcon == NULL) { 379be46c99bSCatalin Patulea fprintf(stderr, "evhttp_connection_base_bufferevent_new() failed\n"); 380be46c99bSCatalin Patulea return 1; 381be46c99bSCatalin Patulea } 382be46c99bSCatalin Patulea 383*d9da8443SAzat Khuzhin if (retries > 0) { 384*d9da8443SAzat Khuzhin evhttp_connection_set_retries(evcon, retries); 385*d9da8443SAzat Khuzhin } 386*d9da8443SAzat Khuzhin 387be46c99bSCatalin Patulea // Fire off the request 3885754d96aSPatrick Pelletier req = evhttp_request_new(http_request_done, bev); 389be46c99bSCatalin Patulea if (req == NULL) { 390be46c99bSCatalin Patulea fprintf(stderr, "evhttp_request_new() failed\n"); 391be46c99bSCatalin Patulea return 1; 392be46c99bSCatalin Patulea } 393be46c99bSCatalin Patulea 3948a90a850SNick Mathewson output_headers = evhttp_request_get_output_headers(req); 3958a90a850SNick Mathewson evhttp_add_header(output_headers, "Host", host); 3968a90a850SNick Mathewson evhttp_add_header(output_headers, "Connection", "close"); 397be46c99bSCatalin Patulea 398c5887f73SAlexey Ozeritsky if (data_file) { 39990786eb0SNick Mathewson /* NOTE: In production code, you'd probably want to use 40090786eb0SNick Mathewson * evbuffer_add_file() or evbuffer_add_file_segment(), to 40190786eb0SNick Mathewson * avoid needless copying. */ 402c5887f73SAlexey Ozeritsky FILE * f = fopen(data_file, "rb"); 403c5887f73SAlexey Ozeritsky char buf[1024]; 404d7be7887SJoakim Soderberg size_t s; 405c5887f73SAlexey Ozeritsky size_t bytes = 0; 406c5887f73SAlexey Ozeritsky 407c5887f73SAlexey Ozeritsky if (!f) { 408c5887f73SAlexey Ozeritsky syntax(); 409c5887f73SAlexey Ozeritsky } 410c5887f73SAlexey Ozeritsky 41129af65ebSAlexey Ozeritsky output_buffer = evhttp_request_get_output_buffer(req); 412c5887f73SAlexey Ozeritsky while ((s = fread(buf, 1, sizeof(buf), f)) > 0) { 41329af65ebSAlexey Ozeritsky evbuffer_add(output_buffer, buf, s); 414c5887f73SAlexey Ozeritsky bytes += s; 415c5887f73SAlexey Ozeritsky } 416462e6b60SNick Mathewson evutil_snprintf(buf, sizeof(buf)-1, "%lu", (unsigned long)bytes); 41729af65ebSAlexey Ozeritsky evhttp_add_header(output_headers, "Content-Length", buf); 418c5887f73SAlexey Ozeritsky fclose(f); 419c5887f73SAlexey Ozeritsky } 420c5887f73SAlexey Ozeritsky 421c5887f73SAlexey Ozeritsky r = evhttp_make_request(evcon, req, data_file ? EVHTTP_REQ_POST : EVHTTP_REQ_GET, uri); 422be46c99bSCatalin Patulea if (r != 0) { 423be46c99bSCatalin Patulea fprintf(stderr, "evhttp_make_request() failed\n"); 424be46c99bSCatalin Patulea return 1; 425be46c99bSCatalin Patulea } 426be46c99bSCatalin Patulea 427be46c99bSCatalin Patulea event_base_dispatch(base); 428be46c99bSCatalin Patulea 429be46c99bSCatalin Patulea evhttp_connection_free(evcon); 430be46c99bSCatalin Patulea event_base_free(base); 431be46c99bSCatalin Patulea 4324e143958SJoakim Söderberg #ifdef _WIN32 43319222e52SJoakim Soderberg WSACleanup(); 43419222e52SJoakim Soderberg #endif 43519222e52SJoakim Soderberg 436be46c99bSCatalin Patulea return 0; 437be46c99bSCatalin Patulea } 438