January 03, 2006
Hyper Estraier +estraierpure.php
さいきん Hyper Estraier が N-gram だけでなく形態素解析にも対応したので、ハイブリッドな検索の具合はいかがなものかと、正月休みにリニューアル開発中の某サイトに突っ込んでみることにしてみたら、これがまたハマった…
きっといつかサーバを引っ越すときに忘れてまたハマると思うので、メモっておくことにした。
Hyper Estraier を入れてコマンドラインでテストしたところ問題ないのだが、PHP バインディングの estraierpure.php 経由だと put_doc できない。つまり文書が登録できない。なんてこった。毎回コマンドを fork() してたら死んでしまう。
調べてみると、どうも PEAR の HTTP_Request がいけてない。
余談だが estraierpure.php 0.0.6 は setBody() を使うので、HTTP_Request 1.43 が必須のようだ。pear install だと 1.41まで しか入れてくれなかった。ケチ。っていうかなぜだ。とりあえず手動で入れて回避したので深く考えないことにする。
話を元に戻すと、estraierpure.php からのリクエストを受け取る側、Hyper Estraier ノードマスターのコード estmaster.c を見てみると、Content-type: text/x-estraier-draft つうのを期待しているようなのだが、この Content-Type が認識できずにエラーになってる。わがままだなぁ。
しかたがないので HTTP パケットをダンプして見てみると、なぜか Content-Type: ヘッダが二つある。HTTP の Content-Type ヘッダは複数あってもよいのだっけ? まぁそれは重要な問題じゃない(というかRFCを眺めるのが面倒くさい)。
で、estraierpure.php は new HTTP_Request() するときに、ちゃんとパラメータとして Content-Type を渡している。しかたがないので HTTP/Request.php を追いかけていくと、Method が POST の場合で、Content-Type ヘッダが存在しない場合に、デフォルトとして application/x-www-form-urlencoded を追加している。それは正しい気がするのだが、この判定が問題。
if (empty($this->_requestHeaders['content-type'])) {
// Add default content-type
$this->addHeader('Content-Type', 'application/x-www-form-urlencoded');
}
lower case しかチェックしていないのである。HTTP Header は case insensitive じゃなかったっけ?
そのくせ自分は Cap and Low でヘッダを足してるという矛盾ぶり…
なので、HTTP_Request 1.43 を使って、POST するときに、自前の Content-Type: ヘッダ *のみ* 使用したい場合は、addHeader("content-type", "hoge/hoge") と書かなければならないのだ。
そもそも estmaster が独自の Content-Type を要求しなければいけない理由はよくわからないのでさておき(そこまで追いかけるとさらに半日潰してしまう…)、とりあえず estraierpure.php の 1455行目あたりを s/Content-Type/content-type/ することで、一晩消費しただけで難を逃れることができた。
せっかくなので estraierpure.php の作者にも教えてあげたいけど、サイトに連絡先がないなぁ。残念。
BSDL なので、ありがたく改変して使わせていただいてます。この場をかりて感謝。


