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 19*88ecda3bSNick Mathewson #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. */ 12829af65ebSAlexey Ozeritsky int ok_so_far = 0; 12964d9f161SPatrick Pelletier 13029af65ebSAlexey Ozeritsky X509 *server_cert = NULL; 13129af65ebSAlexey Ozeritsky 13229af65ebSAlexey Ozeritsky if (ignore_cert) { 13329af65ebSAlexey Ozeritsky return 1; 13429af65ebSAlexey Ozeritsky } 13529af65ebSAlexey Ozeritsky 13629af65ebSAlexey Ozeritsky ok_so_far = X509_verify_cert(x509_ctx); 13729af65ebSAlexey Ozeritsky 13829af65ebSAlexey 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; 18690786eb0SNick Mathewson const char *url = NULL, *data_file = NULL; 18790786eb0SNick Mathewson const char *scheme, *host, *path, *query; 188be46c99bSCatalin Patulea char uri[256]; 189be46c99bSCatalin Patulea int port; 190be46c99bSCatalin Patulea 191be46c99bSCatalin Patulea SSL_CTX *ssl_ctx; 192be46c99bSCatalin Patulea SSL *ssl; 193be46c99bSCatalin Patulea struct bufferevent *bev; 194be46c99bSCatalin Patulea struct evhttp_connection *evcon; 195be46c99bSCatalin Patulea struct evhttp_request *req; 1968a90a850SNick Mathewson struct evkeyvalq *output_headers; 19729af65ebSAlexey Ozeritsky struct evbuffer * output_buffer; 198be46c99bSCatalin Patulea 199c5887f73SAlexey Ozeritsky int i; 200be46c99bSCatalin Patulea 201c5887f73SAlexey Ozeritsky for (i = 1; i < argc; i++) { 202c5887f73SAlexey Ozeritsky if (!strcmp("-url", argv[i])) { 203c5887f73SAlexey Ozeritsky if (i < argc - 1) { 204c5887f73SAlexey Ozeritsky url = argv[i + 1]; 205c5887f73SAlexey Ozeritsky } else { 206c5887f73SAlexey Ozeritsky syntax(); 207c5887f73SAlexey Ozeritsky } 208c5887f73SAlexey Ozeritsky } else if (!strcmp("-ignore-cert", argv[i])) { 209c5887f73SAlexey Ozeritsky ignore_cert = 1; 210c5887f73SAlexey Ozeritsky } else if (!strcmp("-data", argv[i])) { 211c5887f73SAlexey Ozeritsky if (i < argc - 1) { 212c5887f73SAlexey Ozeritsky data_file = argv[i + 1]; 213c5887f73SAlexey Ozeritsky } else { 214c5887f73SAlexey Ozeritsky syntax(); 215c5887f73SAlexey Ozeritsky } 216c5887f73SAlexey Ozeritsky } else if (!strcmp("-help", argv[i])) { 217c5887f73SAlexey Ozeritsky syntax(); 218c5887f73SAlexey Ozeritsky } 219c5887f73SAlexey Ozeritsky } 220c5887f73SAlexey Ozeritsky 221c5887f73SAlexey Ozeritsky if (!url) { 222c5887f73SAlexey Ozeritsky syntax(); 223c5887f73SAlexey Ozeritsky } 224c5887f73SAlexey Ozeritsky 225be46c99bSCatalin Patulea http_uri = evhttp_uri_parse(url); 226be46c99bSCatalin Patulea if (http_uri == NULL) { 227be46c99bSCatalin Patulea die("malformed url"); 228be46c99bSCatalin Patulea } 229be46c99bSCatalin Patulea 230be46c99bSCatalin Patulea scheme = evhttp_uri_get_scheme(http_uri); 231be46c99bSCatalin Patulea if (scheme == NULL || (strcasecmp(scheme, "https") != 0 && 232be46c99bSCatalin Patulea strcasecmp(scheme, "http") != 0)) { 233be46c99bSCatalin Patulea die("url must be http or https"); 234be46c99bSCatalin Patulea } 235be46c99bSCatalin Patulea 236be46c99bSCatalin Patulea host = evhttp_uri_get_host(http_uri); 237be46c99bSCatalin Patulea if (host == NULL) { 238be46c99bSCatalin Patulea die("url must have a host"); 239be46c99bSCatalin Patulea } 240be46c99bSCatalin Patulea 241be46c99bSCatalin Patulea port = evhttp_uri_get_port(http_uri); 242be46c99bSCatalin Patulea if (port == -1) { 243be46c99bSCatalin Patulea port = (strcasecmp(scheme, "http") == 0) ? 80 : 443; 244be46c99bSCatalin Patulea } 245be46c99bSCatalin Patulea 246be46c99bSCatalin Patulea path = evhttp_uri_get_path(http_uri); 247be46c99bSCatalin Patulea if (path == NULL) { 248be46c99bSCatalin Patulea path = "/"; 249be46c99bSCatalin Patulea } 250be46c99bSCatalin Patulea 251be46c99bSCatalin Patulea query = evhttp_uri_get_query(http_uri); 252be46c99bSCatalin Patulea if (query == NULL) { 253be46c99bSCatalin Patulea snprintf(uri, sizeof(uri) - 1, "%s", path); 254be46c99bSCatalin Patulea } else { 255be46c99bSCatalin Patulea snprintf(uri, sizeof(uri) - 1, "%s?%s", path, query); 256be46c99bSCatalin Patulea } 257be46c99bSCatalin Patulea uri[sizeof(uri) - 1] = '\0'; 258be46c99bSCatalin Patulea 259be46c99bSCatalin Patulea // Initialize OpenSSL 260be46c99bSCatalin Patulea SSL_library_init(); 261be46c99bSCatalin Patulea ERR_load_crypto_strings(); 262be46c99bSCatalin Patulea SSL_load_error_strings(); 263be46c99bSCatalin Patulea OpenSSL_add_all_algorithms(); 2645754d96aSPatrick Pelletier 2655754d96aSPatrick Pelletier /* This isn't strictly necessary... OpenSSL performs RAND_poll 2665754d96aSPatrick Pelletier * automatically on first use of random number generator. */ 267be46c99bSCatalin Patulea r = RAND_poll(); 268be46c99bSCatalin Patulea if (r == 0) { 2695754d96aSPatrick Pelletier die_openssl("RAND_poll"); 270be46c99bSCatalin Patulea } 2715754d96aSPatrick Pelletier 2725754d96aSPatrick Pelletier /* Create a new OpenSSL context */ 273be46c99bSCatalin Patulea ssl_ctx = SSL_CTX_new(SSLv23_method()); 2745754d96aSPatrick Pelletier if (!ssl_ctx) 2755754d96aSPatrick Pelletier die_openssl("SSL_CTX_new"); 276be46c99bSCatalin Patulea 277aacd674cSPatrick Pelletier /* Attempt to use the system's trusted root certificates. 278aacd674cSPatrick Pelletier * (This path is only valid for Debian-based systems.) */ 279aacd674cSPatrick Pelletier if (1 != SSL_CTX_load_verify_locations(ssl_ctx, 280aacd674cSPatrick Pelletier "/etc/ssl/certs/ca-certificates.crt", 281aacd674cSPatrick Pelletier NULL)) 282aacd674cSPatrick Pelletier die_openssl("SSL_CTX_load_verify_locations"); 28364d9f161SPatrick Pelletier /* Ask OpenSSL to verify the server certificate. Note that this 28464d9f161SPatrick Pelletier * does NOT include verifying that the hostname is correct. 28564d9f161SPatrick Pelletier * So, by itself, this means anyone with any legitimate 28664d9f161SPatrick Pelletier * CA-issued certificate for any website, can impersonate any 28764d9f161SPatrick Pelletier * other website in the world. This is not good. See "The 28864d9f161SPatrick Pelletier * Most Dangerous Code in the World" article at 28964d9f161SPatrick Pelletier * https://crypto.stanford.edu/~dabo/pubs/abstracts/ssl-client-bugs.html 29064d9f161SPatrick Pelletier */ 291aacd674cSPatrick Pelletier SSL_CTX_set_verify(ssl_ctx, SSL_VERIFY_PEER, NULL); 29264d9f161SPatrick Pelletier /* This is how we solve the problem mentioned in the previous 29364d9f161SPatrick Pelletier * comment. We "wrap" OpenSSL's validation routine in our 29464d9f161SPatrick Pelletier * own routine, which also validates the hostname by calling 29564d9f161SPatrick Pelletier * the code provided by iSECPartners. Note that even though 29664d9f161SPatrick Pelletier * the "Everything You've Always Wanted to Know About 29764d9f161SPatrick Pelletier * Certificate Validation With OpenSSL (But Were Afraid to 29864d9f161SPatrick Pelletier * Ask)" paper from iSECPartners says very explicitly not to 29964d9f161SPatrick Pelletier * call SSL_CTX_set_cert_verify_callback (at the bottom of 30064d9f161SPatrick Pelletier * page 2), what we're doing here is safe because our 30164d9f161SPatrick Pelletier * cert_verify_callback() calls X509_verify_cert(), which is 30264d9f161SPatrick Pelletier * OpenSSL's built-in routine which would have been called if 30364d9f161SPatrick Pelletier * we hadn't set the callback. Therefore, we're just 30464d9f161SPatrick Pelletier * "wrapping" OpenSSL's routine, not replacing it. */ 30564d9f161SPatrick Pelletier SSL_CTX_set_cert_verify_callback (ssl_ctx, cert_verify_callback, 30664d9f161SPatrick Pelletier (void *) host); 307aacd674cSPatrick Pelletier 308be46c99bSCatalin Patulea // Create event base 309be46c99bSCatalin Patulea base = event_base_new(); 310be46c99bSCatalin Patulea if (!base) { 311be46c99bSCatalin Patulea perror("event_base_new()"); 312be46c99bSCatalin Patulea return 1; 313be46c99bSCatalin Patulea } 314be46c99bSCatalin Patulea 315be46c99bSCatalin Patulea // Create OpenSSL bufferevent and stack evhttp on top of it 316be46c99bSCatalin Patulea ssl = SSL_new(ssl_ctx); 317be46c99bSCatalin Patulea if (ssl == NULL) { 3185754d96aSPatrick Pelletier die_openssl("SSL_new()"); 319be46c99bSCatalin Patulea } 320be46c99bSCatalin Patulea 321d1976f8eSNick Mathewson // Set hostname for SNI extension 322d1976f8eSNick Mathewson SSL_set_tlsext_host_name(ssl, host); 323d1976f8eSNick Mathewson 324be46c99bSCatalin Patulea if (strcasecmp(scheme, "http") == 0) { 325be46c99bSCatalin Patulea bev = bufferevent_socket_new(base, -1, BEV_OPT_CLOSE_ON_FREE); 326be46c99bSCatalin Patulea } else { 327be46c99bSCatalin Patulea bev = bufferevent_openssl_socket_new(base, -1, ssl, 328be46c99bSCatalin Patulea BUFFEREVENT_SSL_CONNECTING, 329be46c99bSCatalin Patulea BEV_OPT_CLOSE_ON_FREE|BEV_OPT_DEFER_CALLBACKS); 330be46c99bSCatalin Patulea } 331be46c99bSCatalin Patulea 332be46c99bSCatalin Patulea if (bev == NULL) { 333be46c99bSCatalin Patulea fprintf(stderr, "bufferevent_openssl_socket_new() failed\n"); 334be46c99bSCatalin Patulea return 1; 335be46c99bSCatalin Patulea } 336be46c99bSCatalin Patulea 337be46c99bSCatalin Patulea bufferevent_openssl_set_allow_dirty_shutdown(bev, 1); 338be46c99bSCatalin Patulea 339be46c99bSCatalin Patulea // For simplicity, we let DNS resolution block. Everything else should be 340be46c99bSCatalin Patulea // asynchronous though. 341be46c99bSCatalin Patulea evcon = evhttp_connection_base_bufferevent_new(base, NULL, bev, 342be46c99bSCatalin Patulea host, port); 343be46c99bSCatalin Patulea if (evcon == NULL) { 344be46c99bSCatalin Patulea fprintf(stderr, "evhttp_connection_base_bufferevent_new() failed\n"); 345be46c99bSCatalin Patulea return 1; 346be46c99bSCatalin Patulea } 347be46c99bSCatalin Patulea 348be46c99bSCatalin Patulea // Fire off the request 3495754d96aSPatrick Pelletier req = evhttp_request_new(http_request_done, bev); 350be46c99bSCatalin Patulea if (req == NULL) { 351be46c99bSCatalin Patulea fprintf(stderr, "evhttp_request_new() failed\n"); 352be46c99bSCatalin Patulea return 1; 353be46c99bSCatalin Patulea } 354be46c99bSCatalin Patulea 3558a90a850SNick Mathewson output_headers = evhttp_request_get_output_headers(req); 3568a90a850SNick Mathewson evhttp_add_header(output_headers, "Host", host); 3578a90a850SNick Mathewson evhttp_add_header(output_headers, "Connection", "close"); 358be46c99bSCatalin Patulea 359c5887f73SAlexey Ozeritsky if (data_file) { 36090786eb0SNick Mathewson /* NOTE: In production code, you'd probably want to use 36190786eb0SNick Mathewson * evbuffer_add_file() or evbuffer_add_file_segment(), to 36290786eb0SNick Mathewson * avoid needless copying. */ 363c5887f73SAlexey Ozeritsky FILE * f = fopen(data_file, "rb"); 364c5887f73SAlexey Ozeritsky char buf[1024]; 365c5887f73SAlexey Ozeritsky ssize_t s; 366c5887f73SAlexey Ozeritsky size_t bytes = 0; 367c5887f73SAlexey Ozeritsky 368c5887f73SAlexey Ozeritsky if (!f) { 369c5887f73SAlexey Ozeritsky syntax(); 370c5887f73SAlexey Ozeritsky } 371c5887f73SAlexey Ozeritsky 37229af65ebSAlexey Ozeritsky output_buffer = evhttp_request_get_output_buffer(req); 373c5887f73SAlexey Ozeritsky while ((s = fread(buf, 1, sizeof(buf), f)) > 0) { 37429af65ebSAlexey Ozeritsky evbuffer_add(output_buffer, buf, s); 375c5887f73SAlexey Ozeritsky bytes += s; 376c5887f73SAlexey Ozeritsky } 37729af65ebSAlexey Ozeritsky evutil_snprintf(buf, sizeof(buf)-1, "%lu", bytes); 37829af65ebSAlexey Ozeritsky evhttp_add_header(output_headers, "Content-Length", buf); 379c5887f73SAlexey Ozeritsky fclose(f); 380c5887f73SAlexey Ozeritsky } 381c5887f73SAlexey Ozeritsky 382c5887f73SAlexey Ozeritsky r = evhttp_make_request(evcon, req, data_file ? EVHTTP_REQ_POST : EVHTTP_REQ_GET, uri); 383be46c99bSCatalin Patulea if (r != 0) { 384be46c99bSCatalin Patulea fprintf(stderr, "evhttp_make_request() failed\n"); 385be46c99bSCatalin Patulea return 1; 386be46c99bSCatalin Patulea } 387be46c99bSCatalin Patulea 388be46c99bSCatalin Patulea event_base_dispatch(base); 389be46c99bSCatalin Patulea 390be46c99bSCatalin Patulea evhttp_connection_free(evcon); 391be46c99bSCatalin Patulea event_base_free(base); 392be46c99bSCatalin Patulea 393be46c99bSCatalin Patulea return 0; 394be46c99bSCatalin Patulea } 395