CGIからCGIを呼ぶ際、POSTでデータを渡す方法は?

[上に] [前に] [次に]
フシギダネ 2000/03/18(土) 16:12:51
CGIからCGIを呼ぶ際に、
URL表示部に引数(aaa.cgi?passwd=aaa等)を表示させたくありません。
print "Location: ・・・・・ とする場合は、?の後に引数を記述しないとだめですよね。
text/htmlで出力して、POSTで引数を渡して実行するようなjavascriptを書いてもhistoryに残ってしまうし。
うーん。困りました。
どなたか助けて下さい。

andi 2000/03/18(土) 17:46:17
../199912/99120339.htm

びーだま [E-Mail] 2000/03/18(土) 18:38:41
ソケット通信を使えば、解決できます。
Webクライアントをエミュレートしてあげればよいわけですね。

下記にソケットで、HTTP をしゃべって POST メソッドで要求
を出すクライアントのサンプルを掲示します。

おまけとして、User-Agent の指定の仕方も書いていますが、
これをやっておくと1つ良いことがあります。

受け側の CGI がこの CGI の呼び出しからしか反応しないようにするのに、
ここで、オリジナルな USER_AGENT を設定してあげることで 受け側
では、HTTP_USER_AGENT を利用して挙動を変えることが可能です。


#!/usr/local/bin/perl

use Socket;

$HOST    = 'foo.bar.com';
$PORT    = '80';
$FILE    = '/cgi-bin/aaa.cgi';
$TIMEOUT = '10';

$QUERY = 'passwd=aaa&bbb=ccc'; # 適当に入れてください。

http_post($HOST, $PORT, $FILE, $QUERY);
exit;

#
sub http_post($$$$) {

        my($host, $port, $file, $query) = @_;
        my($ret) = _open_tcp($host, $port);
        my(@list);
        my($len) = length($query);

        if ($ret == 1) {

                # HTTP 要求ヘッダー

                # POST メソッドで要求します。
                # ここを GET にすると、普通のブラウザみたいにすることも出来ますね。
                print SOCK "POST $file HTTP/1.0" . "\r\n";

                # ここで適当な USER AGENT を設定させることが出来る。
                # とりあえず、この場合は、環境変数をそのまま入れてみる。
                print SOCK "User-Agent: $ENV{'HTTP_USER_AGENT'}" . "\r\n";

                # Content-Length: を送る(クエリーのバイト数)
                print SOCK "Content-Length: $len" . "\r\n\r\n";

                # ヘッダーの最後は2回改行するのを忘れないように!

                # POST したいならば
                print SOCK "$query";

                # タイムアウトアラーム開始
                $SIG{'ALRM'} = \&_socket_timeout;
                alarm($TIMEOUT);

                # ボディー部
                $flg = 0;
                while(<SOCK>){
                    #*******************************************#
                    # ここで、受信した内容についてあれこれする。#
                    #*******************************************#
                }

                # タイムアウトアラーム解除
                alarm(0);

                # ソケットを閉じる
                close(SOCK);
        }
}

# TCPソケットのオープンと接続
sub _open_tcp($$) {

        my($host, $port) = @_;
        my($ret) = 1;

        # ソケットのオープン
        if (!socket(SOCK, PF_INET, SOCK_STREAM, getprotobyname('tcp'))) {
                $ret = -1;
        }

        # ポートへの接続
        if (!connect(SOCK, sockaddr_in($port,inet_aton($host)))) {
                close(SOCK);
                $ret = -2;
        }

        # ソケットのバッファリングを停止
        select(SOCK);
        $| = 1;
        select(STDOUT);

        return $ret;
}

# ソケット通信タイムアウト時の処理
sub _socket_timeout {
        close(SOCK);
        exit;
}

1;

フシギダネ 2000/03/18(土) 20:24:07
ありがとうございます。びーだまさん
でも、動きません。

疑問点がいくつかあります。

>        if ($ret == 1) {
>
>                # HTTP 要求ヘッダー
>
>                # POST メソッドで要求します。
>                # ここを GET にすると、普通のブラウザみたいにすることも出来ますね。
>                print SOCK "POST $file HTTP/1.0" . "\r\n";
perlのsocketがよくわからないのですが、connectしたソケットと、print SOCKのSOCKはどう結びついているのでしょうか?

>                # ボディー部
>                $flg = 0;
>                while(<SOCK>){
>                    #*******************************************#
>                    # ここで、受信した内容についてあれこれする。#
>                    #*******************************************#
>                }
あれこれって何をすればいいのでしょうか?

>        # ソケットのバッファリングを停止
>        select(SOCK);
>        $| = 1;
>        select(STDOUT);
このCGIはソケットクライアントですよね。selectの必要なしのような気がするのですが。

びーだま [E-Mail] 2000/03/18(土) 20:56:56
ごめんなさい、既に動いていたもの(実は GET 用)から、切り出してちょこ
ちょこっとPOST用に変更を書いたので、動作確認していませんでした。

あまり、今時間がないところなので、まあ、POSTする方法の考え方は
わかっていただけたかとおもいますが、

SOCK は、このファイルハンドルを通じて、クライアント - サーバー
間の通信を行います。

わかりやすい言葉でなんていったら良いでしょう。
クライアントとサーバーの間に、通信用のパイプをつないで、
情報のやりとりはここを通じて行う。というイメージでしょうか。

要求も、応答も、この SOCK を使って行います。

> # ここで、受信した内容についてあれこれする。#

ところでは、この SOCK を通じて、サーバーからのレスポンスが
帰ってきます。例えば、POST で CGI をキックしたなら、HTTP
応答ヘッダーとそのCGI の出力した内容が、SOCK を通じてやって
きますから、

$_

の内容を、好きに処理すれば良いです。

> selectの必要なしのような気がするのですが。

実は、この辺の動作については私もどこかで習ったのをそのまま
鵜呑みにしているんですけど、実際どうなんでしょう。

しなくても動くのかな?と思いますが、しないと、直感的には、
サーバーに要求する際、バッファに貯まってしまって、実際に
サーバーには送信されず、処理が先に進まない気もします。

目に見えにくいので、実際に書いて確かめてみるのが一番でしょうか。

[上に] [前に] [次に]