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 = *OCTETCopyright(C): 2000, 魔術幻燈