text: /*************************************************************************
   * libjson-rpc-cpp
   *************************************************************************
   * @file    httpclient.cpp
   * @date    02.01.2013
   * @author  Peter Spiess-Knafl <dev@spiessknafl.at>
   * @license See attached LICENSE.txt
   ************************************************************************/
  
  #include "httpclient.h"
  #include <cstdlib>
  #include <curl/curl.h>
  #include <string.h>
  #include <string>
  
  #include <iostream>
  
  using namespace jsonrpc;
  
  class curl_initializer {
  public:
    curl_initializer() { curl_global_init(CURL_GLOBAL_ALL); }
    ~curl_initializer() { curl_global_cleanup(); }
  };
  
  // See here: http://curl.haxx.se/libcurl/c/curl_global_init.html
  static curl_initializer _curl_init = curl_initializer();
  
  /**
   * taken from
   * http://stackoverflow.com/questions/2329571/c-libcurl-get-output-into-a-string
   */
  struct string {
    char *ptr;
    size_t len;
  };
  
  static size_t writefunc(void *ptr, size_t size, size_t nmemb,
                          struct string *s) {
    size_t new_len = s->len + size * nmemb;
    s->ptr = (char *)realloc(s->ptr, new_len + 1);
    memcpy(s->ptr + s->len, ptr, size * nmemb);
    s->ptr[new_len] = '\0';
    s->len = new_len;
    return size * nmemb;
  }
  
  void init_string(struct string *s) {
    s->len = 0;
    s->ptr = static_cast<char *>(malloc(s->len + 1));
    s->ptr[0] = '\0';
  }
  
  HttpClient::HttpClient(const std::string &url) : url(url) {
    this->timeout = 10000;
    curl = curl_easy_init();
  }
  
  HttpClient::~HttpClient() { curl_easy_cleanup(curl); }
  
  void HttpClient::SendRPCMessage(const std::string &message,
                                  std::string &result) {
  
    curl_easy_setopt(curl, CURLOPT_NOSIGNAL, 1);
    curl_easy_setopt(curl, CURLOPT_URL, this->url.c_str());
    curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, writefunc);
  
    CURLcode res;
  
    struct string s;
    init_string(&s);
  
    struct curl_slist *headers = NULL;
  
    for (std::map<std::string, std::string>::iterator header =
             this->headers.begin();
         header != this->headers.end(); ++header) {
      headers = curl_slist_append(
          headers, (header->first + ": " + header->second).c_str());
    }
  
    headers = curl_slist_append(headers, "Content-Type: application/json");
    headers = curl_slist_append(headers, "charsets: utf-8");
  
    curl_easy_setopt(curl, CURLOPT_POSTFIELDS, message.c_str());
    curl_easy_setopt(curl, CURLOPT_WRITEDATA, &s);
    curl_easy_setopt(curl, CURLOPT_HTTPHEADER, headers);
    curl_easy_setopt(curl, CURLOPT_TIMEOUT_MS, timeout);
  
    res = curl_easy_perform(curl);
  
    result = s.ptr;
    free(s.ptr);
    curl_slist_free_all(headers);
    if (res != CURLE_OK) {
      std::stringstream str;
      str << "libcurl error: " << res;
  
      if (res == 7)
        str << " -> Could not connect to " << this->url;
      else if (res == 28)
        str << " -> Operation timed out";
      throw JsonRpcException(Errors::ERROR_CLIENT_CONNECTOR, str.str());
    }
  
    long http_code = 0;
    curl_easy_getinfo(curl, CURLINFO_RESPONSE_CODE, &http_code);
  
    if (http_code / 100 != 2) {
      throw JsonRpcException(Errors::ERROR_RPC_INTERNAL_ERROR, result);
    }
  }
  
  void HttpClient::SetUrl(const std::string &url) { this->url = url; }
  
  void HttpClient::SetTimeout(long timeout) { this->timeout = timeout; }
  
  void HttpClient::AddHeader(const std::string &attr, const std::string &val) {
    this->headers[attr] = val;
  }
  
  void HttpClient::RemoveHeader(const std::string &attr) {
    this->headers.erase(attr);
  }
  