▼CGIのメカニズム▼

-- Common Gateway Interface -- a brige from WWW system

$Id: cgi-mechanism.html,v 2.8 2001-07-02 09:40:26+09 kabe Exp $


もくじ


CGIとは

CGI (Common Gateway Interface) とは、情報サーバーが外部のプログラム (ゲートウェイ)を走らせるためのインターフェースである。 現在の所、情報サーバーとしてはHTTPサーバーだけが定義されている。 この機能を用いれば、静的なデータだけでなく、動的なデータも URIでアクセスすることができる。

ちまたでは CGI と言うと、このプログラム自体を指すようですが、 本当に正確に言うのであれば CGI は単なるインタフェースの規格で、 プログラム自体はゲートウェイと言うのが正しい。
	HTTPd <----> Gateway <----> 他のシステム(データベースとか)
		↑
		ここのプロトコルがCGI (Common Gateway Interface)
	

ゲートウェイが動作するまで

ゲートウェイが実際に動作し、意味のあるドキュメントを生成するまでには、 の連係プレーが必要である。以下に流れを示そう。

WWWブラウザのお仕事

CGIを使うのは動的な出力が欲しいときなので、 普通は FORM や ISINDEX といった入力インタフェースを用意する。 ブラウザの仕事は、ユーザーの入力したデータを URIやHTTPで発信できるような形式に変換して送信するところまで。

<A HREF="...">に直接CGIのURLを書くこともあるが、 この場合はすぐにHTTPサーバーが仕事をする ことになる。

Form Data Set

<ISINDEX>,<FORM>,<IMG ISMAP> といったHTMLタグがあれば、 ブラウザは入力可能なインターフェイスを提供してくれる。 入力されたデータはブラウザが application/x-www-form-urlencoded エンコーディングに変換する。これを form data setという。 たとえば、
 <INPUT TYPE=TEXT NAME="name" VALUE="John Doe"> 
というフィールドを form data setに変換すると、
 name=John+Doe 
となる。

◇HTTPリクエストの生成

構成されたform data setは、 以下のメソッドを使ってHTTPサーバーへ渡される。 GETとPOSTは、副作用のないもの (状態が変わらないもの) をGET、 副作用があるもの (データベースの変更など) はPOSTというふうに使い分ける。

form data setがとんでもなく長くなる場合は、 GETではURIが長くなってしまうため、古いサーバーが萎えてしまうことがある。 こんな時は、副作用がなくても例外的にPOSTを使ったFORMを書く 場合もある。

HTMLの規格では、<ISINDEX> は <HEAD> の中、 <IMG ISMAP> は <A HREF=...> の中でしか使えない。 特に<ISINDEX>は手軽なので <BODY> の中で 使いたくなるが、厳密には規格に沿っていない。気をつけよう。

Netscape拡張では <ISINDEX> のプロンプト文字列が変えられる。 ますます <BODY> で使う人が増えそうだ…って、 Netscape拡張には DTD がないから何をどー書いてもかまわないという話もある:-P

直接 HREF="..." に書く場合

ゲートウェイ呼出のURIは上のように <ISINDEX> か <FORM> で 生成するのが本来の経路であるが、めんどくさい場合には直接 <A HREF> や <IMG SRC> で指定することも少なくない。 この場合は & を &amp; にエスケープすること

http://somehost/cgi-bin/foo?name=John+Doe&gender=male
	↓
<A href="http://somehost/cgi-bin/foo?name=John+Doe&amp;gender=male">...</A>

注意しなければならないのは、URIとしては あくまで `&'が 正しく、`&amp;'への変換は HTML(SGML)のHREF属性の値として埋め込むためという 事情による。従って WWWブラウザはこの &amp; を `&' に戻して サーバーに URLを送信する。

