毎秒1000リクエスト を捌く超高速CMS「adiary」
2007/04/30(月)Microsoft-IIS がダメダメな件(303 See Otherを無視する件)
●対象 Microsoft-IIS/5.0(Windows 2000系付属)
IE で数々のダメを露呈している MS ですが、案の定IISもダメダメでした。adiaryは、IISサーバ + perlis.dll でも動作することになっているのですが、IISサーバ + perl.exe で動かないという報告がありまして、対応外なのですが調査してみました。どうも IIS の Cookie 処理が怪しいようです。
perlis.dll だと Image::Magick を使えない*1のだそうで。試しに動作させたらメモリを食う暴走して危険でした(汗)。
303 See Otherとは何であるか
原因を説明する前に、adiaryのログイン時の動きを確認しておきましょう。
(1) | adiary/?login | login フォーム |
(2) | adiary/ | パスワード認証をして set-cookie |
(3) | adiary/?login_auth | cookieがきちんとブラウザに保存されているか確認 |
(4) | adiary/ | ログイン後の画面 |
IISだと (3) の時点で「Cookieが有効になっていません」とエラーになります。
HTTPヘッダには 303 See Other というものがありまして、これはHTTP/1.1対応ならば使えます。HTTP/1.1対応かどうかというのは、HTTPクライアントとサーバが両方対応しているときに環境変数 SERVER_PROTOCOL=HTTP/1.1 が設定されます。
adiary(というより Satsuki-system)ではリクエストを redirect するとき、SERVER_PROTOCOL を参照して適切な HTTP ヘッダを返します。というのも、ログインのような POST をリダイレクトするとき、Location ヘッダを出せばいいと思っている cgi 作者もたくさんいらっしゃるようですが、事はそう単純ではありません。
Location ヘッダを同時に出せる(出力してもいい) HTTP/1.1ヘッダ には3種類あります。
ヘッダ | 移動後のメソッド | 意味 |
---|---|---|
301 Moved Permanently | そのまま | コンテンツが永久的に移動した |
302 Found | そのまま | コンテンツの一時的な移動 |
303 See Other | GETに変更 | コンテンツの一時的な移動 |
HTTP/1.1 においては、302で redirect してしまうと、フォームのデータを再度送信されてしまい永久にログインし続ける恐れがあります。クライアントの実装がマチマチですので難しいところですが、HTTP/1.1対応を名乗るクライアントはこのように実装されているハズです。
303 See Otherを無視するIIS
論より証拠、Microsoft-IIS/5.0 の実装を確認してみましょう。HTTP/1.0クライアント。
[console~]$ telnet 192.168.1.1 80
POST /adiary-1.30/adiary.cgi HTTP/1.0
Content-Type: application/x-www-form-urlencoded
Content-Length: 30
action=login&id=test&pass=test
--------------------------------------------------
HTTP/1.1 200 OK
Server: Microsoft-IIS/5.0
Date: Mon, 30 Apr 2007 06:17:02 GMT
Set-Cookie: session=%00%02%00sid%00aJXNNh2FJGd3%00id%00test; path=/adiary-1.30/;
Content-Type: text/html; charset=EUC-JP;
Locationヘッダは出ていません。これは正しい実装です。続いて HTTP/1.1 の接続です。この場合 SERVER_PROTOCOL=HTTP/1.1 が設定されていますので、cgiは303 See Other を返します。
[console~]$ telnet 192.168.1.1 80
POST /adiary-1.30/adiary.cgi HTTP/1.1
Content-Type: application/x-www-form-urlencoded
Content-Length: 30
Host: 192.168.1.1
action=login&id=test&pass=test
--------------------------------------------------
HTTP/1.1 100 Continue
Server: Microsoft-IIS/5.0
Date: Mon, 30 Apr 2007 06:18:47 GMT
HTTP/1.1 302 Object Moved
Location: http://192.168.17.104/adiary-1.30/adiary.cgi/nabe?login_auth
Server: Microsoft-IIS/5.0
Content-Type: text/html
Connection: close
Content-Length: 183
- 303 をなぜか 302 に書き換えている。
- Locationヘッダはきちんと出力されている。
- Set-Cookieヘッダを出力しない(cgi側ではきちんと出力している)
解決策は?
Microsoft-IIS で cgi 動作させるときは、SERVER_PROTOCOL を HTTP/1.0 と見せかけるしかないでしょう。*2
ほんとIEといい、IISといい、まったくデタラメなソフトばかりです。AN HTTPDの方が幸せなになるんじゃないかなぁ。perlis.dll でも普通に ImageMagick 使えましたし。
- [BUG] Location ヘッダーと組み合わせると CGI で Set-Cookie ヘッダーが無視される(Microsoft)
- RFC2616(日本語訳)