TL;DR: トピックが言うように - マルチパート ポスト ボディを送信する必要があるのは、接続の確立後に受信した応答ヘッダーを処理した後のみです。
libcurl のドキュメントによると、CURLOPT_HEADERFUNCTION は、ヘッダー データを受信するとすぐに libcurl によって呼び出されます。 しかし、簡単な調査の後、これは起こりませんでした。
再現方法:
コールバック:
size_t HeaderCallback(void *data, size_t size, size_t nmemb, void *userdata) {
cout << __FUNCTION__ << " " << data << '\n';
return size*nmemb;
}
static int Trace(CURL *handle, curl_infotype type, char *data, size_t size, void *userp) {
cout << __FUNCTION__ << " " <<timestamp<< ' ' << data << endl;
return 0;
}
static size_t ReadFromStateCallBack(void* dst, size_t size, size_t nmemb, void* state) {
cout << __FUNCTION__ << " " <<timestamp<< endl;
return READ();
}
リクエストの短い本文:
CURL *curl = curl_easy_init();
curl_slist* h = NULL;
const char * url = "https://upload.box.com/api/2.0/files/content";
curl_httppost *formpost=NULL;
curl_httppost *lastptr=NULL;
curl_formadd(&formpost,&lastptr,
CURLFORM_COPYNAME, "filename",
CURLFORM_CONTENTTYPE, "text/plain",
CURLFORM_FILENAME, "uploadthis.txt",
CURLFORM_STREAM, (void*)state,
CURLFORM_CONTENTSLENGTH, GetFileSize(),
CURLFORM_END);
curl_formadd(&formpost, &lastptr,
CURLFORM_COPYNAME, "parent_id",
CURLFORM_COPYCONTENTS, "0",
CURLFORM_END);
curl_easy_setopt(curl, CURLOPT_VERBOSE, 1L);
curl_easy_setopt(curl, CURLOPT_DEBUGFUNCTION, Trace);
curl_easy_setopt(curl, CURLOPT_URL, url);
curl_easy_setopt(curl, CURLOPT_POST, 1L);
curl_easy_setopt(curl, CURLOPT_HEADERFUNCTION, HeaderCallback);
curl_easy_setopt(curl, CURLOPT_READFUNCTION, ReadFromStateCallBack);
curl_easy_setopt(curl, CURLOPT_READDATA, state);
curl_easy_setopt(curl, CURLOPT_HTTPPOST, formpost);
curl_easy_setopt(curl, CURLOPT_ERRORBUFFER, err_buf);
h = curl_slist_append(h, "Expect: 100-continue");
h = curl_slist_append(h, "Authorization: Bearer WRONGTOKEN");
curl_easy_setopt(curl, CURLOPT_HTTPHEADER, h);
curl_easy_perform(curl);
curl_formfree(formpost);
そして、次のログを受け取ることができます (c++11 クロノエポックからの多数の時間):
タイプ [0] データ: [SSL 関連のもの]
タイプ [0] データ: [100 を待って終了-続行]
ReadFromStateCallBack 1455532592078426519
...
ReadFromStateCallBack 1455532592507779449
HeaderCallback 1455532592937695923 [HTTP/1.1 100 継続]
HeaderCallback 1455532592937713786 [日付: 2016 年 2 月 15 日月曜日 10:36:32 GMT]
タイプ [0] データ: [サーバー ATS はブラックリストに登録されていません]
HeaderCallback: 1455532593030759917 [HTTP/1.1 401 Unauthorized]
ヘッダーからの追加情報
また、ご覧のとおり、libcurl は 100-continue ヘッダーを処理する必要がありますが、ヘッダーを処理するためのコールバックはデータの送信後にのみ呼び出されます。
また、必要なすべてのヘッダーが受信されたようです。tcpdump の例:
13:36:30.425361 IP 192.168.1.70.41895 > 74.112.184.85.https: フラグ [S]、seq 164841209、win 29200、オプション [mss 1460、sackOK、TS val 2164947 ecr 0、nop、wscale 7]、長さ 0
13:36:30.639293 IP 74.112.184.85.https > 192.168.1.70.41895: フラグ [S.]、seq 1336121630、ack 164841210、win 14480、オプション [mss 1460、sackOK、TS val 2083933652 ]、長さ 0
13:36:30.639337 IP 192.168.1.70.41895 > 74.112.184.85.https: フラグ [.]、ack 1、win 229、オプション [nop、nop、TS val 2165000 ecr 2083933652]、長さ 0
13:36:30.640031 IP 192.168.1.70.41895 > 74.112.184.85.https: フラグ [P.]、seq 1:297、ack 1、win 229、オプション [nop、nop、TS val 2165000 ecr 2083933652]、長さ 296
13:36:30.853750 IP 74.112.184.85.https > 192.168.1.70.41895: フラグ [.]、ack 297、win 122、オプション [nop、nop、TS val 2083933866 ecr 2165000]、長さ 0
13:36:30.861507 IP 74.112.184.85.https > 192.168.1.70.41895: フラグ [P.]、seq 1:2690、ack 297、win 122、オプション [nop、nop、TS val 2083933874 ecr 2165000]、長さ 2689
^^^^^ - ここです。
13:36:30.861524 IP 192.168.1.70.41895 > 74.112.184.85.https: フラグ [.]、ack 2690、win 271、オプション [nop、nop、TS val 2165056 ecr 2083933874]、長さ 0
13:36:30.862654 IP 192.168.1.70.41895 > 74.112.184.85.https: フラグ [P.]、seq 297:423、ack 2690、win 271、オプション [nop、nop、TS val 2165056 ecr 2083933874]、長さ 126
13:36:31.076949 IP 74.112.184.85.https > 192.168.1.70.41895: フラグ [P.]、seq 2690:2741、ack 423、win 122、オプション [nop、nop、TS val 2083934090 ecr 2165056]、長さ 51
13:36:31.077286 IP 192.168.1.70.41895 > 74.112.184.85.https: フラグ [P.]、seq 423:693、ack 2741、win 271、オプション [nop、nop、TS val 2165110 ecr 2083934090]、長さ 270
13:36:31.330808 IP 74.112.184.85.https > 192.168.1.70.41895: フラグ [.]、ack 693、勝利 130、オプション [nop、nop、TS val 2083934344 ecr 2165110]、長さ 0
13:36:32.078397 IP 192.168.1.70.41895 > 74.112.184.85.https: フラグ [P.]、seq 693:870、ack 2741、win 271、オプション [nop、nop、TS val 2165360 ecr 2083934344]、長さ 177
13:36:32.078533 IP 192.168.1.70.41895 > 74.112.184.85.https: フラグ [.]、seq 870:2218、ack 2741、win 271、オプション [nop、nop、TS val 2165360 ecr 2083934344]、長さ 1348
繰り返し送信データ
SSL 接続のため、-A を使用して tcpdump を表示できません。ヘッダーが提案された部分で受信されたことを確認してください。
ソフトウェア:
- libcurl(7.36)
- コンパイラ GCC(4.8.4)
PS私にとって、libcurlは[RFC 2616(8.2.4)]に対して間違った動作をしているようです( https://www.w3.org/Protocols/rfc2616/rfc2616-sec8.html )
PPS 存在する場合は同じ動作 接続: ヘッダーを閉じます。