Logo address

実行ハンドラ

目次

2002/08/30

実行ハンドラと言うのは多分 Pegasus 独自の機能で、特定のパスパターンのファイルに対して、それを処理するプログラムをユーザが指定あるいは組み込める機能です。
Pegasus ではこれを、CGI プログラムの定義や SSI (server side include) の機能の実現、さらにある特定のディレクトリに対して index.html が存在しない場合にファイルの一覧を表示する機能の実現のために使用されています。

設定の方法

サービス空間の中の
	/etc/handler
に、パスパターンとコマンドを結びつける行を書く。筆者のサーバ(http://plan9.aichi-u.ac.jp)のファイルの内容は次のようなものです。
	# path      mimetype    ramfs    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項と第3項)を表しています。パスパターンの比較は上の行から行われ、マッチすればそこで終ります。第5項目以降でプログラムの引数を指定する事もできます。

パスパターンの指定において `/' は基本的に他の文字と同じ扱いですが(従ってシェルのパスパターンの扱いと同じではありません)、1つの例外があります。

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

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

第3項はプログラムの実行に伴って ramfs がサービスされるか否かを表しています。

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

第5項目以降に実行プログラムの引数を書くことができます。(Pegasus 1.1 では引数の最後が $target で終る場合には、$target を省略できました。この省略形は廃止します。)

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

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

Apche の 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 を指定した場合には単に HTML 形式、即ち
	<html>
	...
	</html>
だけを書き出します。Apche の CGI は
	Content-Type: text/html

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

Content-length の値は、CGI プログラムが全てのデータを書き出すまで分かりません。そのため Pegasus の現在の版では Content-length を省いています。その場合にはクライアントは

	Connection: close
が指定されたものと解釈し、CGI が出力したデータを受け取った後、接続を切ってしまいます。

Pegasus 1.0 では 「CGI」と言う用語は意味を失っているのですが、慣用的にハンドラの意味でこの言葉の使用を継続する事にします。

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.cgi
で再編成できます。
ユーザ独自の CGI ツールを追加したい場合には、このファイルの内容を
	bind -a /etc/bin/$objtype /bin
	bind -a /etc/bin/rc /bin
として、サービス空間の /etc/bin/386/etc/bin/rc にツールを置きます。

このファイルが存在しない場合、あるいは存在しても再編成をしていない場合には、CGI プログラムが見る名前空間はサービス空間と同じです。

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
	home		# /doc
	query		# QUERY_STRING に同じ
	target		# 要求されたドキュメントの(サービス空間での)パス
	name		# taget の basename
	cputype		# 386
	objtype		# 386
	date		# 'Mon, 04 Mar 2002 07:32:40 GMT' のような時刻
他の環境変数は将来廃止されるかも知れないし、また名称が変更されるかも知れません。

POST データのハンドリング

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

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

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