Railsキャッシュ、FastCGIとMultiViews
Typoにしてしばらく気付いていなかったのだが、次のようなアクセスパターンで404 not foundが起きる。
- キャッシュをクリアする
- 「/typo/2008/10」にアクセスする
- 「/typo/2008/10/11/ほげほげ」にアクセスする
- 404「The requested URL /typo/2008/10.html/11/ほげほげ was not found on this server.」となる
何が起きているかはmod_rewriteのログを見ればすぐに分かる。
[example.jp/sid#8f135d0][rid#8f391e0/subreq] (3) [perdir /typo/public/] add path info postfix: /typo/public/2008/11.html -> /typo/public/2008/10.html/11/ほげほげ [example.jp/sid#8f135d0][rid#8f391e0/subreq] (3) [perdir /typo/public/] strip per-dir prefix: /typo/public/2008/10.html/11/ほげほげ -> 2008/10.html/11/ほげほげ [example.jp/sid#8f135d0][rid#8f391e0/subreq] (3) [perdir /typo/public/] applying pattern '^$' to uri '2008/10.html/11/ほげほげ'
問題はなぜこうなるか。FastCGIなんてどこででも使われているのだから、手元の環境の何かが間違っているのだろう。そうは思いつつも、このことに気付いたのが今朝出掛ける少し前だったので、さっくり動けそうなPassengerに逃げてしまった。
そして今もう一度、別の環境で再現させようとしたのだが、どうにも再現できない。どうしたものか、というところでMultiViewsの動作を思い出した。
問題は/typo/public/2008/10.htmlがあることにより、/typo/public/2008/10/へのアクセスがこのファイルに向けられてしまうところにある。拡張子が補完されてしまっているわけで、この動作がまさにMultiViewsのそれだということにようやく気付いた。そこで再現できなかった別環境でMultiViewsを有効にしたところ、現象が再現するのを確認できた。
というわけで、Typoのように階層的でかつ中間ディレクトリ名と同じベース名のキャッシュファイルが作られるようなときにはMultiViewsとの相性が問題となることがある。もっとも、そのようなところにRailsアプリケーションを配置していたのがそもそもの原因とも言えるが。
ともあれ、運用はFastCGIでもPassengerでもどちらでもいいので、しばらくこのまま様子を見てみようと思っている。Passengerも動かしてみようとは思っていたところでもあるし(とか、いいつつ、typoからまた戻ったり、また別のものにしたりするかもしれないが)。
Apache 2.2のmod_headers
Apache HTTPサーバのフィルタは便利だけどレスポンスボディにしか使えないんだよな。レスポンスヘッダにも手を入れたいのだけど…… と思ってmod_headersのドキュメントにあたってみる。やはり指定したヘッダがあろうがなかろうが置換または追加というの(setやadd)があるだけで、指定したヘッダがあるときにだけ置換するといった便利なものはないようだ。
と、思ったのだが、英語ドキュメントのほうが新しくなっているよとあるので念のためにあたってみると、なんとeditというモードが加わっているではないか。だが、その説明を読んでみるとrequest headerがあったらうんぬんとあって、あらら、これはechoのバリエーションかないな。
なんてがっかりしながら一通りそのページを眺めていくとRequestHeaderのeditモードのとこでもrequest headerがあったらうんぬんと同じことが書いてあるのに気付いた。もしやと思って試してみると、ちゃんとレスポンスヘッダを書き換える動作をしてくれた。
Header edit Location www\.example\.jp www.debug.example.jp
こちらでは「/」を使っても問題なさそう。
mod_substitute(Apache 2.2)
HTTPなアプリケーションのデバッグのために出力の一部を書き換えたいということがある。アプリケーションを書き換えたくない状況ではApache HTTPサーバのフィルタで対応できそうだ。そういうわけで、何か適当なモジュールはないだろうか検索してみたところ、Apache HTTPサーバのバージョン2.2には標準でmod_substituteというモジュールが用意されていた。
レスポンスボディを正規表現で書き換えるもので、設定の都合上「/」をうまく扱えないようなのがいまいちだが、それでもとりあえずしのぐのには使えそうだ。こんな感じで使う。
AddOutputFilterByType SUBSTITUTE text/html Substitute s/www\.example\.jp/www.debug.example.jp/i
追記(2008-02-14): trackbackをいただいた通り、mod_substituteが「/」をうまく扱えないというのは私の間違いで、sedと同じようにちゃんとデリミタを変えられるとのこと。確認不足でした。ありがとうございます。
Apacheモジュール活用ガイド
世にあふれるモジュールの中から,一般にはあまり知られていないが,面白いか非常に有用と思われるモジュールを紹介します.また,モジュールの機能の紹介や設定方法だけに留まらず,具体的な利用方法についてもできるだけ詳しく紹介します.
[CQ出版社: Apacheモジュール活用ガイドより引用]
少し調べてみたところ著者の方が雑誌記事として目次に挙がっているモジュールの解説を書いておられるようなので、雑誌記事をベースにして書籍化したものかと思っていたのだが、まさにその通りだった。掲載当時の記事は読んでいないのだが、分量からすると大幅な加筆というのはなさそう。もしかかするとモジュール単位で追加されていたりするかもしれないが、感じとしては全体的に雑誌記事そのもので、書籍というよりはムックに近い。
メインのターゲットは1.3.xであることも予測通り。ちょうど同種のドキュメントを書いている関係で、どういうアプローチで書かれているのか興味を持っていたのだが、だいたいつかめたので購入は見送った。
Apache HTTPサーバの設定に関する用語
httpd.confに記述する各種のモノの呼び方について、webページや手元にある書籍でどのように表記されているかを少し調べてみた。今のところ、この点に関する私の認識は以下の通りだ。
- ディレクティブ
- サーバに対する指示。実際の指示にあたっては、指示内容の詳細を示すパラメータが与えられることが多い。
- コンテナ
- 設定ファイル上のある領域に対して、その領域中の記述が有効になる条件を指定するためのディレクティブ。「ここからここまで」を
<foo>と</foo>で示し、条件は開始ディレクティブのパラメータとして与える。 - セクション
- コンテナの中身。コンテナの条件にマッチする場合にだけセクション中の記述が有効になる。
ただ実際には、ここでいうセクションの味意を「ブロック」と表記したり、コンテナとセクション(あるいはブロック)の区別が明確でないケースも散見される。
たとえば1.3系のマニュアルでは「ブロック」と「セクション」の両方が使われているが、どのように使い分けられているのかはよく分からなかった。また「コンテナ」がセクションの意味で使われていることもあるようだ。これに対して2.0系のマニュアルでは、範囲指定のためのディレクティブのことは「コンテナ」と表記し、コンテナに挟まれた場合のことは「ブロック」ではなく「セクション」と呼んでいる。
もちろん、多少の表記の揺れが問題になるようなこともそうそうないことなので、あまり厳密に定義しなくてもよいだろうと思う。ただし込み入った設定を指示したり、解説したりする場合など、どうしても共通の認識が必要となることもある。そうした場面での使い分けについての定番はどこかにあるのだろうか。
mod_encodingの副作用
現状のmod_encodingでは、すべてのリクエストURIがコード変換の対象になってしまっているように見える。これはリクエスト読み込み直後のハンドラでコード変換しようとしているからで、この段階では<Directory>や<Location>が処理されていないからである——というのは八重樫さんの指摘で気付いた。
おそらくサブリクエストを発行するなどして処理してやれば、ある領域でだけコード変換を行うということができるようになるのだと思う。ただしその場合には、上位ディレクトリを表す部分を素のApache HTTPサーバが正しく処理できる必要があるだろう。上位ディレクトリがASCII文字だけから構成されていれば問題はないが、妙な文字コードがからんでくると問題が複雑になったりするのではなかろうか。
それはそれとして、こういうのはmod_rewriteの内部マップを拡張する形で実装するという手もあるのではないかと思う。時間を割けたらチャレンジしてみたい。


