Как хранить отправленные/полученные данные с помощью libcurl

#c #curl #libcurl #void-pointers

Вопрос:

Я пытаюсь реализовать некоторые функции curl и curlcpp для небольшого проекта.

До сих пор я реализовал несколько функций, но теперь я хочу добавить функциональность. Идея состоит в том, чтобы хранить в буфере отправленные и полученные данные, чтобы позже я мог получить доступ:

  • Отправленные Данные
  • Отправленные заголовки
  • Полученные Данные
  • Полученные заголовки

Я знаю, что есть функция CURLOPT_WRITEFUNCTION, но это работает только для данных ответа, и мне тоже нужны выходные данные/заголовки. Функция CURLOPT_DEBUGFUNCTION выглядит так, как будто она работает для меня, но я не могу настроить ее на CPP.

Вот пример кода моего класса:

 class CurlCPPClient
{
    private:
        ...
        int trace_data(CURL *handle, curl_infotype type, char *data, size_t size, void *userptr);
        curl::curl_easy curl_easy;
        std::string raw_data;
    public:
        ...
}

CurlCPPClient::CurlCPPClient()
{
    curl_easy.add<CURLOPT_DEBUGFUNCTION>(this->trace_data);
}

int CurlCPPClient::trace_data(CURL *handle, curl_infotype type, char *data, size_t size, void *userptr) 
{
  std::string frame_info(data);

  switch(type)
  {
    case CURLINFO_HEADER_OUT:
    case CURLINFO_DATA_OUT:
      raw_data  = frame_info;
      break;
    case CURLINFO_HEADER_IN:
    case CURLINFO_DATA_IN:
      raw_data  = frame_info;
      break;
    default:
      break;
  }

  return 0;
}
 

У меня проблемы с компилятором при установке указателя функции на trace_data. Я получаю «ошибка C3867» и «ошибка C2228» с помощью: this->trace_data, this.trace_data, trace_data.
Если я не использую trace_data в качестве метода своего класса, я могу вызвать его, но я не могу сохранить информацию о члене, чтобы получить к ней доступ позже в другой части класса.

Ответ №1:

libcurl ожидает автономные функции в стиле C для своих обратных вызовов. Вы не можете использовать метод нестатического класса для обратного вызова.

Объявите свой trace_data() метод статическим. Вы можете использовать CURLOPT_DEBUGDATA для передачи this указателя CurlCPPClient объекта в параметр метода userptr .

 class CurlCPPClient
{
    private:
        ...
        static int trace_data(CURL *handle, curl_infotype type, char *data, size_t size, void *userptr);
        curl::curl_easy curl_easy;
        std::string raw_data;
    public:
        ...
}

CurlCPPClient::CurlCPPClient()
{
    curl_easy.add<CURLOPT_DEBUGFUNCTION>(amp;CurlCPPClient::trace_data);
    curl_easy.add<CURLOPT_DEBUGDATA>(this);
}

int CurlCPPClient::trace_data(CURL *handle, curl_infotype type, char *data, size_t size, void *userptr) 
{
  CurlCPPClient *pThis = static_cast<CurlCPPClient*>(userptr);
  std::string frame_info(data, size);

  switch(type)
  {
    case CURLINFO_HEADER_OUT:
    case CURLINFO_DATA_OUT:
      pThis->raw_data  = frame_info;
      break;
    case CURLINFO_HEADER_IN:
    case CURLINFO_DATA_IN:
      pThis->raw_data  = frame_info;
      break;
    default:
      break;
  }

  return 0;
}
 

В качестве альтернативы используйте CURLOPT_DEBUGDATA для передачи только raw_data элемента в обратный вызов:

 class CurlCPPClient
{
    private:
        ...
        static int trace_data(CURL *handle, curl_infotype type, char *data, size_t size, void *userptr);
        curl::curl_easy curl_easy;
        std::string raw_data;
    public:
        ...
}

CurlCPPClient::CurlCPPClient()
{
    curl_easy.add<CURLOPT_DEBUGFUNCTION>(amp;CurlCPPClient::trace_data);
    curl_easy.add<CURLOPT_DEBUGDATA>(amp;raw_data);
}

int CurlCPPClient::trace_data(CURL *handle, curl_infotype type, char *data, size_t size, void *userptr) 
{
  std::string *pRawData = static_cast<std::string*>(userptr);
  std::string frame_info(data, size);

  switch(type)
  {
    case CURLINFO_HEADER_OUT:
    case CURLINFO_DATA_OUT:
      *pRawData  = frame_info;
      break;
    case CURLINFO_HEADER_IN:
    case CURLINFO_DATA_IN:
      *pRawData  = frame_info;
      break;
    default:
      break;
  }

  return 0;
}