Получение бинарных ответов libcurl в C++ std::string
Передайте std::string как контекст обратного вызова и добавляйте явные счётчики байтов при приёме бинарных данных через libcurl.
Прокси может успешно получить HTML и всё же повредить изображение при копировании его в буфер C++. Прежде чем менять протокол прокси, проверьте обратный вызов приёма и объект, передаваемый как его контекст.
CURLOPT_WRITEDATA передаёт указатель на обратный вызов записи. Без собственного обратного вызова стандартный писатель libcurl ожидает FILE *. Адрес вроде &response, где response — это std::string, имеет смысл только тогда, когда ваш обратный вызов приводит этот контекст обратно к нужному типу.
static size_t receive(char* data, size_t size,
size_t count, void* context) {
const size_t bytes = size * count;
auto* body = static_cast<std::string*>(context);
try {
body->append(data, bytes);
} catch (...) {
return 0;
}
return bytes;
}Зарегистрируйте обе половины на простом дескрипторе, используемом для передачи:
std::string response;
curl_easy_setopt(handle, CURLOPT_WRITEFUNCTION, receive);
curl_easy_setopt(handle, CURLOPT_WRITEDATA, &response);Вызов append использует переданное число байтов. Данные обратного вызова не завершаются нулём, и изображение может содержать нулевые байты; измерение через strlen потеряло бы часть тела. Ответ также может приходить через множество вызовов разного размера.
Возврат количества потреблённых байтов принимает фрагмент. Возврат другого числа прерывает передачу с ошибкой записи. Защита исключений не даёт сбою выделения памяти выйти за границу обратного вызова C; вызывающий по-прежнему должен проверить результат передачи, прежде чем считать response полным файлом.
Держите строку живой, пока передача не завершится. Если асинхронная запись в сокет затем пересылает её содержимое, держите эти байты живыми, пока и эта запись не завершится. Для больших ответов ограниченная потоковая схема предпочтительнее накопления всего тела.