Logo address

実行ハンドラ

目次

配置

	$web/etc/handler

説明

実行ハンドラとは、特定のパスパターンを持つファイルの要求を処理するプログラムのことです。Pegasus ではユーザが必要に応じてテーブル形式で要求とプログラムの関係を記述します。そしてこれを、CGI プログラムの定義や SSI (server side include) の機能の実現、さらにある特定のディレクトリに対して index.html が存在しない場合にファイルの一覧を表示する機能の実現のために使用されています。

設定の方法

パスパターンとそれを処理するプログラムを結びつける行を書く。筆者のサーバ(http://plan9.aichi-u.ac.jp)のファイルの内容は次のようなものです。
# path      mimetype    unused    execpath arg ...
/netlib/*/index.html text/html 0 /bin/ftp2html
*.http         -         0       $target
*.html      text/html    1       $target
*.dx_html   text/html    0       /bin/dx $target
この表は、パスパターン(第1項)によって、そのファイルを処理するプログラム(第4項)と処理の方法(第2項)を表しています。パスパターンの比較は上の行から行われ、マッチすればそこで終ります。第5項目以降でプログラムの引数を指定する事もできます。

パスパターンの指定においてディレクトリの区切り記号 / は基本的に他の文字と同じ扱いですが(従ってシェルのパスパターンの扱いと同じではありません)、1つの例外があります。

	/netlib/*/index.html
のように、/*/ のパターンは / にマッチすると言うルールが追加されています。(このルールは Pegasus が ftp ディレクトリを扱うのに都合の良い様にできている訳です。)

第2項は HTTP ヘッダの ContentType を表しています。これが - の場合にはプログラムは HTTP ヘッダを自ら出力する必要があります。

第3項は現在の版では使用されていません。(この項ははプログラムの実行に伴って ramfs がサービスされるか否かを表していましたが現在では常に ramfs がサービスされています。)

第4項は実行プログラムが指定されます。第4項以降に現れる $target はリクエストされたドキュメントの絶対パスを表しています。第4項が $target になっていると言う事は、要求されたドキュメントが実行プログラムである事を意味しています。

Pegasus では、URI のバス部に続けて「;」で区切って(パスが実行ハンドラを起動する場合に)引数を渡すことができますが(この頁の「URI との関係」を見よ)、それらの引数は自動的に実行プログラムの引数として追加されます。

なおこの例に現れた /bin/ftp2html はftp のディレクトリを扱うために筆者が使用しているツールです。他のサーバでは、index.html がない場合にディレクトリの内容を表示するオプションがあったりします。ftp2html はそれと類似の機能を持っていますが、それだけではなく README があった場合にはそれも表示するとか、INDEX があった場合には、ディレクトリの内容ではなく INDEX の内容を気のきいたやり方で表示するとかします。
また/bin/dx は筆者が作成して使用している SSI の機能を実行する(もっと一般的な、そしてシンプルな)ツールです。

Apache の CGI との比較

Pegasus では、いわゆる CGI ファイルは実行ハンドラの単なる1つの形式として扱われています。
/etc/handler で mimetype として - を指定した場合にはハンドラは HTTP ヘッダの全てを(標準出力に)出力する必要があります。例えば
HTTP/1.1 200 OK
Server: Pegasus/1.2 (Plan9)
Date: Tue, 27 Aug 2002 03:35:12 GMT
Content-Type: text/html
Connection: Keep-Alive
Content-Length: 1234

<html>
...
</html>
のようなものです。mimetype として text/html を指定した場合には Pegasus では単に HTML 形式、即ち
<html>
...
</html>
だけを書き出すように CGI プログラムを作成します。Apche の CGI は
Content-Type: text/html

<html>
...
</html>
のように書く必要があるので、Pegasus の *.html ファイルの方が幾分簡単になっています。しかも Pegasus の *.html はそれ以上の効果を持っています。即ちクライアントから見た時に CGI ファイルである事が分からないのです。

CGI プログラムにおけるエラー処理

Pegasus 2.0 では CGI プログラムから容易にクライアントに対してレスポンスコードを渡すことができるようになりました。従って mimetype"-" とする *.http ファイルは存在意義を失ったといえます。
mimetypetext/html が指定された場合にはサーバが自動的にヘッダを作成しクライアントに送ります。
その場合のレスポンスヘッダは次のルールに従います。
このルールは概してうまく働くように思えますが、コネクションを直接制御することもできます:
	exit '403 Forbidden # keep'
のように、# に続けて、keep または close を指定してください。

また出力に関しは、CGI プログラムの標準出力、標準エラーともにクライアントに渡ります。

Plan9 では exit status に文字列を渡せて有り難いですね。

CGI 記述言語

UNIX のシェルは問題が多く CGI を書くには適さなかったのですが、Plan9 のシェルである rc はよく設計されていて、筆者は rc をもっとも多く使用しています。次の好みは awk であり、さらに高度な CGI では Python を使用しています。perl は嫌い! (プラグマティズムの見本を見せつけられているようです)
CGI スクリプトの多数のサンプルが配布ファイルの example に含まれています。 参考にして下さい。

URI との関係

HTTP/1.0 及び HTTP/1.1 では URI のドキュメントへのパスに続いて paramquery を書くことができます。即ち、次の様になっています。
	path;params?query
	params = param[;params]
Web のサーバは(伝統的には) param を無視し、query をデコードして CGI に引数として渡している様です。Pegasus はこの伝統的な方式を改め、 param を実行ハンドラに引数として渡すべき部分であると認め、他方 query に関してはサーバは解釈に関与しないことにしました。(query の値は環境変数としてそのまま実行ハンドラに渡る。)

CGI の名前空間(ハンドラの名前空間)

CGI プログラム(ハンドラ)が見る名前空間は、サービス空間の中でのファイル
	/etc/namespace_80
で再編成できます。(Pegasus 2.0 ではこのファイルは、サービス空間のドキュメント管理者による再編成を可能にするためにあります。)

CGI の環境変数(ハンドラの環境変数)

Pegasus は多数の環境変数を持っていますが、しかしながら現在の版では多くはまだ確定してはいません。確定的なのは以下に掲げる少数の環境変数だけです。
	GATEWAY_INTERFACE
	SERVER_NAME
	SERVER_PORT
	SERVER_SOFTWARE
	SERVER_PROTOCOL
	REQUEST_METHOD
	REMOTE_ADDR
	QUERY_STRING
	HTTP_HEADER
	HTTP_HOST
	HTTP_REFERER
	HTTP_USER_AGENT
	REQUEST_PATH	# 要求されたファイルのパス(注1)
	REQUEST_URI	# 要求されたファイルのパス(注1)
	home		# /doc
	query		# QUERY_STRING に同じ
	target		# 要求されたファイルの(サービス空間での)パス(注1)
	name		# target の basename
	cputype		# 386
	objtype		# 386
	date		# 'Mon, 04 Mar 2002 07:32:40 GMT' のような時刻
注1: URI のパス部分はディレクトリの場合、REQUEST_URI は "/" で終わるが、REQUEST_PATH は "/index.html" で終わる。targetrc 流に書くと、
	target = /doc^$REQUEST_PATH
である。

他の環境変数は将来廃止されるかも知れないし、また名称が変更されるかも知れません。

POST データのハンドリング

POST データは一旦サーバ(Pegasus)がクライアントから受け取ります。(その際に実際に受け取ったデータ量と Content-Length の整合性がチェックされます。)
次にサーバ(Pegasus)はこの POST データを CGI の標準入力に渡します。(従って POST データのパーサは Content-Length を調べる必要は無いはずです。)

CGI timeout(ハンドラのタイムアウト)

問題のある CGI がいつまでもデータの到来を待っているのを防ぐためにタイムアウトが定義されています。この時間は /sys/lib/httpd.conf または httpd のオプションで指定できます。暗黙の値は 5 秒です。