3部 CGI リファレンス

HTTPプロトコル

1.リクエストヘッダとレスポンスヘッダ

インターネット上のサービスのほとんどはHTTPというプロトコルを利用しています。この仕様を抑えておけば、CGIプログラムの理解もより深まると思います。

HTTPプロトコルの概要

ウェブブラウザとウェブサーバは、『HTTP』というプロトコルを通じてメッセージの交換を行います。HTTPは、HTMLやテキストファイル、画像などのリソースをクライアントに送信するためのプロトコルとして開発されました。メッセージにはASCII コードを使用しているので、リソースに特殊文字や、日本語のような複数バイトの文字コードが含まれている場合は、『URL エンコード』と呼ばれる加工が施されてから送信されます。

HTTPのメッセージには、クライアント側が送信するリクエストヘッダ(request header)と、サーバ側が送信するレスポンスヘッダ(response header)の2種類があります。リクエストヘッダに関してはウェブサーバが処理するのでCGIの出番はありませんが、レスポンスヘッダはCGIで出力することができます。

CGIからレスポンスヘッダを出力し、ブラウザにページを表示させることはとても簡単です。

HTMLを出力する単純なプログラム
#!/user/bin/perl
# レスポンスヘッダの出力
print "Content-type: text/html", "\n\n";
# HTMLの出力
print "<HTML>\n";
print "<BODY>\n";
print "ようこそCGIの世界へ!<BR>\n";
print "</BODY>\n";
print "</HTML>\n";

上記プログラムは、レスポンスヘッダを最初に出力し、次にHTMLを出力しているだけです。レスポンスヘッダにはさまざまな種類がありますが、ページを表示させるだけでしたら、Content-Typeを出力するだけで済みます。

ウェブブラウザとウェブサーバ間の通信

それでは、クライアントのブラウザからリクエストが送られてきたあと、ウェブサーバがレスポンスヘッダを返すまでの流れをざっと追っていきましょう。

  1. クライアントからサーバへリクエストが送信されます。
  2. クライアントからリクエストされたアドレスが CGIプログラムを指していれば、サーバはファイルの内容を表示する代わりにプログラムを実行させます。
  3. プログラムは必要な処理を行った後、リソースの内容やURLをウェブサーバに返します。
  4. プログラムの出力はウェブサーバの『標準出力』(STDOUT)に送られ、そこで正式なフォーマットに作り直されてから、最終的にクライアント側に送信されます。
用語
HTTP
(Hypertext Transfer Protocol)
TCP上で動作するプロトコル。サーバとクライアントとの間でデータをやりとりるための伝送機構。Webサーバとクライアントがデータを送受信するのに使われるプロトコル。HTML文書や、文書に関連付けられている画像、音声、動画などのファイルを、表現形式などの情報を含めてやり取りできる。SMTP、NNTP、FTPプロトコルなどの一般的なプロトコルとしても使用されます。
URL エンコード
複数バイトの文字コードなどを URL として利用できるようにエンコードすることを意味します。
標準出力
プロセスの処理結果を出力するための機構。デフォルトはディスプレイなどの画面デバイスがオープンされますが、他のプロセスやファイルに切り替えることもできます。

HTTPヘッダをTELNETから見てみよう

ウェブブラウザがHTMLや画像をリクエストするときは、HTTPヘッダのGETメソッドを使って、対象となるファイルを指定しています。

GET /test.html HTTP/1.0

上記では、「/test.html」ファイルの要求と、通信プロトコルHTTP/1.0を使うことを指定しています。

実際にブラウザがウェブサーバにリクエストしているのを見ることは難しいですが、ブラウザを使わずに直接ウェブサーバにリクエストを行い、それに対してウェブサーバがどう答えるかを見ることはできます。ウェブサーバに直接リクエストを送るには、telnetと呼ばれるソフトウエアを使用します。
ウインドウズでしたら、「ハイパーターミナル」というソフトウエアが標準でインストールされています。CGIを本格的に使うのでしたら、より高機能なTera Term Proというフリーソフトのご利用をオススメします。

