Skip to content
This repository

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
branch: master
Fetching contributors…

Cannot retrieve contributors at this time

file 151 lines (115 sloc) 5.003 kb
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151
#define CURL_CLIENT
#include "curl_client.h"

CurlClient::CurlClient() {}

CurlClient::~CurlClient() {}

curl_response CurlClient::request(curl_request request) {
  curl_response response;

  CURL *curl_handle = curl_easy_init();
 
  /* set request URL */
  curl_easy_setopt(curl_handle, CURLOPT_URL, request.url.c_str());

  /* set method type */
  if (request.method == "HEAD") {
    curl_easy_setopt(curl_handle, CURLOPT_NOBODY, 1); //no need to get response data if it's a HEAD request
  }
  else {
    curl_easy_setopt(curl_handle, CURLOPT_CUSTOMREQUEST, request.method.c_str());
  }

  /* no signal. should stop curl from killing the thread */
  curl_easy_setopt(curl_handle, CURLOPT_NOSIGNAL, 1L);

  /* set timeout */
  if (request.timeout > 0) {
    curl_easy_setopt(curl_handle, CURLOPT_TIMEOUT_MS, request.timeout);
  }

  /* set connection timeout */
  if (request.connectionTimeout > 0) {
    curl_easy_setopt(curl_handle, CURLOPT_CONNECTTIMEOUT_MS, request.connectionTimeout);
  }

  /* add custom headers */
  struct curl_slist *list = NULL;
  if (request.headers.size() > 0) {
    typedef std::map<string, string>::iterator it_type;
    for(it_type iterator = request.headers.begin(); iterator != request.headers.end(); iterator++) {
      string header = iterator->first + ": " + iterator->second;
      list = curl_slist_append(list, header.c_str());
    }
  }
  
  /* no expect header. not required but may be beneficial in some cases, but I don't need it. */
  /* todo: allow this to be configurable. */
  list = curl_slist_append(list, "Expect:");
  curl_easy_setopt (curl_handle, CURLOPT_HTTPHEADER, list);

  /* send body data. Illegal to send body data with a GET request (even though libcurl will send it). */
  if (request.method != "GET") {
    if (request.bodyData.size() > 0) {
      curl_easy_setopt(curl_handle, CURLOPT_POSTFIELDS, request.bodyData.c_str());
    }
  }

  /* send all data to this function */
  curl_easy_setopt(curl_handle, CURLOPT_WRITEFUNCTION, write_callback);
  curl_easy_setopt(curl_handle, CURLOPT_WRITEDATA, &response);

  /* we want the headers to this file handle */
  curl_easy_setopt(curl_handle, CURLOPT_HEADERFUNCTION, header_callback);
  curl_easy_setopt(curl_handle, CURLOPT_HEADERDATA, &response.headers);
  
  /* set error buffer */
  char errorBuffer[CURL_ERROR_SIZE];
  curl_easy_setopt(curl_handle, CURLOPT_ERRORBUFFER, errorBuffer);

  /* no progress meter please */
  curl_easy_setopt(curl_handle, CURLOPT_NOPROGRESS, 1L);

  /* custom user agent */
  if (!request.userAgent.empty()) {
    curl_easy_setopt(curl_handle, CURLOPT_USERAGENT, request.userAgent.c_str());
  }

  /* proxy support */
  if (!request.proxy.empty()) {
    curl_easy_setopt(curl_handle, CURLOPT_PROXY, request.proxy.c_str());
  }

  /* follow redirects? */
  if (request.maxRedirects > 0) {
    curl_easy_setopt(curl_handle, CURLOPT_FOLLOWLOCATION, 1L);
    curl_easy_setopt(curl_handle, CURLOPT_MAXREDIRS, request.maxRedirects);
  }
  
  /* do not verify peer or host */
  curl_easy_setopt(curl_handle, CURLOPT_SSL_VERIFYPEER, 0L);
  curl_easy_setopt(curl_handle, CURLOPT_SSL_VERIFYHOST, 0L);

  /* CVE-2013-0249 */
  curl_easy_setopt(curl_handle, CURLOPT_PROTOCOLS, CURLPROTO_HTTP | CURLPROTO_HTTPS);
  curl_easy_setopt(curl_handle, CURLOPT_REDIR_PROTOCOLS, CURLPROTO_HTTP | CURLPROTO_HTTPS);

  /* let's do it */
  CURLcode res = curl_easy_perform(curl_handle);
  if (res != 0) {
    response.error = errorBuffer;
  }

  /* lets get some stats on the request */
  curl_easy_getinfo(curl_handle, CURLINFO_TOTAL_TIME, &response.totalTime);
  curl_easy_getinfo(curl_handle, CURLINFO_NAMELOOKUP_TIME, &response.dnsTime);
  curl_easy_getinfo(curl_handle, CURLINFO_PRETRANSFER_TIME, &response.preTransferTime);
  curl_easy_getinfo(curl_handle, CURLINFO_CONNECT_TIME, &response.connectTime);
  curl_easy_getinfo(curl_handle, CURLINFO_STARTTRANSFER_TIME, &response.startTransferTime);

  /* get status code */
  response.statusCode = 0;
  curl_easy_getinfo(curl_handle, CURLINFO_RESPONSE_CODE, &response.statusCode);

  /* cleanup curl handle */
  curl_easy_cleanup(curl_handle);

  return response;
}

size_t CurlClient::header_callback(void *buffer, size_t size, size_t nmemb, void *userp) {
  int result = size * nmemb;

  std::string data = (char*) buffer;
  std::string key, value;

  size_t p = data.find(":");

  if((int)p > 0) {
    key = data.substr(0, p);
    value = data.substr(p + 2, (result - key.size() - 4)); //4 = 2 (aka ": " between header name and value) + carriage return
    
    map<string, string> *headers = (map<string, string>*)userp;
    headers->insert(pair<string,string>(key, value));
  }

  return result;
}

size_t CurlClient::write_callback(void *contents, size_t size, size_t nmemb, void *userp) {
  int result = size * nmemb;

  if (result > 0) {
    curl_response *response = (curl_response*)userp;
    string data = string((char*)contents, result);

    response->data = response->data + data;
  }

  return result;
}
Something went wrong with that request. Please try again.