title: libcurl c++ segfault on POSTing JSON
body: <p>Disclaimer: I am not asking anyone to debug this code, I am more interested to know if anyone sees that I am using libcurl improperly, because as far as I can tell, I am following the documentation exactly.</p>
  
  <p>The problem is in the MakeRequest() method. At curl_easy_perform(), I get std output of</p>
  
  <pre><code>* About to connect() to dynamodb.us-east-1.amazonaws.com port 80 (#0)
  *   Trying 72.21.195.244... * connected
  </code></pre>
  
  <p>Then a segfault.</p>
  
  <p>Here is the stack trace:</p>
  
  <pre><code>Thread [1] 30267 [core: 0] (Suspended : Signal : SIGSEGV:Segmentation fault)    
      Curl_getformdata() at 0x7ffff79069bb    
      Curl_http() at 0x7ffff790b178   
      Curl_do() at 0x7ffff791a298 
      Curl_do_perform() at 0x7ffff7925457 
      CurlHttpClient::MakeRequest() at CurlHttpClient.cpp:91 0x7ffff7ba17f5   
      AWSClient::MakeRequest() at AWSClient.cpp:54 0x7ffff7bbac4d 
      DynamoDbV2Client::GetItem() at DynamoDbV2Client.cpp:34 0x7ffff7bb7380   
      GetItemResultTest_TestLiveRequest_Test::TestBody() at GetItemResultTest.cpp:88 0x43db5a 
      testing::internal::HandleSehExceptionsInMethodIfSupported&lt;testing::Test, void&gt;() at gtest-all.cc:3,562 0x46502f 
      testing::internal::HandleExceptionsInMethodIfSupported&lt;testing::Test, void&gt;() at gtest-all.cc:3,598 0x4602f6    
      &lt;...more frames...&gt; 
  </code></pre>
  
  <p>Here is the code in question.</p>
  
  <pre><code>#include "http/curl/CurlHttpClient.h"
  #include "http/standard/StandardHttpResponse.h"
  #include "utils/StringUtils.h"
  #include &lt;curl/curl.h&gt;
  #include &lt;sstream&gt;
  #include &lt;algorithm&gt;
  #include &lt;functional&gt;
  #include &lt;vector&gt;
  
  bool CurlHttpClient::isInit = false;
  
  void SetOptCodeForHttpMethod(CURL* requestHandle, HttpMethod method)
  {
    switch (method)
    {
    case GET:
      curl_easy_setopt(requestHandle, CURLOPT_HTTPGET, 1);
      break;
    case POST:
      curl_easy_setopt(requestHandle, CURLOPT_HTTPPOST, 1);
      break;
    case PUT:
      curl_easy_setopt(requestHandle, CURLOPT_PUT, 1);
      break;
    default:
      curl_easy_setopt(requestHandle, CURLOPT_CUSTOMREQUEST, "DELETE");
      break;
    }
  }
  
  CurlHttpClient::CurlHttpClient()
  {
    if (!isInit)
    {
      isInit = true;
      curl_global_init(CURL_GLOBAL_ALL);
    }
  }
  
  CurlHttpClient::~CurlHttpClient()
  {
  }
  
  HttpResponse* CurlHttpClient::MakeRequest(const HttpRequest&amp; request) const
  {
    struct curl_slist* headers = NULL;
  
    std::stringstream headerStream;
    HeaderValueCollection requestHeaders = request.GetHeaders();
  
    for (HeaderValueCollection::iterator iter = requestHeaders.begin();
        iter != requestHeaders.end(); ++iter)
    {
      headerStream.str("");
      headerStream &lt;&lt; iter-&gt;first &lt;&lt; ": " &lt;&lt; iter-&gt;second;
      headers = curl_slist_append(headers, headerStream.str().c_str());
    }
  
    CURL* singleRequestHandle = curl_easy_init();
    HttpResponse* response = NULL;
  
    if (singleRequestHandle)
    {
      if (headers)
      {
        curl_easy_setopt(singleRequestHandle, CURLOPT_HTTPHEADER, headers);
      }
  
      if(request.GetMethod() == HttpMethod::POST)
      {
        curl_easy_setopt(singleRequestHandle, CURLOPT_POSTFIELDS, request.GetUri().GetFormParameters().c_str());
      }
  
      response = new StandardHttpResponse(request);
  
      SetOptCodeForHttpMethod(singleRequestHandle, request.GetMethod());
      std::string url = request.GetURIString(false);
      curl_easy_setopt(singleRequestHandle, CURLOPT_URL, url.c_str());
      curl_easy_setopt(singleRequestHandle, CURLOPT_WRITEFUNCTION, &amp;CurlHttpClient::WriteData);
      curl_easy_setopt(singleRequestHandle, CURLOPT_WRITEDATA, response);
      curl_easy_setopt(singleRequestHandle, CURLOPT_HEADERFUNCTION, &amp;CurlHttpClient::WriteHeader);
      curl_easy_setopt(singleRequestHandle, CURLOPT_HEADERDATA, response);
  
      if (request.GetContentBody() != NULL)
      {
        curl_easy_setopt(singleRequestHandle, CURLOPT_POSTFIELDSIZE, request.GetContentBody()-&gt;tellp());
        curl_easy_setopt(singleRequestHandle, CURLOPT_READFUNCTION, &amp;CurlHttpClient::ReadBody);
        curl_easy_setopt(singleRequestHandle, CURLOPT_READDATA, &amp;request);
      }
  
      curl_easy_setopt(singleRequestHandle, CURLOPT_VERBOSE, 1L);
      curl_easy_perform(singleRequestHandle);
  
      int responseCode;
      curl_easy_getinfo(singleRequestHandle, CURLINFO_RESPONSE_CODE, &amp;responseCode);
      response-&gt;SetResponseCode((HttpResponseCode) responseCode);
  
      char* contentType = NULL;
      curl_easy_getinfo(singleRequestHandle, CURLINFO_CONTENT_TYPE, &amp;contentType);
      response-&gt;SetContentType(contentType);
      curl_easy_cleanup(singleRequestHandle);
    }
  
    if (headers)
    {
      curl_slist_free_all(headers);
    }
  
    return response;
  }
  
  size_t CurlHttpClient::WriteData(char *ptr, size_t size, size_t nmemb, void* userdata)
  {
    if (ptr)
    {
      HttpResponse* response = (HttpResponse*)userdata;
      if (!response-&gt;GetResponseBody())
      {
        std::streambuf* strBuffer = new std::stringbuf;
        response-&gt;SetResponseBody(new std::iostream(strBuffer));
      }
  
      int sizeToWrite = size * nmemb;
      response-&gt;GetResponseBody()-&gt;write(ptr, sizeToWrite);
  
      return sizeToWrite;
    }
  
    return 0;
  }
  
  size_t CurlHttpClient::WriteHeader(char *ptr, size_t size, size_t nmemb, void* userdata)
  {
    if (ptr)
    {
      HttpResponse* response = (HttpResponse*)userdata;
      std::string headerLine(ptr);
      std::vector&lt;std::string&gt; keyValuePair = StringUtils::Split(headerLine, ':');
  
      if (keyValuePair.size() == 2)
      {
        std::string headerName = keyValuePair[0];
        headerName = StringUtils::Trim(headerName);
  
        std::string headerValue = keyValuePair[1];
        headerValue = StringUtils::Trim(headerValue);
  
        response-&gt;AddHeader(headerName, headerValue);
      }
      return size * nmemb;
    }
  
    return 0;
  }
  
  size_t CurlHttpClient::ReadBody(char* ptr, size_t size, size_t nmemb, void* userdata)
  {
    HttpRequest* request = (HttpRequest*)userdata;
    std::shared_ptr&lt;std::iostream&gt; outputStream = request-&gt;GetContentBody();
  
    if (outputStream != NULL &amp;&amp; size * nmemb)
    {
      size_t written = outputStream-&gt;readsome(ptr, size * nmemb);
      return written;
    }
  
    return 0;
  }
  </code></pre>
  
  <p>For reference here is the definition for CurlHttpClient:</p>
  
  <pre><code>//Curl implementation of an http client. Right now it is only synchronous.
  class CurlHttpClient : public HttpClient
  {  
    public: 
     //Creates client, intializes curl handle if it hasn't been created already.
     CurlHttpClient();
     //cleans up curl lib
     virtual ~CurlHttpClient();
     //Makes request and recieves response synchronously
     virtual HttpResponse* MakeRequest(const HttpRequest&amp; request) const;
  
    private:    
      //Callback to read the content from the content body of the request
      static size_t ReadBody(char* ptr, size_t size, size_t nmemb, void* userdata);
      //callback to write the content from the response to the response object
      static size_t WriteData( char* ptr, size_t size, size_t nmemb, void* userdata);
      //callback to write the headers from the response to the response
      static size_t WriteHeader( char* ptr, size_t size, size_t nmemb, void* userdata);
  
      //init flag.
      static bool isInit;     
  };
  </code></pre>