Hatena::Groupsubtech

冬通りに消え行く制服ガールは✖夢物語にリアルを求めない。

 | 

Dec 21, 2010 (Tue)

Apache2 + mod_perl2 の仕様と正しく mod_perl2 を使うための方法 23:17 はてなブックマーク - Apache2 + mod_perl2 の仕様と正しく mod_perl2 を使うための方法 - 冬通りに消え行く制服ガールは✖夢物語にリアルを求めない。

Plack::Handler::Apache2 をちょっと使ってみているのですが、本格的に使おうとすると挙動がおかしいところがあって最近手を入れています (Plack にクソパッチを送ったりして申し分けない気分にはなりますが、背に腹は変えれないので、恥を忍んで送りまくってます……)。その間に気付いたこととかをいくつかメモ書きしておきます。

Apache2::RequestRec (以下 $r) の path_info は全く信用できない

$r->unparsed_uri から作りましょう。

この path_info とかいうやつは Apache がパースしたあとの値が入っているので、いろいろおかしいことになっていることがあります。例えば

とかがあります。この $r->path_info から変なことになってない状態に復元することは不可能なので、$r->unparsed_uri から作るしかありません。基本的には以下のように

URI->new($r->unparsed_uri)->path

で PATH_INFO 相当になります。$r->uri というのあって "The path portion of the URI" と書かれているので、これも上記と同じ動作をするはずですが、信用できないので自力で unparsed_uri をパースしたほうが懸命な気がしています (遅いだろうけど、正しく動かないと早いも遅いもない)。

とはいえ、これで PATH_INFO 相当になるのは <Location /> で PerlHandler をしかけている場合に限っています。例えば /foo とかに PerlHandler をしかけたら、SCRIPT_NAME 相当のものは /foo で PATH_INFO は残りの部分になってほしいわけですが、上記のままではそうなりません (unparsed_uri を使って自力でやってるので当然です)。

SCRIPT_NAME を期待通りとる確実な方法がない

$r->unparsed_uri と $r->location から頑張って作りましょう。

subprocess_env でとれる SCRIPT_NAME は PATH_INFO と同様、ファイルシステムの影響 (よくわからず再現できなかったけど他の何かの影響をうけていることもある気がする) をうけるので信用なりません。 (SCRIPT_NAME と PATH_INFO は御互い重複する部分がないという性質があるので、一方が変わったら一方も変わります ref. RFC3875)

CGI とかの場合ファイルシステムを実際見るのはたぶん正しいと思いますが、mod_perl のように実際にファイルがあるかとかは関係なく Location を使ってハンドリングする場合、Location の位置を SCRIPT_NAME とし、残りの部分を PATH_INFO を扱ってくれるのというのが一番混乱しない仕様でしょう (まぁだいたい / にしか PerlHandler 書かないと思いますけど……)。

Location ディレクティブの引数は $r->location でとれるので、これを SCRIPT_NAME として扱えばだいたいいいんですが、ややこしいことに LocationMatch ディレクティブというのもあって、こちらは正規表現が使え、これも $r->location で取得できます。すなわち $r->location は正規表現の場合があります。といっても Location と LocationMatch を区別する方法はないようなので、どっちを使っているかは推測する必要があります。(実際のところ、こんなことしないだろという気はするので、汎用的にしないなら決めうちでどうにかしてしまうべきでしょう……)

で、もろもろ解決するため、テストを追加しつつだいたい動くであろう以下のようなコードを書きました。

    my $path_info = URI->new($r->unparsed_uri)->path;
    my $location = $r->location;

    if ($path_info =~ s{^($location)/?}{/}) {
        $env->{SCRIPT_NAME} = $1 || '';
    }

location がただの文字列の場合に大変心苦しい感じがするので、もっと完璧な方法があったら教えてほしいです。

まとめ

文章に書きくだしてみるとそんなに大したことはやらなくていい気もするんですが、知らないと大変困る仕様がいくつかあってハマりまくりました。「なんとなく動いている」というのが一番怖いので、ホント勘弁して欲しいところです。まだなんかありそうで怖いです。

これらの BK を知らなくても安心して使いたいわけなので、P::H::Apache2 を完璧にしたいですね…… mod_perl に詳しい人に助言を頂きたいものです

 | 

スポンサード リンク

書いてる人

cho45 (佐藤広央) (www.lowreal.net)

Perl, JavaScript, Ruby, HTML, CSS, Web etc


スポンサード リンク