CGI プログラムの入出力は HTTP(HyperText Transfer Protocol, 超越書類転送作法) に拠るので、まずは HTTP を押さえておきましょう。
2000年11月現在で最新の HTTP は、HTTP 1.1 です。
World-Wide Web は、クライアント/サーバ方式によるインターネット上の情報交換システムです。敢えて訳すなら、クライアントは主人、サーバは召使を意味するので、クライアント/サーバ・システムとは「ご主人様と奴隷もの」ということになります。
このシステムでは複数のご主人様が奴隷を共有するので、奴隷は一人でご主人様の人数分を奉仕せねばなりません。奴隷が疲れて動きがとれなくなると「遅い」「役に立たん」「もっと速い奴と取り替えろ」と文句を言われ、過労で倒れでもしたら「動かねえ」「仕事ができん」「損害が出た」などと非難囂囂、奴隷の道もなかなかに厳しいようです。
HTTP は、このご主人様と奴隷の間でやり取りする、要求 request と応答 response の作法を取り決めたものです。HTTP/1.1 の用語定義によると、(要求を出すために)接続を果たすプログラムが client、要求を執り行う client が user agent、応答を返すプログラムが server とされています。 利用者手先 user agent は同時にご主人様 client でもあるのですが、ご主人様は自ら率先して働くとは限らないわけですね。
従ってこの作法による通信は、client が接続を張った上で、user agent から server へ送られた要求について、server から user agent へ応答を返す、この繰り返しになります。この通信は、双方向ではありますが、対等ではないのです。
要求 →→→→→→→→→→→→ User Agent ------------ 接続 ------------ Server ←←←←←←←←←←←← 応答
この図は直接に繋いだときのもので、実際には間に proxy や gateway や tunnel を介することがあります。これらは要求と応答を中継するので、user agent の機能と server の機能を併せ持つプログラムになっています。
ところで、Server から返される内容が既存のファイルであれば、Server は単にファイルを探して拾ってくればいいわけです。
要求 →→→→→→ User Agent ------ 接続 ------ Server ------> ファイル ←←←←←← 応答
ここで、取ってきたものがファイルでなくプログラムであったときは、Server はプログラムを起動して入力を渡し、出力を受け取ります。この入出力の作法を、CGI (Common Gateway Interface) と呼んでいるのです。
要求 →→→→ 入力→→→→→ User Agent ---- 接続 ---- Server ---- CGI ---- プログラム ←←←← 応答 ←←←←←出力
CGI (っつーか、Gateway)自体は何も処理しません。その役割は、Server からの入力をプログラムに渡し、プログラムからの出力を Server に返す、その仲立ちをするのみです。
つまり、CGI とは World-Wide Web のために取り決められた作法の一つなのですが、プロトコルとしてはまだ仕様が固まっておらず、CGI/1.1 の確定に向けてプロジェクトが進行中です。
User Agent と Server の間でやり取りする要求 request と応答 response を、まとめて HTTP 通信文 HTTP message と呼びます。
HTTP-message = Request | Response ; HTTP/1.1 messages
この2つはいずれも RFC 822 形式の通信文で、開始行・0個以上の頭項目・頭項目の終りを示すための空行(CRLF 以外何もない行)・通信文本文から成ります。複数の頭項目は、それぞれ CRLF で区切ります。
generic-message = start-line
*(message-header CRLF)
CRLF
[ message-body ]
start-line = Request-Line | Status-Line
日本では古来より、手紙にいきなり用件を述べることは失礼とされてきました。頭語をつけ、挨拶をつけ、時候の話題について述べ、段々に用件に入るのが礼儀であったので、このような本文の前に置く文章を頭(かしら)と呼びます。今日でも文書を送るときは、何かしら挨拶の文章を置くのが普通でしょう。また、本文を始めるより前に、日付や名目や差出人などを明記するあたり、文書の頭には挨拶だけでなく、付加情報を入れることもあるわけです。
英語圏でいう header は、ほぼ日本での頭に相当します。コンピュータ通信においても、その用語と概念をそっくり拝借しているので、通信文 message は、頭 header と本文 body とに分けて構成されています。
もっとも、機械相手に挨拶は無用なので、コンピュータ通信文における頭は付加情報の塊です。
HTTP header fields として定義されている項目には、以下の4通りがあります。
項目を書く順序は決まってはいませんが、どちらかというと、この順に並べたほうがわかりやすいでしょう。
頭項目は、項目名と項目値を1行に組み合わせて書きます。名と値はコロン ":" で区切ります。ただし、項目値は空白文字から始めてよいことになっており、実際読むときには1文字開けたほうが見やすいので、コロン + 半角空白 ": " で区切ると覚えてもいいでしょう。(行継続文字として)タブか半角スペースを付ければ、単一の項目を複数の行にまたがって書くことができます。項目名には HTTP 仕様書に定められたものを使いますが、大文字・小文字は区別しません。
message-header = field-name ":" [ field-value ]
field-name = token
field-value = *( field-content | LWS )
field-content = <the OCTETs making up the field-value
and consisting of either *TEXT or combinations
of token, separators, and quoted-string>
この拡張 BNF に出てくる LWS とは Linear White Space の略で、空白文字の連続を意味します。従って、項目値は半角スペースから始めるとは限らず、タブから始めても、スペースをいくつ開けてもいいわけです。
要求と応答のいずれにも使える頭項目を、一般頭項目 General Header Fields と呼びます。
general-header = Cache-Control
| Connection
| Date
| Pragma
| Trailer
| Transfer-Encoding
| Upgrade
| Via
| Warning
通信文本文は、何らかの方式で符号化された実体を担うものとされています。文章であれば文字コード、画像であればバイナリが、ここに入るわけです。
message-body = entity-body
| <entity-body encoded as per Transfer-Encoding>
HTTP 要求文の第1行には、素材に適用されるべき手法、素材の識別子、利用する作法の版番号が入れられます。
Request = Request-Line
*(( general-header
| request-header
| entity-header ) CRLF)
CRLF
[ message-body ]
要求行は手法の指定をもって始め、次に要求する URI と作法の版番号を書き、CRLF で終わります。各要素は空白文字で区切ります。要求行の途中に CR あるいは LF を入れてはなりません。
Request-Line = Method SP Request-URI SP HTTP-Version CRLF
この拡張 BNF に出てくる SP とは Space の略で、US-ASCII 32 番を指します。
手法指定は、要求 URI で識別された素材を取り扱う手法を示すものです。大文字・小文字は区別しません。
Method = "OPTIONS"
| "GET"
| "HEAD"
| "POST"
| "PUT"
| "DELETE"
| "TRACE"
| "CONNECT"
| extension-method
extension-method = token
要求 URI は、定型素材識別子及び要求に適応する素材の識別子群です。
Request-URI = "*" | absoluteURI | abs_path | authority
この4つのうちいずれを使うかは、要求次第です。例えば、proxy に対しては絶対 URI を使う必要があります。絶対 URI を使うなら、要求行全体は次のような形になります。
GET http://www.w3.org/pub/WWW/TheProject.html HTTP/1.1
もっとありがちな使い方としては、元のサーバあるいは gateway 上の素材を指定することでしょう。
絶対 URI を使ってもいいのですが、ホストから見た経路を指定したほうが簡潔になります。この経路指定を使うときは
GET /pub/WWW/TheProject.html HTTP/1.1
Host: www.w3.org
のようにします。
要求の際に追加できる頭を、要求頭 request-header と呼びます。追加情報のみならず、client 自体の情報も含まれます。
request-header = Accept
| Accept-Charset
| Accept-Encoding
| Accept-Language
| Authorization
| Expect
| From
| Host
| If-Match
| If-Modified-Since
| If-None-Match
| If-Range
| If-Unmodified-Since
| Max-Forwards
| Proxy-Authorization
| Range
| Referer
| TE
| User-Agent
サーバは受け取った要求に対して、HTTP 応答文 HTTP response message を返します。
Response = Status-Line
*(( general-header
| response-header
| entity-header ) CRLF)
CRLF
[ message-body ]
応答文第1行は、状況行 Status-Line です。これは、作法の版番号・数字による状況符号・関連語句、及び各要素を区切る空白文字から構成されます。状況行の途中に CR あるいは LF を入れてはなりません。
Status-Line = HTTP-Version SP Status-Code SP Reason-Phrase CRLF
状況符号は、3桁の数字です。最初の数字が、5級までの応答の階級を示します。
HTTP/1.1 に定められた全コードは、次のとおりです。
Status-Code =
"100" ; Section 10.1.1: Continue
| "101" ; Section 10.1.2: Switching Protocols
| "200" ; Section 10.2.1: OK
| "201" ; Section 10.2.2: Created
| "202" ; Section 10.2.3: Accepted
| "203" ; Section 10.2.4: Non-Authoritative Information
| "204" ; Section 10.2.5: No Content
| "205" ; Section 10.2.6: Reset Content
| "206" ; Section 10.2.7: Partial Content
| "300" ; Section 10.3.1: Multiple Choices
| "301" ; Section 10.3.2: Moved Permanently
| "302" ; Section 10.3.3: Found
| "303" ; Section 10.3.4: See Other
| "304" ; Section 10.3.5: Not Modified
| "305" ; Section 10.3.6: Use Proxy
| "307" ; Section 10.3.8: Temporary Redirect
| "400" ; Section 10.4.1: Bad Request
| "401" ; Section 10.4.2: Unauthorized
| "402" ; Section 10.4.3: Payment Required
| "403" ; Section 10.4.4: Forbidden
| "404" ; Section 10.4.5: Not Found
| "405" ; Section 10.4.6: Method Not Allowed
| "406" ; Section 10.4.7: Not Acceptable
| "407" ; Section 10.4.8: Proxy Authentication Required
| "408" ; Section 10.4.9: Request Time-out
| "409" ; Section 10.4.10: Conflict
| "410" ; Section 10.4.11: Gone
| "411" ; Section 10.4.12: Length Required
| "412" ; Section 10.4.13: Precondition Failed
| "413" ; Section 10.4.14: Request Entity Too Large
| "414" ; Section 10.4.15: Request-URI Too Large
| "415" ; Section 10.4.16: Unsupported Media Type
| "416" ; Section 10.4.17: Requested range not satisfiable
| "417" ; Section 10.4.18: Expectation Failed
| "500" ; Section 10.5.1: Internal Server Error
| "501" ; Section 10.5.2: Not Implemented
| "502" ; Section 10.5.3: Bad Gateway
| "503" ; Section 10.5.4: Service Unavailable
| "504" ; Section 10.5.5: Gateway Time-out
| "505" ; Section 10.5.6: HTTP Version not supported
| extension-code
extension-code = 3DIGIT
Reason-Phrase = *<TEXT, excluding CR, LF>
応答頭項目は、サーバから返される応答に追加できる頭です。これにはサーバ自体の情報や、目当ての素材に関する情報などが含まれます。
response-header = Accept-Ranges ; Section 14.5
| Age ; Section 14.6
| ETag ; Section 14.19
| Location ; Section 14.30
| Proxy-Authenticate ; Section 14.33
| Retry-After ; Section 14.37
| Server ; Section 14.38
| Vary ; Section 14.44
| WWW-Authenticate ; Section 14.47
要求及び応答通信文は、要求の手法や応答文の状況符号によって制限されていない限り、実体へ変換してかまいません。実体は、実体の頭項目と実体の本文から成ります。
実体頭項目は、実体本文あるいは目当ての素材に関わる前置情報を定義します。これら前置情報には追加的なものもあり、必須とされるものもあります。
entity-header = Allow ; Section 14.7
| Content-Encoding ; Section 14.11
| Content-Language ; Section 14.12
| Content-Length ; Section 14.13
| Content-Location ; Section 14.14
| Content-MD5 ; Section 14.15
| Content-Range ; Section 14.16
| Content-Type ; Section 14.17
| Expires ; Section 14.21
| Last-Modified ; Section 14.29
| extension-header
extension-header = message-header
HTTP 要求あるいは応答をもって送られる実体本文は、実体頭項目で定義された形式及び符号化に則ります。
entity-body = *OCTET
Copyright(C): 2000, 魔術幻燈