Tera Term関連ホームページ
  • UTF-8対応Tera Term
    Tera Termの後継バージョンで、新たにSSH接続、UTF-8への対応が施されています。
telnet
別のコンピュータに接続し、操作するためのソフトウエアの総称です。

それでは、telnetからウェブサーバに接続して、ファイルを指定して画面に表示させてみましょう。telnetを起動し、目的のサーバに接続、ログインしてください。コマンドラインが表示されたら、次のように入力していきます。太字が入力した行で、それ以外がウェブサーバが返した行になっています。

> telnet www.***.jp 80
Trying 123.123.123.98...
Connected to www.sampledomain.co.jp.
Escape character is '^]'.
GET /test.html HTTP/1.0

HTTP/1.1 200 OK
Date: Wed, 03 Jan 2001 17:22:53 GMT
Server: Apache/1.3.9 (Unix)
Connection: close
Content-Type: text/html

<html><body>
test.<br>
</body></html>

上記の例では、telnetコマンドで通信ポート80番を使って「www.***.jp」というドメインに接続しています。その後、GETメソッドを使って「test.html」ファイルを要求しています。ウェブサーバはGETメソッドの要求にしたがって、いくつかの必要なHTTPヘッダを出力し、空行の後に「test.html」ファイルの内容を出力しています。

HTTPヘッダを使ってダイナミックドキュメントを出力

CGIを使ってダイナミックドキュメントを出力するには、その内容の前にレスポンスヘッダを出力する必要があります。上記で行ったウェブサーバ接続へのテストで、ウェブサーバが出力したHTTPメッセージは、「HTTP/1.1 200 OK」から「Content-Type: text/html」の範囲です。完全なHTTPメッセージをプログラムで出力すると、次のようになります。

完全なHTTP メッセージを出力するプログラム
#!/user/local/bin/perl
# 完全なレスポンスヘッダの出力
print "HTTP/1.1 200 OK\n";
print "Date: Wed, 03 Jan 2001 17:22:53 GMT\n";
print "Server: Apache/1.3.9 (Unix)\n";
print "Connection: close\n";
print "Content-Type: text/html", "\n\n";
# HTMLの出力
print "<HTML>\n";
print "<BODY>\n";
print "ようこそCGIの世界へ!<BR>\n";
print "</BODY>\n";
print "</HTML>\n";

ここで出力しているヘッダは、通信プロトコル、応答の日付と時間、サーバ名とバージョン、データの種類です。もちろん、先に紹介したサンプルプログラムのように、Content-Type と空行を出力するだけでも、ブラウザ側にダイナミックドキュメントを表示させることができます。

CGIプログラムからHTMLを出力したいときは、最低でも下記のようにContent-Typeと空行を出力します。あとはサーバが、足りないヘッダを追加して送ってくれます。

print "Content-Type: text/html", "\n\n";

HTTPは単純なプロトコルです。ヘッダ行は特別な順序にする必要がありませんし、ヘッダの終了は空行で見分けられます。上記では、「Content-Type: text/html」の後の空行でヘッダの終了を宣言しているので、その後に続く行でリソースの内容(HTMLなど)を出力するだけで終わりです。

HTMLからフォーム内容を送信するには、リクエストヘッダを理解しておいたほうがいいね。それから、CGI プログラムからHTMLや画像を出力する際は、レスポンスヘッダを出力する必要があるんだ。これを指定しないと、いつまでたってもブラウザに出力されることはないよ。


1.ブラウザが出力するリクエストメッセージ

ブラウザが送信するリクエストには、リソースの要求以外にも沢山の種類があります。リクエストはウェブサーバが処理するものなので、CGI側で意識するような場面はほとんどありませんが、そのいくつかは間接的に利用されています。その代表的なものがRefererやUser-Agentで、これらのヘッダは環境変数という機構に格納されて、CGIからアクセスすることが可能です。

リクエストヘッダ

ここでは、代表的なリクエストヘッダを紹介しておきましょう。

