太郎日記’79J

「やったろうやないの。」な太郎のblog
技術ネタはタロタローグに任せて、こっちはニュースメインで。
<< September 2018 | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 >>
 
RECOMMEND
MySQLによるタフなサイトの作り方
MySQLによるタフなサイトの作り方 (JUGEMレビュー »)
佐藤 真人,桑野 章弘,岡田 達典,大黒 圭祐
MySQLだけでなく、DBサーバやアプリの設計など、あらゆる手段を使ってタフなサイトを作る本である
最新記事
あわせて読みたい
あわせて読みたい
なかのひと
ClusterMaps
CM by JUGEM
スポンサーサイト

一定期間更新がないため広告を表示しています

- | 個別記事 | - | -
CGI.pmでPOSTされてきたXMLデータを受け取る方法[crossdomain問題(4)]

さて、自分で作ったlibディレクトリからPerlモジュールを読み取る方法[crossdomain問題(3)]の次の話です。
いよいよxml_proxy.cgiを作るべくPerlスクリプトを書くところまで来ました。
今回作るxml_proxy.cgiは、xml_proxy.phpを真似て、
以下のような動作をします。

  1. アクセス先は「http://〜/xml_proxy.cgi?url=<ウェブサービスのURL>」で、
    パラメータurlに指定されたウェブサービスに処理をそのまま投げる
  2. アクセス時にPOSTデータとして、Content-typeがtext/xmlのXMLデータを
    xml_proxy.cgiに渡す
  3. xml_proxy.cgiは、受け取ったXMLデータをそのままウェブサービスに流す
こんな感じです。
xml_proxy.cgiの役割は、
ムーディー勝山のように右から来たものを左へ受け流す事です。

このxml_proxy.cgiを、XMLデータとURLの受け取りをCGI.pmで、
受け取ったデータをウェブサービスに投げる処理をHTTP::Liteで実装するつもりです。

■POSTされてくるXMLデータは、ちょっと特殊らしい

まず今回は、CGI.pmからXMLデータを抜き出してくる方法です。
普通、リクエストの際に送られてくるデータは、
名前と値の対になってます。
今回だと、ウェブサービスのURLは
http://〜/xml_proxy.cgi?url=<ウェブサービスのURL>
てな感じで、「url」って名前で
やってきてますよね。
そんな時は、以下のコードのように、
CGI->param(<パラメータ名>)」メソッドを使えば簡単に値が取れます。
use CGI;
my $q = CGI->new;
my $url = $q->param('url');
が、ウェブサービス用に送られてくるXML形式のデータは違っていて、
名前が付いてません。
なので、送られてきたパラメータ全部の名前を取得できる、
引数なしの「CGI->param()」でも、 パラメータ名を取得することが出来ません。
my @params = $q->param();
print "@params¥n";
上のコードでも、出てくるパラメータ名は「url」だけです。
当然、名前を指定して値を拾ってこれません。

しかし、何とかなりました。
どうやら、「Content-typeがtext/xmlのXMLデータ」は、
パラメータ名として「POSTDATA」を指定すれば
取得できるようです。
というか、CGI.pmのソースを見る限りだと、
以下の条件を満たす場合、「POSTDATA」で取ってこれます。

  • リクエストメソッドがPOST
  • Content-typが定義されている
  • Content-typeが「application/x-www-form-urlencoded」ではない
  • Content-typeが「multipart/form-data」ではない
てなわけで、
my $xml = $q->param('POSTDATA');
これで、XMLデータを取得できました。

■POSTだとクエリ文字列無視!?

