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); 994637aa88SAzat Khuzhin fputs(" https-client -url <https-url> [-data data-file.bin] [-ignore-cert] [-retries num] [-timeout sec]\n", stderr); 100be46c99bSCatalin Patulea fputs("Example:\n", stderr); 101c5887f73SAlexey Ozeritsky fputs(" https-client -url https://ip.appspot.com/\n", stderr); 102be46c99bSCatalin Patulea } 103be46c99bSCatalin Patulea 104be46c99bSCatalin Patulea static void 10524a1f25aSAzat Khuzhin err(const char *msg) 106be46c99bSCatalin Patulea { 107be46c99bSCatalin Patulea fputs(msg, stderr); 108be46c99bSCatalin Patulea } 109be46c99bSCatalin Patulea 1105754d96aSPatrick Pelletier static void 11124a1f25aSAzat Khuzhin err_openssl(const char *func) 1125754d96aSPatrick Pelletier { 1135754d96aSPatrick Pelletier fprintf (stderr, "%s failed:\n", func); 1145754d96aSPatrick Pelletier 1155754d96aSPatrick Pelletier /* This is the OpenSSL function that prints the contents of the 1165754d96aSPatrick Pelletier * error stack to the specified file handle. */ 1175754d96aSPatrick Pelletier ERR_print_errors_fp (stderr); 1185754d96aSPatrick Pelletier 1195754d96aSPatrick Pelletier exit(1); 1205754d96aSPatrick Pelletier } 1215754d96aSPatrick Pelletier 12264d9f161SPatrick Pelletier /* See http://archives.seul.org/libevent/users/Jan-2013/msg00039.html */ 12364d9f161SPatrick Pelletier static int cert_verify_callback(X509_STORE_CTX *x509_ctx, void *arg) 12464d9f161SPatrick Pelletier { 12564d9f161SPatrick Pelletier char cert_str[256]; 12664d9f161SPatrick Pelletier const char *host = (const char *) arg; 12764d9f161SPatrick Pelletier const char *res_str = "X509_verify_cert failed"; 12864d9f161SPatrick Pelletier HostnameValidationResult res = Error; 12964d9f161SPatrick Pelletier 13064d9f161SPatrick Pelletier /* This is the function that OpenSSL would call if we hadn't called 13164d9f161SPatrick Pelletier * SSL_CTX_set_cert_verify_callback(). Therefore, we are "wrapping" 13264d9f161SPatrick Pelletier * the default functionality, rather than replacing it. */ 13329af65ebSAlexey Ozeritsky int ok_so_far = 0; 13464d9f161SPatrick Pelletier 13529af65ebSAlexey Ozeritsky X509 *server_cert = NULL; 13629af65ebSAlexey Ozeritsky 13729af65ebSAlexey Ozeritsky if (ignore_cert) { 13829af65ebSAlexey Ozeritsky return 1; 13929af65ebSAlexey Ozeritsky } 14029af65ebSAlexey Ozeritsky 14129af65ebSAlexey Ozeritsky ok_so_far = X509_verify_cert(x509_ctx); 14229af65ebSAlexey Ozeritsky 14329af65ebSAlexey Ozeritsky server_cert = X509_STORE_CTX_get_current_cert(x509_ctx); 14464d9f161SPatrick Pelletier 14564d9f161SPatrick Pelletier if (ok_so_far) { 14664d9f161SPatrick Pelletier res = validate_hostname(host, server_cert); 14764d9f161SPatrick Pelletier 14864d9f161SPatrick Pelletier switch (res) { 14964d9f161SPatrick Pelletier case MatchFound: 15064d9f161SPatrick Pelletier res_str = "MatchFound"; 15164d9f161SPatrick Pelletier break; 15264d9f161SPatrick Pelletier case MatchNotFound: 15364d9f161SPatrick Pelletier res_str = "MatchNotFound"; 15464d9f161SPatrick Pelletier break; 15564d9f161SPatrick Pelletier case NoSANPresent: 15664d9f161SPatrick Pelletier res_str = "NoSANPresent"; 15764d9f161SPatrick Pelletier break; 15864d9f161SPatrick Pelletier case MalformedCertificate: 15964d9f161SPatrick Pelletier res_str = "MalformedCertificate"; 16064d9f161SPatrick Pelletier break; 16164d9f161SPatrick Pelletier case Error: 16264d9f161SPatrick Pelletier res_str = "Error"; 16364d9f161SPatrick Pelletier break; 16464d9f161SPatrick Pelletier default: 16564d9f161SPatrick Pelletier res_str = "WTF!"; 16664d9f161SPatrick Pelletier break; 16764d9f161SPatrick Pelletier } 16864d9f161SPatrick Pelletier } 16964d9f161SPatrick Pelletier 17064d9f161SPatrick Pelletier X509_NAME_oneline(X509_get_subject_name (server_cert), 17164d9f161SPatrick Pelletier cert_str, sizeof (cert_str)); 17264d9f161SPatrick Pelletier 17364d9f161SPatrick Pelletier if (res == MatchFound) { 17464d9f161SPatrick Pelletier printf("https server '%s' has this certificate, " 17564d9f161SPatrick Pelletier "which looks good to me:\n%s\n", 17664d9f161SPatrick Pelletier host, cert_str); 17764d9f161SPatrick Pelletier return 1; 17864d9f161SPatrick Pelletier } else { 17964d9f161SPatrick Pelletier printf("Got '%s' for hostname '%s' and certificate:\n%s\n", 18064d9f161SPatrick Pelletier res_str, host, cert_str); 18164d9f161SPatrick Pelletier return 0; 18264d9f161SPatrick Pelletier } 18364d9f161SPatrick Pelletier } 18464d9f161SPatrick Pelletier 185be46c99bSCatalin Patulea int 186be46c99bSCatalin Patulea main(int argc, char **argv) 187be46c99bSCatalin Patulea { 188be46c99bSCatalin Patulea int r; 189be46c99bSCatalin Patulea 19024a1f25aSAzat Khuzhin struct evhttp_uri *http_uri = NULL; 19190786eb0SNick Mathewson const char *url = NULL, *data_file = NULL; 19290786eb0SNick Mathewson const char *scheme, *host, *path, *query; 193be46c99bSCatalin Patulea char uri[256]; 194be46c99bSCatalin Patulea int port; 195d9da8443SAzat Khuzhin int retries = 0; 1964637aa88SAzat Khuzhin int timeout = -1; 197be46c99bSCatalin Patulea 19824a1f25aSAzat Khuzhin SSL_CTX *ssl_ctx = NULL; 199f3d7ff5dSAzat Khuzhin SSL *ssl = NULL; 200be46c99bSCatalin Patulea struct bufferevent *bev; 20124a1f25aSAzat Khuzhin struct evhttp_connection *evcon = NULL; 202be46c99bSCatalin Patulea struct evhttp_request *req; 2038a90a850SNick Mathewson struct evkeyvalq *output_headers; 20429af65ebSAlexey Ozeritsky struct evbuffer *output_buffer; 205be46c99bSCatalin Patulea 206c5887f73SAlexey Ozeritsky int i; 20724a1f25aSAzat Khuzhin int ret = 0; 20824a1f25aSAzat Khuzhin enum { HTTP, HTTPS } type = HTTP; 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(); 21624a1f25aSAzat Khuzhin goto error; 217c5887f73SAlexey Ozeritsky } 218c5887f73SAlexey Ozeritsky } else if (!strcmp("-ignore-cert", argv[i])) { 219c5887f73SAlexey Ozeritsky ignore_cert = 1; 220c5887f73SAlexey Ozeritsky } else if (!strcmp("-data", argv[i])) { 221c5887f73SAlexey Ozeritsky if (i < argc - 1) { 222c5887f73SAlexey Ozeritsky data_file = argv[i + 1]; 223c5887f73SAlexey Ozeritsky } else { 224c5887f73SAlexey Ozeritsky syntax(); 22524a1f25aSAzat Khuzhin goto error; 226c5887f73SAlexey Ozeritsky } 227d9da8443SAzat Khuzhin } else if (!strcmp("-retries", argv[i])) { 228d9da8443SAzat Khuzhin if (i < argc - 1) { 229d9da8443SAzat Khuzhin retries = atoi(argv[i + 1]); 230d9da8443SAzat Khuzhin } else { 231d9da8443SAzat Khuzhin syntax(); 23224a1f25aSAzat Khuzhin goto error; 233d9da8443SAzat Khuzhin } 2344637aa88SAzat Khuzhin } else if (!strcmp("-timeout", argv[i])) { 2354637aa88SAzat Khuzhin if (i < argc - 1) { 2364637aa88SAzat Khuzhin timeout = atoi(argv[i + 1]); 2374637aa88SAzat Khuzhin } else { 2384637aa88SAzat Khuzhin syntax(); 2394637aa88SAzat Khuzhin goto error; 2404637aa88SAzat Khuzhin } 241c5887f73SAlexey Ozeritsky } else if (!strcmp("-help", argv[i])) { 242c5887f73SAlexey Ozeritsky syntax(); 24324a1f25aSAzat Khuzhin goto error; 244c5887f73SAlexey Ozeritsky } 245c5887f73SAlexey Ozeritsky } 246c5887f73SAlexey Ozeritsky 247c5887f73SAlexey Ozeritsky if (!url) { 248c5887f73SAlexey Ozeritsky syntax(); 24924a1f25aSAzat Khuzhin goto error; 250c5887f73SAlexey Ozeritsky } 251c5887f73SAlexey Ozeritsky 2524e143958SJoakim Söderberg #ifdef _WIN32 25319222e52SJoakim Soderberg { 25419222e52SJoakim Soderberg WORD wVersionRequested; 25519222e52SJoakim Soderberg WSADATA wsaData; 25619222e52SJoakim Soderberg int err; 25719222e52SJoakim Soderberg 25819222e52SJoakim Soderberg wVersionRequested = MAKEWORD(2, 2); 25919222e52SJoakim Soderberg 26019222e52SJoakim Soderberg err = WSAStartup(wVersionRequested, &wsaData); 26119222e52SJoakim Soderberg if (err != 0) { 26219222e52SJoakim Soderberg printf("WSAStartup failed with error: %d\n", err); 26324a1f25aSAzat Khuzhin goto error; 26419222e52SJoakim Soderberg } 26519222e52SJoakim Soderberg } 2664e143958SJoakim Söderberg #endif // _WIN32 26719222e52SJoakim Soderberg 268be46c99bSCatalin Patulea http_uri = evhttp_uri_parse(url); 269be46c99bSCatalin Patulea if (http_uri == NULL) { 27024a1f25aSAzat Khuzhin err("malformed url"); 27124a1f25aSAzat Khuzhin goto error; 272be46c99bSCatalin Patulea } 273be46c99bSCatalin Patulea 274be46c99bSCatalin Patulea scheme = evhttp_uri_get_scheme(http_uri); 275be46c99bSCatalin Patulea if (scheme == NULL || (strcasecmp(scheme, "https") != 0 && 276be46c99bSCatalin Patulea strcasecmp(scheme, "http") != 0)) { 27724a1f25aSAzat Khuzhin err("url must be http or https"); 27824a1f25aSAzat Khuzhin goto error; 279be46c99bSCatalin Patulea } 280be46c99bSCatalin Patulea 281be46c99bSCatalin Patulea host = evhttp_uri_get_host(http_uri); 282be46c99bSCatalin Patulea if (host == NULL) { 28324a1f25aSAzat Khuzhin err("url must have a host"); 28424a1f25aSAzat Khuzhin goto error; 285be46c99bSCatalin Patulea } 286be46c99bSCatalin Patulea 287be46c99bSCatalin Patulea port = evhttp_uri_get_port(http_uri); 288be46c99bSCatalin Patulea if (port == -1) { 289be46c99bSCatalin Patulea port = (strcasecmp(scheme, "http") == 0) ? 80 : 443; 290be46c99bSCatalin Patulea } 291be46c99bSCatalin Patulea 292be46c99bSCatalin Patulea path = evhttp_uri_get_path(http_uri); 29329a04825SAndrey Skriabin if (strlen(path) == 0) { 294be46c99bSCatalin Patulea path = "/"; 295be46c99bSCatalin Patulea } 296be46c99bSCatalin Patulea 297be46c99bSCatalin Patulea query = evhttp_uri_get_query(http_uri); 298be46c99bSCatalin Patulea if (query == NULL) { 299be46c99bSCatalin Patulea snprintf(uri, sizeof(uri) - 1, "%s", path); 300be46c99bSCatalin Patulea } else { 301be46c99bSCatalin Patulea snprintf(uri, sizeof(uri) - 1, "%s?%s", path, query); 302be46c99bSCatalin Patulea } 303be46c99bSCatalin Patulea uri[sizeof(uri) - 1] = '\0'; 304be46c99bSCatalin Patulea 305be46c99bSCatalin Patulea // Initialize OpenSSL 306be46c99bSCatalin Patulea SSL_library_init(); 307be46c99bSCatalin Patulea ERR_load_crypto_strings(); 308be46c99bSCatalin Patulea SSL_load_error_strings(); 309be46c99bSCatalin Patulea OpenSSL_add_all_algorithms(); 3105754d96aSPatrick Pelletier 3115754d96aSPatrick Pelletier /* This isn't strictly necessary... OpenSSL performs RAND_poll 3125754d96aSPatrick Pelletier * automatically on first use of random number generator. */ 313be46c99bSCatalin Patulea r = RAND_poll(); 314be46c99bSCatalin Patulea if (r == 0) { 31524a1f25aSAzat Khuzhin err_openssl("RAND_poll"); 31624a1f25aSAzat Khuzhin goto error; 317be46c99bSCatalin Patulea } 3185754d96aSPatrick Pelletier 3195754d96aSPatrick Pelletier /* Create a new OpenSSL context */ 320be46c99bSCatalin Patulea ssl_ctx = SSL_CTX_new(SSLv23_method()); 32124a1f25aSAzat Khuzhin if (!ssl_ctx) { 32224a1f25aSAzat Khuzhin err_openssl("SSL_CTX_new"); 32324a1f25aSAzat Khuzhin goto error; 32424a1f25aSAzat Khuzhin } 325be46c99bSCatalin Patulea 3264e143958SJoakim Söderberg #ifndef _WIN32 32719222e52SJoakim Soderberg /* TODO: Add certificate loading on Windows as well */ 32819222e52SJoakim Soderberg 329aacd674cSPatrick Pelletier /* Attempt to use the system's trusted root certificates. 330aacd674cSPatrick Pelletier * (This path is only valid for Debian-based systems.) */ 331aacd674cSPatrick Pelletier if (1 != SSL_CTX_load_verify_locations(ssl_ctx, 332aacd674cSPatrick Pelletier "/etc/ssl/certs/ca-certificates.crt", 33324a1f25aSAzat Khuzhin NULL)) { 33424a1f25aSAzat Khuzhin err_openssl("SSL_CTX_load_verify_locations"); 33524a1f25aSAzat Khuzhin goto error; 33624a1f25aSAzat Khuzhin } 33764d9f161SPatrick Pelletier /* Ask OpenSSL to verify the server certificate. Note that this 33864d9f161SPatrick Pelletier * does NOT include verifying that the hostname is correct. 33964d9f161SPatrick Pelletier * So, by itself, this means anyone with any legitimate 34064d9f161SPatrick Pelletier * CA-issued certificate for any website, can impersonate any 34164d9f161SPatrick Pelletier * other website in the world. This is not good. See "The 34264d9f161SPatrick Pelletier * Most Dangerous Code in the World" article at 34364d9f161SPatrick Pelletier * https://crypto.stanford.edu/~dabo/pubs/abstracts/ssl-client-bugs.html 34464d9f161SPatrick Pelletier */ 345aacd674cSPatrick Pelletier SSL_CTX_set_verify(ssl_ctx, SSL_VERIFY_PEER, NULL); 34664d9f161SPatrick Pelletier /* This is how we solve the problem mentioned in the previous 34764d9f161SPatrick Pelletier * comment. We "wrap" OpenSSL's validation routine in our 34864d9f161SPatrick Pelletier * own routine, which also validates the hostname by calling 34964d9f161SPatrick Pelletier * the code provided by iSECPartners. Note that even though 35064d9f161SPatrick Pelletier * the "Everything You've Always Wanted to Know About 35164d9f161SPatrick Pelletier * Certificate Validation With OpenSSL (But Were Afraid to 35264d9f161SPatrick Pelletier * Ask)" paper from iSECPartners says very explicitly not to 35364d9f161SPatrick Pelletier * call SSL_CTX_set_cert_verify_callback (at the bottom of 35464d9f161SPatrick Pelletier * page 2), what we're doing here is safe because our 35564d9f161SPatrick Pelletier * cert_verify_callback() calls X509_verify_cert(), which is 35664d9f161SPatrick Pelletier * OpenSSL's built-in routine which would have been called if 35764d9f161SPatrick Pelletier * we hadn't set the callback. Therefore, we're just 35864d9f161SPatrick Pelletier * "wrapping" OpenSSL's routine, not replacing it. */ 35964d9f161SPatrick Pelletier SSL_CTX_set_cert_verify_callback(ssl_ctx, cert_verify_callback, 36064d9f161SPatrick Pelletier (void *) host); 3614e143958SJoakim Söderberg #endif // not _WIN32 362aacd674cSPatrick Pelletier 363be46c99bSCatalin Patulea // Create event base 364be46c99bSCatalin Patulea base = event_base_new(); 365be46c99bSCatalin Patulea if (!base) { 366be46c99bSCatalin Patulea perror("event_base_new()"); 36724a1f25aSAzat Khuzhin goto error; 368be46c99bSCatalin Patulea } 369be46c99bSCatalin Patulea 370be46c99bSCatalin Patulea // Create OpenSSL bufferevent and stack evhttp on top of it 371be46c99bSCatalin Patulea ssl = SSL_new(ssl_ctx); 372be46c99bSCatalin Patulea if (ssl == NULL) { 37324a1f25aSAzat Khuzhin err_openssl("SSL_new()"); 37424a1f25aSAzat Khuzhin goto error; 375be46c99bSCatalin Patulea } 376be46c99bSCatalin Patulea 3775c7282f7SJoakim Soderberg #ifdef SSL_CTRL_SET_TLSEXT_HOSTNAME 378d1976f8eSNick Mathewson // Set hostname for SNI extension 379d1976f8eSNick Mathewson SSL_set_tlsext_host_name(ssl, host); 3805c7282f7SJoakim Soderberg #endif 381d1976f8eSNick Mathewson 382be46c99bSCatalin Patulea if (strcasecmp(scheme, "http") == 0) { 383be46c99bSCatalin Patulea bev = bufferevent_socket_new(base, -1, BEV_OPT_CLOSE_ON_FREE); 384be46c99bSCatalin Patulea } else { 38524a1f25aSAzat Khuzhin type = HTTPS; 386be46c99bSCatalin Patulea bev = bufferevent_openssl_socket_new(base, -1, ssl, 387be46c99bSCatalin Patulea BUFFEREVENT_SSL_CONNECTING, 388be46c99bSCatalin Patulea BEV_OPT_CLOSE_ON_FREE|BEV_OPT_DEFER_CALLBACKS); 389be46c99bSCatalin Patulea } 390be46c99bSCatalin Patulea 391be46c99bSCatalin Patulea if (bev == NULL) { 392be46c99bSCatalin Patulea fprintf(stderr, "bufferevent_openssl_socket_new() failed\n"); 39324a1f25aSAzat Khuzhin goto error; 394be46c99bSCatalin Patulea } 395be46c99bSCatalin Patulea 396be46c99bSCatalin Patulea bufferevent_openssl_set_allow_dirty_shutdown(bev, 1); 397be46c99bSCatalin Patulea 398be46c99bSCatalin Patulea // For simplicity, we let DNS resolution block. Everything else should be 399be46c99bSCatalin Patulea // asynchronous though. 400be46c99bSCatalin Patulea evcon = evhttp_connection_base_bufferevent_new(base, NULL, bev, 401be46c99bSCatalin Patulea host, port); 402be46c99bSCatalin Patulea if (evcon == NULL) { 403be46c99bSCatalin Patulea fprintf(stderr, "evhttp_connection_base_bufferevent_new() failed\n"); 40424a1f25aSAzat Khuzhin goto error; 405be46c99bSCatalin Patulea } 406be46c99bSCatalin Patulea 407d9da8443SAzat Khuzhin if (retries > 0) { 408d9da8443SAzat Khuzhin evhttp_connection_set_retries(evcon, retries); 409d9da8443SAzat Khuzhin } 4104637aa88SAzat Khuzhin if (timeout >= 0) { 4114637aa88SAzat Khuzhin evhttp_connection_set_timeout(evcon, timeout); 4124637aa88SAzat Khuzhin } 413d9da8443SAzat Khuzhin 414be46c99bSCatalin Patulea // Fire off the request 4155754d96aSPatrick Pelletier req = evhttp_request_new(http_request_done, bev); 416be46c99bSCatalin Patulea if (req == NULL) { 417be46c99bSCatalin Patulea fprintf(stderr, "evhttp_request_new() failed\n"); 41824a1f25aSAzat Khuzhin goto error; 419be46c99bSCatalin Patulea } 420be46c99bSCatalin Patulea 4218a90a850SNick Mathewson output_headers = evhttp_request_get_output_headers(req); 4228a90a850SNick Mathewson evhttp_add_header(output_headers, "Host", host); 4238a90a850SNick Mathewson evhttp_add_header(output_headers, "Connection", "close"); 424be46c99bSCatalin Patulea 425c5887f73SAlexey Ozeritsky if (data_file) { 42690786eb0SNick Mathewson /* NOTE: In production code, you'd probably want to use 42790786eb0SNick Mathewson * evbuffer_add_file() or evbuffer_add_file_segment(), to 42890786eb0SNick Mathewson * avoid needless copying. */ 429c5887f73SAlexey Ozeritsky FILE * f = fopen(data_file, "rb"); 430c5887f73SAlexey Ozeritsky char buf[1024]; 431d7be7887SJoakim Soderberg size_t s; 432c5887f73SAlexey Ozeritsky size_t bytes = 0; 433c5887f73SAlexey Ozeritsky 434c5887f73SAlexey Ozeritsky if (!f) { 435c5887f73SAlexey Ozeritsky syntax(); 43624a1f25aSAzat Khuzhin goto error; 437c5887f73SAlexey Ozeritsky } 438c5887f73SAlexey Ozeritsky 43929af65ebSAlexey Ozeritsky output_buffer = evhttp_request_get_output_buffer(req); 440c5887f73SAlexey Ozeritsky while ((s = fread(buf, 1, sizeof(buf), f)) > 0) { 44129af65ebSAlexey Ozeritsky evbuffer_add(output_buffer, buf, s); 442c5887f73SAlexey Ozeritsky bytes += s; 443c5887f73SAlexey Ozeritsky } 444462e6b60SNick Mathewson evutil_snprintf(buf, sizeof(buf)-1, "%lu", (unsigned long)bytes); 44529af65ebSAlexey Ozeritsky evhttp_add_header(output_headers, "Content-Length", buf); 446c5887f73SAlexey Ozeritsky fclose(f); 447c5887f73SAlexey Ozeritsky } 448c5887f73SAlexey Ozeritsky 449c5887f73SAlexey Ozeritsky r = evhttp_make_request(evcon, req, data_file ? EVHTTP_REQ_POST : EVHTTP_REQ_GET, uri); 450be46c99bSCatalin Patulea if (r != 0) { 451be46c99bSCatalin Patulea fprintf(stderr, "evhttp_make_request() failed\n"); 45224a1f25aSAzat Khuzhin goto error; 453be46c99bSCatalin Patulea } 454be46c99bSCatalin Patulea 455be46c99bSCatalin Patulea event_base_dispatch(base); 45624a1f25aSAzat Khuzhin goto cleanup; 457be46c99bSCatalin Patulea 45824a1f25aSAzat Khuzhin error: 45924a1f25aSAzat Khuzhin ret = 1; 46024a1f25aSAzat Khuzhin cleanup: 46124a1f25aSAzat Khuzhin if (evcon) 462be46c99bSCatalin Patulea evhttp_connection_free(evcon); 46324a1f25aSAzat Khuzhin if (http_uri) 46424a1f25aSAzat Khuzhin evhttp_uri_free(http_uri); 465be46c99bSCatalin Patulea event_base_free(base); 466be46c99bSCatalin Patulea 46724a1f25aSAzat Khuzhin if (ssl_ctx) 46824a1f25aSAzat Khuzhin SSL_CTX_free(ssl_ctx); 469f3d7ff5dSAzat Khuzhin if (type == HTTP && ssl) 47024a1f25aSAzat Khuzhin SSL_free(ssl); 47124a1f25aSAzat Khuzhin EVP_cleanup(); 47224a1f25aSAzat Khuzhin ERR_free_strings(); 47324a1f25aSAzat Khuzhin 474*c4e9d9bdSAzat Khuzhin #ifdef EVENT__HAVE_ERR_REMOVE_THREAD_STATE 47577ad68a6SAzat Khuzhin ERR_remove_thread_state(NULL); 476*c4e9d9bdSAzat Khuzhin #else 477*c4e9d9bdSAzat Khuzhin ERR_remove_state(0); 478*c4e9d9bdSAzat Khuzhin #endif 47924a1f25aSAzat Khuzhin CRYPTO_cleanup_all_ex_data(); 48024a1f25aSAzat Khuzhin 48124a1f25aSAzat Khuzhin sk_SSL_COMP_free(SSL_COMP_get_compression_methods()); 48224a1f25aSAzat Khuzhin 4834e143958SJoakim Söderberg #ifdef _WIN32 48419222e52SJoakim Soderberg WSACleanup(); 48519222e52SJoakim Soderberg #endif 48619222e52SJoakim Soderberg 48724a1f25aSAzat Khuzhin return ret; 488be46c99bSCatalin Patulea } 489