主なリクエストヘッダ一覧

フィールド名 説明
If-Modified-Since キャッシュの有効性の確認
このフィールドで指定した日付と、リソースの更新日を比較し、リソースのほうが新しい場合のみデータを取得できるように指示します。
Referer 直前にリンクされていたURL情報
User-Agent ブラウザの固有情報
Accept 利用可能なアプリケーション・メディアタイプ
複数指定し、優先度を付けることが可能です。
Accept-Charset 利用可能な文字セット
Accept-Encoding 利用可能なエンコーディング形式
Accept-Language 利用可能な言語コード
複数指定し、優先度を付けることが可能です。

リクエスト・メソッド

リクエストはブラウザが出力するものですが、その内容は HTMLから指定することが可能です。リクエストメッセージ群には必ずメソッドと呼ばれるリクエスト行が含まれています。

メソッドとは、サーバにリクエストを指示するための命令です。HTTPで定義されているメソッドを紹介しましょう。

HTTP1.0で定義されているメソッド一覧

メソッド 説明
DELETE URLで指定したリソースを削除
GET URLで指定したリソースを取得
レスポンスのボディにはリソースのデータが含まれます。
HEAD URLで指定したリソースについてのレスポンスヘッダのみ取得
POST 指定したURLが示すサーバーのコマンドに対して、データを転送
リクエストのボディには転送するデータが含まれます。
PUT 指定したURLが示すリソースに対して、データを転送して置き換え
リクエストのボディには置き換えるデータが含まれます。

LINK
(廃止されました)

UNLINK
(廃止されました)

HTTP1.1で定義されているメソッド一覧

メソッド 説明
TRACE サーバーやプロキシの動作を診断するための情報を返答
OPTIONS 使用できるメソッドやオプションの一覧を取得
CONNECT プロキシでのトンネリング接続を行う

メソッドの中で実際によく利用されるのは GET メソッドPOST メソッドです。それ以外のメソッドは、セキュリティ上の問題などにより、実際に実装されているケースはほとんどありません。

GET メソッド

GETメソッドはHTMLページや画像ファイルの取得に使用され、デフォルトのメソッドとなっています。例えばURLアドレスを指定されたり、リンクをクリックした場合には、GETメソッドとしてウェブサーバに送信されます。

GETの一般的な使い方はとても簡単です。アンカータグのhref属性の値に、クエリを追加するだけです。HTMLドキュメントでGETを使うには、次のようにします。

<a href="/cgi-bin/query.cgi?post_data=1">...</a>

上記では、ファイル名の後にクエスチョン( ? )を挟んでGETを指定しています。クエスチョン以降の「post_data=1」がクエリデータとして環境変数QUERY_STRINGに格納されます。ただし、渡されるデータがリミットを越えると、超えた分の値が切り捨てられます。

環境変数QUERY_STRINGを使用すれば、このクエリ情報にアクセスすることができます。CGIからQUERY_STRINGを利用する方法は「環境変数」の章で詳しく説明しますが、簡単な利用法を紹介しておきましょう。環境変数を参照するには、下記のように%ENV変数を使って呼び出します。

# 環境変数 QUERY_STRING の値を $query_string に代入
$query_string = $ENV{'QUERY_STRING'};

GETはリクエストヘッダのデフォルトです。リンクをクリックしたり、アドレスバーにURLを指定した場合もGETになるので、ほとんどのリクエストスヘッダが
GET によるリクエストになるといえるでしょう。

POST メソッド

HTMLページのフォームなどのデータは、POSTメソッドによって送信されるのが一般的です。

POSTは HTTPヘッダのボディ部でデータを送信します。各パラメータは標準入力で渡されます。データの長さ(バイト数)は環境変数CONTENT_LENGTHに格納されています。

POSTの主な特徴は、クエリのサイズに制限がないことです。したがって、クライアントやサーバがデータを切り捨ててしまうことはありません。POSTによって送られたデータは、標準出力から取得することができます。

