HTTP::Request::AsCGIの使い方

今まで知らなかったんだが、HTTP::Request::AsCGIというのを使うとテストとかにスゴく便利らしい。
というわけで、早速いくつかのブログを見ながら触ってみた。

use strict;
use HTTP::Request;
use HTTP::Request::AsCGI;
use CGI;
use Data::Dumper;

# HTTP::Requestオブジェクトを作っておく
my $url = "http://localhost/test?key1=value1&key2=value2;
my $req = HTTP::Request->new("GET", $url);

# AsCGIでcgi環境を作る
my $c = HTTP::Request::AsCGI->new($req)->setup;
my $q = new CGI;

# クエリーパラメータを出力してみる
for($q->param){
    print $_, " => ", $q->param($_), "\n";
}

あれ?なにも表示されないよ??
ちょっと悩んでみたが、sixapartのブログに少し解説があったので読んでみました。

HTTP::Request::AsCGI は STDIN や STDOUT などをテンポラリファイルへのディスクリプタに置き換え、Content-Length があると、STDIN に置き換えられているテンポラリファイルにメッセージボディを書き出しておきます。

あとid:naoyaブログのコメントの中にもこんなやり取りがありました。

hassylin 2007/01/31 20:08 $cってどこでつかってるんだろ??(初心者)

naoya 2007/01/31 21:51 enviroment and descriptors will automatically be restored when $c is destructed. (via http://search.cpan.org/~chansen/HTTP-Request-AsCGI-0.5/lib/HTTP/Request/AsCGI.pm )

要するに$cが破棄された後でないと標準入出力は普通の状態に戻らないんですね。
ということは上のコードは、AsCGIの処理の部分だけをブロックで囲んでやればよいわけだ。

use strict;
use HTTP::Request;
use HTTP::Request::AsCGI;
use CGI;
use Data::Dumper;

# HTTP::Requestオブジェクトを作っておく
my $url = "http://localhost/test?key1=value1&key2=value2;
my $req = HTTP::Request->new("GET", $url);

# AsCGIでcgi環境を作る
# ここをブロックで囲む
my $q;
{
  my $c = HTTP::Request::AsCGI->new($req)->setup;
  $q = new CGI;
}

# クエリーパラメータを出力してみる
for($q->param){
    print $_, " => ", $q->param($_), "\n";
}

こんどはちゃんとパラメータが表示されました。


もうちょっと色々やってみるとこんな感じ。

use strict;
use HTTP::Request;
use HTTP::Request::AsCGI;
use CGI;
use Data::Dumper;

# HTTP::Requestオブジェクトを作っておく
my $url = "http://localhost/test?key1=value1&key2=value2;
my $req = HTTP::Request->new("GET", $url);

# AsCGIでcgi環境を作る
# ここをブロックで囲む
my $q;
{
  my $cgi = HTTP::Request::AsCGI->new($req)->setup;

  # CGI環境に(をエミュレートしたFDに対して)出力する
 # これはコンソールには表示されない
  $q = new CGI;
  print $q->header;
  print $q->start_html;
  print $q->h1("テストだよ");
  print $q->end_html;

  # HTTP::Responseのカタチで結果を取得して表示してみる
  # restore後はコンソールに出力される
  my $res = $cgi->restore->response;
  print $res->as_string;
}

# クエリーパラメータを出力してみる
for($q->param){
    print $_, " => ", $q->param($_), "\n";
}

ふむ。なるほど。sixapartの中の人を見習って$cを$cgiって書き換えたんだけど、
この方が何してるのかイメージがわくな。

で、結果はこう。

HTTP/1.1 200 OK
Date: Sun, 11 May 2008 18:12:18 GMT
Content-Length: 369
Content-Type: text/html; charset=ISO-8859-1

<!DOCTYPE html
        PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
         "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" lang="en-US" xml:lang="en-US">
<head>
<title>Untitled Document</title>
<meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1" />
</head>
<body>
<h1>テストだよ</h1>
</body>
</html>
key1 => value1
key2 => value2

ふー。直感的にはなんだかよくわからないモジュールだったけど、でもこれはかなり便利。

今後いろいろと使いそうなので、覚えておこう。
あとでちゃんとCPANドキュメントも読んでおかねば。