[PHP-users 21225]Re: POSTデータを受け取らない場合があります

ikeda @ tsm.kddilabs.jp ikeda @ tsm.kddilabs.jp
2004年 4月 9日 (金) 15:24:55 JST


なかしま様。
こんにちわ。
池田と申します。

※既に ML を退会されておられるのかもしれませんが、
  一応、web 上からでも内容は閲覧できるので返信します。

> (1)レンタルサーバーのローカルユーザーであるため
> httpd.confをいじったり、エラーログをのぞいたりすることは
> 基本的にはできない
> (2)バージョンが、皆様には問題の発生しなかった4.3.4であること
> (3)そもそもこのスレッドでは問題の原因と理由がイマイチはっきりしない
> 
> ということで、やはり原因を突きとめ改善したいと思っています。

動作確認でご利用のブラウザが Internet Explorer であれば、原因と
思われる事に遭遇した事があります。

以前、wininet ライブラリを使用して Windows アプリを作成した折、
同様の現象に頭を抱えたことがございます。
(ブラウザの Internet Explorer は wininet ライブラリを使用して HTTP, 
HTTPS の処理を行うはずなので現象は同じと考えて良いと思います。)

その時、調べて分かった事は、、、

(a)wininet により空白のヘッダーのみの POST 要求が再送される
   http://support.microsoft.com/default.aspx?scid=kb;ja-jp;831167
(b)wininet ライブラリ(IE)は SSL 3.0 の実装が不完全
   http://support.microsoft.com/?kbid=305217

です。

まず (a) についてですが、Apache などのデフォルトでは Keep Alive の
時間が 15秒に設定されています。
ところが wininet では独自に TCPセッションを持続する仕組みが在り、これの
タイムアウト値が 60秒に設定されています。
また、wininet はサーバーよりの Keep Alive が解除されたと言う FIN 
シグナルを無視してしまいます。
ここで、クライアントは繋がっているはず、サーバーは切断されたはずと
TCPセッションの矛盾が発生してしまいます。
この状況はサーバーが Keep Alive を解除して FIN を投げた時から発生致します。
→ netstat で状態を見ると、クライアント側では CLOSE_WAIT、サーバー側では
   FIN_WAIT2(かな?)になっていると思います。

この状況下で、クライアント側(IE)からリクエストを行うと、wininet は
先ほどまで使用していた TCPセッションが生きていると思っていますから、
その TCPセッションに対してリクエストのデータをセットして、サーバーに
データを送出します。
ですがサーバー側では、その TCPセッションは既に無効になっていますので、
そのリクエストは受け付けられません。(当然サーバーのログにも残りません)
この時、wininet はどうするかと言うと、送出に失敗した TCPセッションは
消去して、新規に TCPセッションを再作成してしまい、そのまま処理を継続
しようとします。
しかも先ほど消去された TCPセッションにセットしたデータは引き継がれず、
結果として Content-Length : 0 のリクエストが再送される形になります。
サーバーのログにはこちらが残ります。

次に (b) ですが、詳しい説明はリンク先を見て頂くとして、(b) が発生した場合、
結果として無効な TCPセッションが残ってしまう現象になりますので (a) と同様
の現象が発生致します。
(リンク先に記載されている現象と今回の現象は違いますが、私は今回と同様の
現象も確認しました。)

ところで (a) については HTTP でも HTTPS でも発生しうる現象です。
では何故、HTTPS の不具合報告が多いのか?
一応、私の結論としては、サーバーに Apache を利用されている場合、HTTP に
おいては下記の設定がデフォルトで設定されている為ではないかと考えてます。

Apache における環境変数(特別な目的の環境変数)
http://www.apache.jp/docs/env.html#special

HTTPS においても同様の設定が存在しており、私のテスト環境下ではデフォルトで
設定されておりました。
恐らく mod_ssl を組み込んだ時に追加されたのだと思います。
(sslcfg.patch と言うファイルに httpd.conf の設定と同じ内容の物がございました。)

以下、Apache の httpd.conf の設定内容です。

// HTTP 用の設定
<IfModule mod_setenvif.c>
    BrowserMatch "MSIE 4\.0b2;" nokeepalive downgrade-1.0 force-response-1.0
</IfModule>

// HTTPS(mod_ssl)用の設定
<VirtualHost _default_:443>
#   SSL Protocol Adjustments:
SetEnvIf User-Agent ".*MSIE.*" \
         nokeepalive ssl-unclean-shutdown \
         downgrade-1.0 force-response-1.0
</VirtualHost>


また、IE のインターネットオプション → 詳細設定で SSL 3.0 のチェックを
外して SSL 2.0 にチェックを入れ、SSL 3.0 を使用しない様にすれば、
サーバー側は何も変更しなくても動作するようになると思います。
(ユーザーに環境設定の変更を強要してしまいますが、、、)

ですので PHP のみで処置を完結するのは、非常に困難と言わざるをえません。

以上です。

--------
池田  元




PHP-users メーリングリストの案内