QUERY_STRINGが勝手にデコードされた

IRCログを検索するCGIをでっちあげようとしていたら,日本語の扱いに困った.ASCIIの範囲だとうまくいくのに「ほげ」とかだと化けてしまう.これはRubyNKFライブラリの判定精度の問題なのかな,と思って <input type="hidden" value="日本語文字列"> がどのように渡されるかで判定することにした*1.しかしどうやってもCGI内の各種エンコード済みのものと一致しない.あれあれ,と思いとりあえず単純なクエリからテスト: "foo" はOK.次に "!@#$%^&*(){}|" を試したら '#' でぷつりと途切れる.Rubyのライブラリ cgiCGI#params がそもそもおかしいのだ.信じ難いがこれはRubyのバグ? じゃあライブラリには頼るまい,と環境変数 QUERY_STRING を見るとここですでに途切れている.しかもURLエンコーディングが勝手にデコードされてるではないか.先輩が環境変数一覧を表示するCGIで試して下さったところ, QUERY_STRING はおかしくなっているが(完全に一般的ではない) REQUEST_URI ならOKということが分かった.よって REQUEST_URI から自分でクエリを切り分けて亊無きを得た.2時間くらい手間取ったが... これが昨日の夜のこと.
とりあえず当該CGIでは問題は解決したものの,このままでは新サーバにまともにCGIが置けない.そう思ってあれこれとApacheのマニュアルを調べる.環境変数CGI,suexec,関連モジュール... しかし分からない.そもそも環境変数を書き換えるなどという機能のモジュールなど載ってないのだ??? そして昼過ぎ,ふと別のことをしていたら,ふと閃いた.こないだWebDAVサービスを整備してたときに入れた mod_encoding がすげーーーー怪しいじゃないか,と. "mod_encoding QUERY_STRING" でググると,出るわ出るわ同じ症状の報告と対策情報がいっぱい.あーあ.自分で入れたモジュールのことなんて,Apacheの標準添付マニュアルいくら読んでも載ってるわけないよなぁ.むしろそういうのをまず疑うべきだったのに.アホくさい.検索CGIも普通に CGI#params を使うように戻して,テストして... という一つ一つが単純なことでも時間を取られるのが鬱陶しい.
んで結論: とりあえず安直にディレクティブ Location を使うことにした*2.mod_encodingに当てるパッチもあるようだが,私の場合は必要ない((Re: Netscape + Apache 日本語で検索できない? に投稿されたパッチが必要なのは「mod_encodingが有効になっているディレクトリの特定のサブディレクトリでのみmod_encodingを無効にしたい」ときだけ.私の場合,WebDAVディレクトリの下はみなmod_encodingが有効になっていてくれていいので,単に Location でいいのだ.)).
なおmod_encodingの設定で AddClientEncoding SJIS "Microsoft .* DAV" は入れないように注意.これはweb上の古い文書(@ITとか)で散見される設定だが,ワイルドカード ".*" を使うと以降の選択肢が無視されてしまうとのこと.DefaultClientEncoding があれば十分なのだ.

<IfModule mod_encoding.c>
  <Location /dav>
    EncodingEngine    on
    NormalizeUsername on
    SetServerEncoding     UTF-8
    DefaultClientEncoding JA-AUTO-SJIS-MS SJIS

    AddClientEncoding "cadaver/" EUC-JP
  </Location>
</IfModule>

このようなものを mods-available/dav.conf に保存し, mods-enabled-members/dav.conf として貼ったsymlinkを経由して sites-available/default 内の <VirtualHost *:443> 内で Include している.こうすればHTTPSでないと /dav は "404: Object Not Found" になる.

*1:「そもそもブラウザがどのエンコーディングに基づいてMB文字をURLエンコードするのか明確な規則があればいいのに... これだから毛唐の規格は困るぜ.W3Cの慶応サイトがんばらんかい!」とぼやきつつも.

*2:Directory, Files, Location の違いについては以下を参照のこと: http://httpd.apache.org/docs/2.0/sections.html