c++ - libcurl C++ 在 POSTing JSON 时出现段错误

标签 c++ http libcurl

免责声明:我不是要求任何人调试这段代码,我更想知道是否有人发现我不正确地使用 libcurl,因为据我所知,我完全遵循文档。

问题出在 MakeRequest() 方法中。在curl_easy_perform()中,我得到了std输出

* About to connect() to dynamodb.us-east-1.amazonaws.com port 80 (#0)
*   Trying 72.21.195.244... * connected

然后出现段错误。

这是堆栈跟踪:

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<testing::Test, void>() at gtest-all.cc:3,562 0x46502f 
    testing::internal::HandleExceptionsInMethodIfSupported<testing::Test, void>() at gtest-all.cc:3,598 0x4602f6    
    <...more frames...> 

这是有问题的代码。

#include "http/curl/CurlHttpClient.h"
#include "http/standard/StandardHttpResponse.h"
#include "utils/StringUtils.h"
#include <curl/curl.h>
#include <sstream>
#include <algorithm>
#include <functional>
#include <vector>

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& 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 << iter->first << ": " << iter->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, &CurlHttpClient::WriteData);
    curl_easy_setopt(singleRequestHandle, CURLOPT_WRITEDATA, response);
    curl_easy_setopt(singleRequestHandle, CURLOPT_HEADERFUNCTION, &CurlHttpClient::WriteHeader);
    curl_easy_setopt(singleRequestHandle, CURLOPT_HEADERDATA, response);

    if (request.GetContentBody() != NULL)
    {
      curl_easy_setopt(singleRequestHandle, CURLOPT_POSTFIELDSIZE, request.GetContentBody()->tellp());
      curl_easy_setopt(singleRequestHandle, CURLOPT_READFUNCTION, &CurlHttpClient::ReadBody);
      curl_easy_setopt(singleRequestHandle, CURLOPT_READDATA, &request);
    }

    curl_easy_setopt(singleRequestHandle, CURLOPT_VERBOSE, 1L);
    curl_easy_perform(singleRequestHandle);

    int responseCode;
    curl_easy_getinfo(singleRequestHandle, CURLINFO_RESPONSE_CODE, &responseCode);
    response->SetResponseCode((HttpResponseCode) responseCode);

    char* contentType = NULL;
    curl_easy_getinfo(singleRequestHandle, CURLINFO_CONTENT_TYPE, &contentType);
    response->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->GetResponseBody())
    {
      std::streambuf* strBuffer = new std::stringbuf;
      response->SetResponseBody(new std::iostream(strBuffer));
    }

    int sizeToWrite = size * nmemb;
    response->GetResponseBody()->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<std::string> 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->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<std::iostream> outputStream = request->GetContentBody();

  if (outputStream != NULL && size * nmemb)
  {
    size_t written = outputStream->readsome(ptr, size * nmemb);
    return written;
  }

  return 0;
}

这里是 CurlHttpClient 的定义供引用:

//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& 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;     
};

最佳答案

我在代码中看到的一个明确的问题是

curl_easy_setopt(requestHandle, CURLOPT_HTTPPOST, 1);

CURLOPT_HTTPPOST需要一个指向 struct curl_httppost 类型的结构的指针。传递 1 创建一个悬空指针。您可能想使用 CURLOPT_POST相反。

关于c++ - libcurl C++ 在 POSTing JSON 时出现段错误,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/25173691/

相关文章:

python - pycurl 安装 :( already have min. libcurl 版本

c++ - curl_easy_perform 在 URL 不正确时崩溃

c++ - 帮助解析S-Expression

python - 对于大于 3 x 3 的尺寸,OpenCV 的 Sobel 滤波器的核系数是多少?

c++ - 24 位图像中有多少种颜色组合

java - 同时为 HTTP 和 WS 客户端提供服务

java - HttpServletRequest 完成 URL

c - 检测 http header 的结尾\r\n\r\n

c++ - curl 回调未返回相同数量的字节

C++:存储/记住模板类的类型