プロキシは 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 呼び出しは渡されたバイト数を使います。コールバックのデータは NUL 終端されておらず、画像にはゼロバイトが含まれ得ます。strlen で測ると本文の一部を失います。応答は異なるサイズの多数のコールバック呼び出しに分かれて届くこともあります。

消費したバイト数を返すとそのチャンクが受理されます。異なる数を返すと書き込みエラーで転送が中断されます。例外ガードはメモリ確保の失敗が C コールバックの境界を越えて抜け出すのを防ぎます。呼び出し側は response を完全なファイルとして扱う前に、転送結果を必ず確認する必要があります。

転送が終わるまで文字列を生かしておきます。非同期のソケット書き込みがその後内容を転送する場合は、その書き込みも完了するまでバイトを生かしておきます。大きな応答では、本文全体を蓄積するより、上限付きのストリーミング構成が適しています。

関連記事