最近、LWPやWWW::Mechanizeを2007年頃のバージョンから最新のバージョンにしたら、文字コードで色々ハマったのでメモっておきます。
結論から言えば、最新のLWPやWWW::MechanizeはUnicode文字列を適切に扱えますので、以下を心得て使うとハマりどころが少ないかなと思います。
LWP-5.837
WWW-Mechanize-1.66
- $mech->content は $ua->decoded_content
- つまり、Unicode文字列
- $mech->field, tick, valueとかには、Unicode文字列を渡す
- $mech->click とすると、その<form>にaccept-charset属性があればその値でencodeされて送信される
- そうでなければ、全て"UTF-8"でencodeされる
さて、このclickの動作には一つ問題があって、WWW::Mechanize-1.66では「<form>が表示されているドキュメントのcharsetを、送信するクエリのcharsetとする」という大多数のブラウザでの動作をエミュレートできていません。具体的には、以下のテストが通りません。サーバに届くのは「%E5%A3%B1=%E3%81%82」となります。
$Plack::Test::Impl = 'Server'; my $mech = WWW::Mechanize->new; test_psgi ua => $mech, app => sub { my $env = shift; if ($env->{PATH_INFO} eq '/post') { return [ 200, [ 'Content-Type' => 'text/html; charset=euc-jp', 'X-QStr' => $env->{QUERY_STRING}, ], [ "done\n" ] ]; } else { return [ 200, [ 'Content-Type' => 'text/html; charset=euc-jp' ], [ encode 'euc-jp', do { local $/; <DATA> } ] ]; } }, client => sub { my $cb = shift; my $res_form = $cb->(GET '/'); $mech->tick('壱' => 'あ'); my $res_posted = $mech->click; is scalar $res_posted->header('X-QStr'), '%B0%ED=%A4%A2'; done_testing; }; __DATA__ <form action="/post" method="GET"> <input type="checkbox" name="壱" value="あ"> </form>
こちらはパッチを送ってみましたが、適用されるかはわかりません。
*1:厳密にいえばLatin-1文字列が返ることもあるので、UTF-8フラグが立つとは限らない → UTF8 フラグあれこれ