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 なので、ありがたく改変して使わせていただいてます。この場をかりて感謝。

Posted by ryo at 15:57 | Parmalink | Comments (0) | TrackBack (0)