実行ハンドラ
目次- 1.0.0 配置
- 2.0.0 説明
- 3.0.0 設定の方法
- 4.0.0 Apache の CGI との比較
- 5.0.0 CGI プログラムにおけるエラー処理
- 6.0.0 CGI 記述言語
- 7.0.0 URI との関係
- 8.0.0 CGI の名前空間(ハンドラの名前空間)
- 9.0.0 CGI の環境変数(ハンドラの環境変数)
- 10.0.0 POST データのハンドリング
- 11.0.0 CGI timeout(ハンドラのタイムアウト)
配置
$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
ファイルは存在意義を失ったといえます。mimetype
で text/html
が指定された場合にはサーバが自動的にヘッダを作成しクライアントに送ります。その場合のレスポンスヘッダは次のルールに従います。
- exit status に文字列が与えられない場合には成功と見なし、
"200 OK"
にします。
接続は維持されます。
- exit status が HTTP の正式なレスポンスヘッダ(先頭3文字が数字で、次に空白が続く)であれば、それをそのままレスポンスヘッダとして採用します。
コード番号が 100 から 299 までは接続は維持されます。それ以外の場合には接続は切られます。
- exit status が HTTP の規則に従わない場合には、Pegasus のこれまでの版との互換性を保ち、
"200 OK"
を送り、接続を切ります。
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 のドキュメントへのパスに続いてparam
と query
を書くことができます。即ち、次の様になっています。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' のような時刻
REQUEST_URI
は "/
" で終わるが、REQUEST_PATH
は "/index.html
" で終わる。target
は rc
流に書くと、target = /doc^$REQUEST_PATHである。
他の環境変数は将来廃止されるかも知れないし、また名称が変更されるかも知れません。
POST データのハンドリング
POST データは一旦サーバ(Pegasus)がクライアントから受け取ります。(その際に実際に受け取ったデータ量とContent-Length
の整合性がチェックされます。)次にサーバ(Pegasus)はこの POST データを CGI の標準入力に渡します。(従って POST データのパーサは
Content-Length
を調べる必要は無いはずです。)
CGI timeout(ハンドラのタイムアウト)
問題のある CGI がいつまでもデータの到来を待っているのを防ぐためにタイムアウトが定義されています。この時間は/sys/lib/httpd.conf
または httpd
のオプションで指定できます。暗黙の値は 5 秒です。