POSTは明示的に指定しないと使われません。HTMLのフォームタグでMETHOD属性にPOSTを指定します。

<FORM METHOD="POST"
action=
"test01.cgi">

2つのうちどちらかの方法でデータを送るかが決まると、データは指定された形式で送信されます。


2.CGI から出力できるレスポンスヘッダ

レスポンスヘッダは、ウェブサーバからブラウザに送信する HTTPメッセージです。基本的にはウェブサーバがレスポンスヘッダを送信するのですが、CGIプログラムからウェブサーバにレスポンスヘッダを出力することで、間接的にブラウザに返すことができます。その際、CGIプログラムは最低限「Content-type」を出力する必要があります。するとウェブサーバは、CGIプログラムが生成したヘッダを解析して、必要なヘッダを付け足してブラウザに送り返します。

レスポンス・ヘッダ

主なレスポンス・ヘッダ一覧

フィールド名 内容
Server ウェブサーバの名前とバージョン情報。
Date 現在の日付(グリニッジ標準時)
Last-Modified リソースの更新日
Content-Length 出力のバイト単位の長さ
バイナリデータも含みます。
Content-Type 出力のMIMEタイプ
Expires リソースの有効期限
この日付以降は無効です。キャッシュは破棄されます。
Location リダイレクト URL 情報
Location で指定されたリソースが送信されます。
単独ヘッダとして出力されます。
Pragma リソースのキャッシングを有効/無効にする
「Pragma: no-cache」と指定すると、リソースのキャッシュを無効にします。
Status リクエストのステータス
単独ヘッダとして出力されます。
WWW-Authenticate 認証データ。
認証に必要なユーザー名やパスワードなどの情報が含まれます。
Refresh 指定されたドキュメントを再ロードする。
Set-Cookie データをクライアント側に保存する。

レスポンスヘッダの構造

ウェブサーバからブラウザに送られる出力内容は、レスポンスヘッダとボディの2つです。HTTPヘッダはeメールで使用されている『MIME』に似たメッセージです。
CGIプログラムがこのメッセージの出力を忘れると、クライアント側のブラウザは正しくデータを受け取ることができず、サーバエラーのメッセージを表示します。ボディは、ヘッダで指定したフォーマットのデータタイプです。一般的なデータタイプはHTMLや画像です。

用語
MIME
MIME(Multipurpose Internet Mail Extensions)
MIMEは、元々は電子メールを通じて複数のデータタイプを送るために開発されたものです。MIMEタイプは、Web上のから送信されるデータタイプを識別するために使用されます。

Status : ステータスコード

ステータスコードは、リクエストの結果を知らせるための情報です。ウェブサーバは、ブラウザからのリクエストを正しく処理すると、次のようなステータスコードを返します。

HTTP/1.1 200 OK

ステータスコードはブラウザからのリクエスト結果を知らせるヘッダです。100番代から500番代までの状態コードが用意されています。CGIからこのヘッダを出力することはほとんどありませんが、CGIでエラーが発生したときなどは、ブラウザがこのステータスコードを表示します。

CGI エラーが発生した場合、ブラウザに次のようなメッセージが表示されることがあります。

Internal Server Error
The server encountered an internal error or
misconfiguration and was unable to complete your
request.
Please contact the server administrator.....

Additionally, a 404 Not Found error was encountered
while trying to use an ErrorDocument to handle the
request.

このときのページタイトルは「500 Internal Server Error」となっていて、ウェブサーバからステータスコード500番が返されたことがわかるようになっています。ステータスコード500番は「リクエストを実行中に予期しないエラーが発生した」というメッセージですので、CGIが原因ということが予測できます。
また、リクエストしたリソースへのアクセスが拒否された場合などは、ブラウザがエラー内容を表示し、そのページタイルが「403 Forbidden」となります。これで、CGIのエラーではなく、URLのタイプミスかファイルの属性の問題などにより、アクセスが拒否されたということが予測することができます。

Content-Type

Content-Type ヘッダは、CGI プログラムで最もよく使用する HTTPヘッダで、プログラムが出力する MIME タイプの情報をサーバやブラウザに伝えます。

