小林と申します。
WININET(CInternetxxx)を用いたHttpについての質問です。

【現象】
WinInet API(正確にはMFCのCHttpほげほげクラス)を用いてWebサーバと
データの送受信をするプログラムを書いているのですが、Proxy経由の
POST時の動作で認証が入った場合にうまく動作してくれません。

具体的にはクライアント-Proxy間でPOSTのヘッダを受けてすぐProxyが
リプライを返しており、クライアント側はこれを読まずに残りのボディを
送信しようとした結果、Proxyからコネクションを切られてしまいます。

クライアントからのリクエスト発行順序としては大雑把に

pServer = pSession->GetHttpConnection(server, port)
//プロクシの指定など
while(1) {
pFile = pServer->OpenRequest(HTTP_VERB_POST, uri, ...);
//ヘッダ付加など
// (1)
try {
pFile->SendRequestEx(content-length);
// (2)
//データを読んでpFile->Write();繰り返し (A)
pFile->EndRequest();
} catch(CInternetException *pEx) {
//SSL関係,FORCE_RETRY例外捕捉
// (3)
}
pFile->QueryInfoStatusCode(dwRet);
if (dwRet == HTTP_STATUS_DENIED)
{
//サーバ認証情報設定

} else if(dwRet == HTTP_STATUS_PROXY_AUTH_REQ) {
//Proxy認証情報設定
} else {
break;
}
}

という流れで行っています。
認証情報はあらかじめ設定せず、SendRequestの結果でSetOptionして
Authorizationヘッダを生成させて再リクエストという形ですね(あらかじめ設
定してあってもAPI内部で同様に振舞うようですが)。
このとき、Proxy-Authorization:ヘッダが必要なProxyを介するときに、(A)
の部分でERROR_INTERNET_CONNECTION_ABORTEDによる例外が発生しています。

RFC2616のSec8.2.2によると
リクエストボディを持つ要求を送るクライアントは
・リクエスト送信中エラーステータスを監視すべきである。
・エラーステータスを受信した場合すぐ送信をとめるべきである。
・Content-Lengthを送信した場合は、接続をきらなければならない。

Proxy-Authenticate: を貰わないと認証手順がわからず、
そのためにBodyを送りきらなきゃいけないというのは無駄すぎなので
こうあるべきだとは思うのですが、ではそのように振舞おうとすると
SendRequestExからEndRequestまでの間でQueryInfoStatusCodeが発行
できればよいのですが、
・(2)でQueryInfoStatusCodeを発行->APIエラー
・(3)の例外捕捉時にステータス確認->APIエラー
・(3)でEndRequest()後ステータス確認->EndRequest()で例外

データ(90kb程度)をあらかじめメモリ展開し、SendRequestEx-EndRequestを
SendRequestに変更したところ、15分ほど待たされた挙句に
ERROR_INTERNET_CONNECTION_ABORTEDによる例外が発生しました。
#RFC2616 8.2.4 に従ってリトライしていた?

非同期モードというのもあるため、こちらならできるかと、APIから作成
して見ました(MFCは対応していない)が、EndRequest発行まではデータの読
み出しができないのは変わらないようでした。
InternetGetLastResponseInfo()も試してみましたが、こちらは
DWORD dwerr;
char buff[4096];
DWORD len= 4096;
InternetGetLastResponseInfo(&dwerr, buff, &len);
のように使っているのですが、Len=0しか帰ってきません。

リクエスト中にリプライを受信する方法についてはほぼお手上げの状態になっ
ています。

1セッションで複数リクエストを行うことから、毎回*Authenticate:を受けて
*Authorization:をつけたりクエストを再発行するというのも無駄な気もしま
すし、アプリケーションの中ではGETがまず発生しますので発行した
*Authorization:ヘッダを保存してしまって2回目以降は直接リクエストヘッダ
に付加してやるというのも1つの手かと思うのですが、

InternetQueryInfoのフラグはあるにも関わらず、実際発行しても 
取得できず、RAW_HEADERSを確認すると、該当ヘッダは削除されているとい
う状態です。
#まあ、とれたらとれたで問題のような気もします。

という形で、*Authorization:ヘッダ自体取得ができていません。

BASIC認証ヘッダくらいなら自前で生成できるのですが、これは認証方式が
BASICに固定されてしまい、WWW-Authenticate:NTLMしか許されないような場合
に利用できなくなるのが気になります。

【質問事項】

1.POST時のエラーステータスメッセージのハンドリングを行う
  方法はないでしょうか。より正確には、リクエスト中にレスポンスを監視
  し、読み出す方法を期待しています。
2.その他WININET APIにてPOSTを扱う時の情報はないでしょうか。
3.リクエスト-リプライが完了したときそのProxy-Authorization:ヘッダを
  取得できるのであれば。その方法を教えてください。
4.その他現象を回避する妙案があればご教授願います。
5.本論からずれますが、Content-Lengthが指定されたPOSTにてBODYを
  継続して送信された場合に接続を閉じるProxyの動作は仕様として
  正しいのでしょうか。DoS対策のため必要な気もしますが、RFC上は
 クライアントから切ることを期待しているように読めました。

【環境】
OS WindowsNT4.0SP6
IE 5.0.2314.1003
VC6 SP4
Proxy Squid 2.3.STABLE2(らしい・・・ヘッダ情報から)
Delegate 7.1.1でも同じ(CONNECTION_RESETでしたが)でした。

【おまけ】
ついでに気になっていることをいくつか質問しておこう(^^;

HTTP1.1における100番台のステータスコードのハンドリングはAPI|MFCが勝手
に行ってくれるのでしょうか?
これがどのような場合に返却されるのか今一つわかっていません。
#ProxyでConnection:Keep-aliveにした場合?
テストしている環境ではこれを返答させることができておらず、プロトコル上
載ってきたパターンを見たことがないためどのように振舞えばよいのかわかり
ません。クラス仕様的には1リクエスト1リプライでしか処理できなさそうに見
えます。
-- 
Norihiro Kobayashi mailto:n...@yha.att.ne.jp