Catalyst + FastCGI + LighttpdでControllerが見つからなくなる件

myapp_server.pl上だと普通に動くのに、FastCGIで動かすと規定のControllerにリクエストが飛ばない事態が発生。

MyApp::Controller::Admin, MyApp::Controller::Admin::Userという2つのControllerがある時に、/admin/*へのリクエストは問題ないが、/admin/user/*をリクエストしてもM::C::Admin::Userが呼ばれない。何故かRoot.pmがリクエストを受け取ってしまう。

Catalyst::Controller::Resourceとか使ってわりと複雑なDispatch構成になってるのが原因だろうかと思って、Controllerの構成をいろいろ変更したりしても何も解決しなくて困っていたら、牧さんとこで同じ症状を発見。

これに習って、Catalyst::Engine::CGIの140行目を

my $path = $base_path . ($ENV{PATH_INFO} || $ENV{SCRIPT_NAME} || '');

こうしたら確かに解決した。でも、2年も前に発覚してる問題がそのまま残ってるとも考えにくいので、もう少し掘ってみら次の日にフォローされてた。

残念ながら本記事のリンク先はつながらなくなってたけど、原因は判明。

で、この後ちょっと色々試してみてたら、結局 ルートパスにそのままFastCGIハンドラをひもづけるとPATH_INFOが正しく設定されないってことらしい。

まさに書いてある通りで、ルートパスに割り当ててました。

前段にApacheを置いて、静的なコンテンツは全てそこでサーブして、Catalystが処理するものだけmod_proxy経由でLightyに振るからルートからCatalystに回せばいいや、とか思ってたらそれが裏目に出たらしい。

結局、lighttpd.confをこんな感じにしたら解決した。staticなコンテンツはここで処理しない前提だから、必要ない記述もあるけど、とりあえず一般的な形にしておいた。

$HTTP["url"] =~ "^/" {
    setenv.add-environment = ( "SCRIPT_NAME" => "/" )
}

url.rewrite-once = (
    "^/((?:js/|css/|image/|static/).*)" => "/root/$1",
    "^/(?!js/|css/|image/|static/)(.*)" => "/myapp/$1"
)

fastcgi.server = (
    "/myapp" => (
        "MyApp" => (
            "socket"      => "/tmp/myapp_web.socket",
            "check-local" => "disable",
            "bin-path"    => "/var/sites/MyApp/script/myapp_fastcgi.pl",
            "bin-environment" => (
                "PERL5LIB" => "/usr/local/CPAN/lib/perl5/i386-linux-thread-multi:/usr/local/CPAN/lib/perl5:/usr/local/CPAN/lib/perl5/site_perl/5.8.8",
                "DBIC_NO_WARN_BAD_PERL" => "1",
            ),
        )
    )
)

しかし、これってそんなに特殊な形でもないだろうし、ハマる人も少なくないと思うんだけど、ググってもなかなか見つからなかったところを見るとわりとレアケースなのかしら。

あと、Catalyst::Engine::CGIをああいう形に変更したらマズいんだろうか。うーん、謎だ。