ただやっかいなことにこの処理をきちんとやらないブラウザが 世の中にはびこっているので、どうしても安全側に倒したい人は `&'を使わずに 値を渡す手段も考える余地あり。 どっちにしてもform data setの解釈はゲートウェイの作り方次第なので、 HREFに直書きするなら別に & でなくてもよい。

もっと濃ゆいはなし


HTTPサーバーのお仕事

HTTPサーバーは、渡されたURIおよびBodyを読み込み、 ゲートウェイに環境変数の形で渡す。
この「環境変数で渡す」というのが要するに Common Gateway Interfaceの方法なので、 CGIではないゲートウェイ起動方法 (プラグインとか)では 環境変数を使わないこともある。

ゲートウェイに渡される環境変数にはさまざまのものがあり、 どんなものがあるかは使っているHTTPサーバーに依存する。 このうち、NCSA HTTPdの実装をまとめたものが CGI/1.1 であり、W3C httpdをはじめ多くのサーバーはこれに準拠 (完全対応とはいってない:P)しているようである。

CGI/1.1では、CGIを指すscript URIが以下のように定義されている。 見ためは普通のURIと変わらない。

script-uri
= protocol :// SERVER_NAME [ : SERVER_PORT ] enc-script [ enc-path-info ] [ ? QUERY_STRING ]
enc-script
SCRIPT_NAMEをURIエンコードしたもの。
enc-path-info
PATH_INFO (追加パス)をURIエンコードしたもの。
サーバーの設定にもよるが、ゲートウェイのプログラム自体は ディレクトリ階層の深い所には置けず、スクリプト名の後に追加した 階層はすべてenc-path-infoとなる。

例としては

http://somehost/cgi-bin/test-cgi?keyword

script URIをサーバーが受けとっても、

はサーバーの機能や設定(~=管理者のポリシー)による。 一般には、 といった動作をするようである。 W3C httpdでの例

設定方法は違えどこういったメカニズムはどのHTTPサーバーも 持っている。渡されたURIをどう解釈し、どうゲートウェイに渡すかは 本当はサーバー依存なのだが、 やはり普及しているW3CやNCSAのサーバー (CGI/1.1) と 大きく違う動作をするものは 互換性の点であまり使われていないような気がする。

というか、大きく違うものは "CGI" ではなく、 別のインターフェースになる。

より多くの環境変数を渡すことには問題がないので、 サーバーによってはCGI/1.1よりも多くの有用な情報を渡してくれる ものもある。 その機能を使用するゲートウェイは残念ながら他のサーバーの管理下では 使えなくなる可能性があるが、 実際問題としてサーバーのグレードダウンはそうそうないであろうから、 問題は少ないと思う。 あなたのサイトのサーバーにも、何か面白い機能があるかもしれない。

逆に、他のサイトでも使ってもらいたいようなゲートウェイ (CGIプログラム)を作って公開する場合は、サーバー依存の環境変数は あまり使わない方がいいだろうし、使っている場合はちゃんと 動作環境として「ほげサーバー専用」と書かないといけない。 (意外にみんな書かない)

たとえば REQUEST_URISCRIPT_FILENAME なんてのは 良く使われてそうだが、実は Apache依存。


ゲートウェイのお仕事

ゲートウェイは、環境変数から情報を受けとり、データを生成してサーバーに渡す。

特に指定がなければ、ゲートウェイは生成するデータを標準出力に 書き出すのが一般的である。 サーバーはこのデータを読みとり、必要に応じてHTTP Responseに 変換する。

Non-Parsed Header
一番単純な方式であり、ゲートウェイが完全なHTTP Responseを生成する。 (サーバーは単に中継するだけ。) 単純なサーバーではこの機能しか持っていないこともある。
Parsed Header
ゲートウェイは最小限の情報をサーバーに伝え、サーバーが完全な HTTP Response を生成する。 この情報を伝える方法として、CGI/1.1ではCGI-Responseが 以下のように定義されている。 ゲートウェイの仕事は下のCGI-Responseを標準出力に出すことにある。
CGI-Response
= *(CGI-Header | HTTP-Header ) NL [ Entity-Body ]
CGI-Header
= Content-type | Location | Status | extension-header
Content-type
= "Content-Type" ":" media-type NL
Location
= "Location" ":" URI NL
Status
= "Status" ":" 3digit SP reason-phrase NL
Content-type
通常のURIでは、ローカルのファイル名などによりサーバーは 与えられたドキュメントの形式(Content-Type)を判別できる。 しかし、ゲートウェイの出力はそのままでは判定しようがないので、 ゲートウェイは明示的にサーバーにデータの形式を教えてやる必要がある。 CGI/1.1ではこの情報をデータ出力の前に追加してやる形で 実装しており、これが Content-typeである。 このヘッダがない場合は、サーバーはPLAINTEXTとしてHTTP Response を生成する。
どんなゲートウェイであっても、Parsed Headerを使っているならば データ本体の前に必ず NL ('\n')が必要である。 サーバーはこの NL でCGI-Headerとデータ本体を 区別する。
考え方自体はInternet MailやNetNewsと同じ。 空行でヘッダと本文を区切る。

データの受けとり


参考文献


ホ〜ムペ〜ジ
かべ@dais.is.tohoku.ac.jp