LWP::UserAgentで、文字列をそのままPOST

何がしたいかと言うと。普通はこんな感じで、POSTでパラメタを引き渡すのだけど。

#!/usr/bin/perl

use strict;
use LWP::UserAgent;

my $ua = LWP::UserAgent->new;
my %param = (
 "id" => "ozuma",
 "type" => "12",
);
my $res = $ua->post("http://localhost/~ozuma/param.cgi", \%param);
print $res->as_string;

今回はSOAPっぽいインタフェースで、Request Bodyにパラメタ名を付けず、無造作にXMLをそのまま送りつけたかった。HTMLでformを作るとパラメタとしてPOSTしてしまうし。

これがちょっと迷ってしまったのだけど、HTTP::Requestのインスタンスにcontentメソッドを使うだけで解決。

#!/usr/bin/perl

use strict;
use LWP::UserAgent;

my $ua = LWP::UserAgent->new;
my $url = "http://localhost/~ozuma/param.cgi";
my $post_body = <<POST_XML;
<?xml version="1.0" encoding="utf-8"?>
<sample>
  <company>
    <name>Example Company</name>
    <url>http://www.example.com/<url>
  </company>
</sample>
POST_XML

my $req= HTTP::Request->new(POST => $url);
$req->content($post_body);

print $ua->request($req)->as_string;

HTTP::Message

と、これだけで終わってしまっては何なのでもう少し突っ込んで見てみる。

$ perldoc HTTP::Request

としてperldocを読んでみると分かるけど、contentメソッドに以下のような記述がある。

This is used to get/set the content and it is inherited from the HTTP::Message base class. See HTTP::Message for details and other methods that can be used to access the content.

Note that the content should be a string of bytes. Strings in perl can contain characters outside the range of a byte. The Encode module can be used to turn such strings into a string of bytes.

というわけで、HTTP::Requestは、実はHTTP::Messageを継承したものなのでこのメソッドを見ろと。実際に $ perldoc HTTP::Message してみると分かるけど、他にもcontent_charsetなど使えそうなメソッドがいくつか見つかる。

そして第2パラグラフだが……これはPerlのことを分かっていないと、和訳するのが難しい。"a string of bytes" ってなんやねん?! って感じだが、これは慣習的には「バイト文字列」とか「バイナリ文字列」と訳される。一方の、"Strings in perl"の方は、「(Perlの)内部文字列」とか訳す人が多いかな。

つまり、以下のようにutf8プラグマを使う場合は、encodeして出さないとダメだということだ。

#!/usr/bin/perl

use strict;
use LWP::UserAgent;
use Encode 'encode';
use utf8;

my $ua = LWP::UserAgent->new;
my $url = "http://localhost/~ozuma/param.cgi";
my $post_body = <<POST_XML;
<?xml version="1.0" encoding="utf-8"?>
<sample>
  <company>
    <name>Example Company</name>
    <url>http://www.example.com/<url>
  </company>
</sample>
POST_XML

my $req= HTTP::Request->new(POST => $url);
$req->content(encode('UTF-8', $post_body));

print $ua->request($req)->as_string;