書式は次のようになります。

Content-Type: media_type

media_type には、プログラムが出力する MIME タイプが入ります。MIMEタイプには一般タイプと特殊タイプの2タイプを明記します。

たとえば、HTML として出力したい場合は、一般タイプが text、特殊タイプが htmlになるので、次のように print を使って出力します。

print "Content-type: text/html", "\n\n";

主な MIME タイプは次の表のとおりです。

MIMEタイプ 説明
text/html HTML文書
text/plain テキストファイル
image/gif GIFファイル
image/jpeg JPEGファイル
video/mpeg MPEGファイル

登録されているMIME タイプ一覧

charset

Content-Type の行で、文字符号コードを指定することもできます。

Content-Type: text/html; charset=UTF-8

文字コードラベルの一覧

以下の一覧は、インターネットで使用可能な文字符号コードラベルの一部です。

文字コードラベル ラベルのエリアス名
ISO-2022-JP csISO2022JP
ISO-2022-JP-2 csISO2022JP2
Shift_JIS MS_Kanji /
csShiftJIS
UTF-8 -
Extended_UNIX_Code_Packed_Format_for_Japanese csEUCPkdFmtJapanese /
EUC-JP

指定できる文字コードの一覧

Character Set Recognition (Internet Explorer)

レスポンスヘッダのcharsetパラメータの代わりに、HTMLドキュメントのMETA要素で文字符号コード化を指定することもできます。

例えば、HTMLドキュメントの文字符号コード化がUTF-8の場合、以下のようなMETA宣言を記載します。

<META http-equiv="Content-Type" content="text/html; charset=utf-8">

Content-Length

HTTPを使って画像などのバイナリファイルを送信するときは、ファイルサイズの情報も一緒に送信するとよいでしょう。ファイルをブラウザに送信している途中で問題が発生しても、このヘッダ情報があればブラウザはファイルが完全に送信されていないことを知ることができます。また、このヘッダ情報を利用して、ダウンロードまでの時間をリアルタイムにユーザに伝えることもできます。

書式は次のようになります。

Content-length: number_of_bytes

CGI で画像を出力するには、次のような方法になるでしょう。

# -s オプションでファイルのバイト数を調べています
$length = -s $file;
print "Content-type: image/gif", "\n";
print "Content-length: $length", "\n\n";

Location

Locationヘッダを使うと、任意のリソースをブラウザに送るようにウェブサーバに命令することができます。Locationヘッダの引数には、URL 形式のパスを指定します。

書式は次のようになります。

Location: URL

URL には再読み込みを行うページの URL を指定します。

Locationヘッダの出力
#! /usr/local/bin/perl
print "Location: /thanks.html", "\n\n";

ローカルのドキュメント以外にも、インターネット上のドキュメントを返すことができます。

print "Location: http://www.rfs.jp", "\n\n";

Refresh

このヘッダは、指定した時間が経過した後に任意の URL を再読み込みさせることができます。

Refresh: second; URL

second には再読み込みまでの待機時間を秒で指定し、URL には再読み込みを行うページの URLを指定します。

60秒後に「http://www.rfs.jp/」サイトを読み込ませるには、次のようにします。

print "Refresh: 60; http://www.rfs.jp/", "\n\n";

キャッシュの無効:Expiresヘッダ/Pragmaヘッダ

多くのブラウザは読み込んだHTMLファイルをキャッシュすることができます。キャッシュを無効にするには、Expires
ヘッダまたは Pragma ヘッダを使います。

Pragma で指定する場合は「no-cashe」オプションを使います。

print "Content-type: text/html", "\n";
print "Pragma: no-cache", "\n\n";

Expires を使う場合は古い日付を指定します。

print "Content-type: text/html", "\n";
print "Expires: Wednesday, 03-Jan-01 17:22:53 GMT", "\n\n";

※いくつかのブラウザはこれらの指定を無視します。

HTTPヘッダ関連サイト

関連記事