さて、折角調子良く行ってましたが、問題が発生しました。
まず、このCGI.pmですが、
リクエストメソッドをPOSTにすると、
クエリ文字列(URLの後ろの「?」以降の部分)を無視します。
つまり、今回の場合だと、
パラメータ「url」は無かったことになってしまいます。
CGI.pmの当該部分のコードを見ると、
      if ($meth eq 'POST') {
      $self->read_from_client(¥*STDIN,¥$query_string,$content_length,0)
          if $content_length > 0;
      # Some people want to have their cake and eat it too!
      # Uncomment this line to have the contents of the query string
      # APPENDED to the POST data.
      # $query_string .= (length($query_string) ? '&' : '') . $ENV{'QUERY_STRING'} if defined $ENV{'QUERY_STRING'};
      last METHOD;
      }
こんな風になってます。
そもそもリクエストメソッドがPOSTだった場合、
クエリ文字列を取ろうともしないようです。
ただ、下のコメント部分を見ると、何かよく意味はわかりませんが、
「POSTデータもクエリ文字列も欲しい奴は、ココ(太字部分)をコメントから外せ!」
的なことが書いてあるように見えます。
このコメントを外すと、POSTデータの最後にクエリ文字列がくっつくみたいですね。

■XMLデータだとクエリ文字列強制排除!?

が、コメントを外しただけではまだ足りません。
先ほどの「POSTDATA」がらみの部分を見ると、
    if ($meth eq 'POST'
        && defined($ENV{'CONTENT_TYPE'})
        && $ENV{'CONTENT_TYPE'} !~ m|^application/x-www-form-urlencoded|
        && $ENV{'CONTENT_TYPE'} !~ m|^multipart/form-data| ) {
        my($param) = 'POSTDATA' ;
        $self->add_parameter($param) ;
      push (@{$self->{$param}},$query_string);
      undef $query_string ;
    }
などと、太字部分でクエリ文字列を消しちゃってます。
なのでこのコードを削除するか、
消した後でもう一回クエリ文字列をこの変数$query_string
放り込む必要がありますね。
要するに、通常のCGI.pmでは無理ということですな。

■仕方ないので自力で頑張る?イヤイヤ、楽もしつつね。

CGI.pmを使う限りはURLは取れそうに無いので、
とりあえず、クエリ文字列だけ自分で拾ってパースするしかない?
というわけで、最低限自分でも頑張って、
何とかクエリ文字列からURLを取得しましょう。
幸い、クエリ文字列そのものの取得方法は、CGI.pmのソース見れば載ってます。
my $query_string = $ENV{'QUERY_STRING'} if defined $ENV{'QUERY_STRING'};
こんな感じですね。
で、これで「url=<ウェブサービスのURL>」の部分が
$query_stringに入りました。
これを自力で解析して、「<ウェブサービスのURL>」を拾ってくれば・・・
と言いたいところですが、面倒です。
そもそもCGI.pmに解析機能が付いてるんだから、
そいつにやらせましょう。
CGI.pm内で解析を行ってる部分を抜き出して真似ればいいはずです。
つまりこう。
$q->parse_params($query_string) if defined $query_string;
最後の定義チェックは念のためですが。
これで、URLがパラメータとして$qに入ったので、
my $url = $q->param('url');
このコードでウェブサービスのURLを取得できます。

■まとめ

と言うわけで、今回のコードはこんな感じかな。
use CGI;
my $q = new CGI;
my $xml = $q->param('POSTDATA');
my $query_string = $ENV{'QUERY_STRING'} if defined $ENV{'QUERY_STRING'};
$q->parse_params($query_string) if defined $query_string;
my $url = $q->param('url');
これで、XMLデータとURLを取得できたので、
次はこれをウェブサービスに受け流すだけですな。

スポンサーサイト
- | 個別記事 | - | -
ドミノ・ピザでも食べながら、コメントをどうぞ。
コメントする









 
トラックバック
この記事のトラックバックURL(記事と無関係なトラックバックは削除される可能性があります)
※記事が投稿されてから30分の間、トラックバックを行うことが出来ません。
http://tarotaro.jugem.cc/trackback/1542
 

Copyright (C) 2004 paperboy&co. All Rights Reserved.

Powered by "JUGEM"