@kyanny's blog

My life. Opinions are my own.

RewriteMap で外部プログラム (prg:/path/to/file) を使う場合、出力は改行で終端しなければならない

過去何度もハマり、何時間いや何十時間も費やして、先日「どうやらそうしないとうまくいかない」と書いた、この問題が、実はマニュアルに書いてあった。

Apache module mod_rewrite

# 外部の書き換えプログラム
MapType: prg, MapSource: 有効な通常ファイルへの Unix ファイルシステムのパス

ソースにはマップファイル以外にプログラムを使うこともできます。 これ用のプログラムを作成するには、まずいずれかの言語を選択する ことになりますが、作成されたものは実行可能ファイル (すなわちオブジェクトコード、もしくは1行目に ' #!/path/to/interpreter' のようなマジッククッキー トリックの入ったスクリプト)でなければなりません。

このプログラムは Apache サーバの起動時にすぐに起動され、 自分の stdin および stdout ファイル ハンドルを通して、書き換えエンジンとのやりとりを行ないます。 このプログラムは、各々のマップ関数の検索のたびに、検索対象の キーを、改行文字で終端された文字列として stdin から受け取ります。そして、見つかった値を改行文字で終端された 文字列として、もしくは見つからなかった(すなわち、 与えられたキーに対応する値がない)場合、4 文字の文字列 ``NULL'' を返されなければなりません。1:1 の マップ(すなわちキー = 値)を実現する単純なプログラム 例としては、以下のようになります:

#!/usr/bin/perl
$| = 1;
while () {
# ...put here any transformations or lookups...
print $_;
}

しかし、十分に気をつけてほしいことがあります:

1. ``Keep it simple, stupid(アホ、もっと簡単に 書けよ!)」'' (KISS) ということなのですが、もしこの プログラムがハングしてしまうと、そのルールが現れた瞬間に Apache サーバ自体がハングしてしまいます。
2. ありがちな間違いとしては:stdout に対して バッファード I/O を使ってはなりません!これをやると永久ループ にハマってしまいます!だから上のコードでも ``$|=1'' とやってるんです。。。
3. RewriteLock ディレクティブを使ってロック ファイルを定義し、mod_rewrite が当該プログラムへの通信において 同期合わせができるようにしてください。デフォルトではそのような 同期合わせは行なわれません。

マニュアルは頭から通して読んでみるものですねぇ。