Mod_Rexxは強力なパッケージであり、REXXプログラマーはこれを使用して、Apacheの要求の処理を完全に制御することが可能です。要求を受信すると、Apacheは要求の処理を以下の複数のフェーズに分割します。
図1. ApacheによるHTTP要求の処理
図1の各フェーズは、以下に示すとおり、要求の各部分の処理を担当します。
- 読み取り後の要求 (post read request) により、要求が読み取られた後に要求を修正できます。
- URI変換 (URI translation) により、物理ファイル、外部スクリプトによって作成された仮想文書、または内部モジュールによって生成された文書へのURI要求をマップします。
- ヘッダー・パーサー (header parser) により、要求ヘッダーを調べることも可能です。
- アクセス制御 (access control) により、認証と許可を処理します。また、ブラウザーのIPアドレス、ホスト名、あるいは任意の別の単純な属性に基づいて、簡易なアクセス制御を行うことができます(これは、認証と許可処理を行う3つのフェーズの第1フェーズです)。
- 認証 (authentication) により、ユーザーIDとパスワードの検査が行われます。認証処理は、要求ファイルにパスワードがかけられている場合は常に呼び出されます(これは認証と許可処理の第2フェーズです)。
- 許可 (authorization) により、ユーザーが、要求したURIに対するアクセス権を実際に保持しているかどうかを判別します(これは認証と許可処理の最後の第3フェーズです)。
- MIMEタイプの検査 (MIME type check)により、要求に対するMIMEタイプを暫定的に割り当てます。
- 修正 (fixup) は、「応答」フェーズが呼び出される前に、要求を修正する最後の機会です。
- 応答 (response)(応答ハンドラー) により、ファイルを戻すことによって要求された情報がブラウザーに (動的または静的に) 戻されます(この処理は、コンテンツ・ハンドラー・フェーズとも呼ばれます)。このハンドラーの動作はCGIプログラムに若干似ていますが、このフェーズの実行環境は、従来のCGI環境とはかなり異なります。
- ロギング (logging) により、要求をログに記録します。
各フェーズには、REXXスクリプトを割り当てることができます。スクリプトを割り当てるのは、ほとんどの場合、応答フェーズのみですが、REXXスクリプトはすべてのフェーズを十分に処理できます。Mod_RexxはApacheの構成ファイルに記述されるディレクティブと、特定の要求フェーズへのREXXスクリプトの割り当てを定義します。
Apacheの要求フェーズの動作についての詳細は、Apache拡張ガイド (上) (下)(この記事の後半の参考文献を参照) をお読みになることを強くお勧めします。
REXXスクリプトとMod_Rexxを併用する方法は、Apacheの応答フェーズのハンドラーとして、最も頻繁に行われます。ApacheがドキュメントをREXXプログラムとして認識するには、以下のディレクティブをApacheの構成ファイル (通常はhttp.conf) に記述する必要があります。
AddType application/x-httpd-rexx-script .rex .rexx |
このディレクティブにより、ファイル拡張子 .rexおよび .rexxをMod_Rexxに割り当てて、処理を行うことができます。Mod_RexxはREXX言語プロセッサーを呼び出し、ドキュメント (スクリプトも可) をプロセッサーに渡して処理を行います。Mod_Rexxは、スクリプトを実行するための特別な環境を作成します。スクリプトには、事前定義されたREXX変数と外部関数が含まれています。
ファイル拡張子をREXXスクリプトに割り当てたら、以下の標準的なURIを用いてファイルを呼び出すことができます。
http://your.domain.com/myscript.rex |
このURIは、メインのApacheドキュメントのサブディレクトリーにあるmyscript.rexというREXXスクリプトを呼び出し、このスクリプトをApacheの応答ハンドラーとして実行します。応答ハンドラーとして使用するREXXスクリプトの簡単な例を検討してみましょう。
"
/* these are some typical Apache return codes */
DECLINED = -1 /* Module declines to handle */
OK = 0 /* Module has handled this stage. */
/* get the Apache request record ptr */
r = arg(1)
/* set content-type and send the HTTP header */
call WWWSendHTTPHeader r, "text/html"
call WWWGetArgs r
/* start sending the html page */
say "<html>"
say "<head>"
say "<title>Sample HTML Page From Rexx</title>"
say "</head>"
say "<body>"
say "<h1>Sample HTML Page From Rexx</h1>"
say '<p>The Mod_Rexx version string is "'WWWGetVersion()'"'
say "<p>The following is the list of standard Rexx CGI variables and their values:"
say '<table border="1"><tr><th>Name</th><th>Value</th></tr>'
say "<tr><td>WWWAUTH_TYPE</td><td>"vorb(wwwauth_type)"</td></tr>"
say "<tr><td>WWWCONTENT_LENGTH</td><td>"vorb(wwwcontent_length)"</td></tr>"
say "<tr><td>WWWCONTENT_TYPE</td><td>"vorb(wwwcontent_type)"</td></tr>"
say "<tr><td>WWWGATEWAY_INTERFACE</td><td>"vorb(wwwgateway_interface)"</td></tr>"
say "<tr><td>WWWHTTP_USER_ACCEPT</td><td>"vorb(wwwhttp_user_accept)"</td></tr>"
say "<tr><td>WWWHTTP_USER_AGENT</td><td>"vorb(wwwhttp_user_agent)"</td></tr>"
say "<tr><td>WWWPATH_INFO</td><td>"vorb(wwwpath_info)"</td></tr>"
say "<tr><td>WWWPATH_TRANSLATED</td><td>"vorb(wwwpath_translated)"</td></tr>"
say "<tr><td>WWWQUERY_STRING</td><td>"vorb(wwwquery_string)"</td></tr>"
say "<tr><td>WWWREMOTE_ADDR</td><td>"vorb(wwwremote_addr)"</td></tr>"
say "<tr><td>WWWREMOTE_HOST</td><td>"vorb(wwwremote_host)"</td></tr>"
say "<tr><td>WWWREMOTE_IDENT</td><td>"vorb(wwwremote_ident)"</td></tr>"
say "<tr><td>WWWREMOTE_USER</td><td>"vorb(wwwremote_user)"</td></tr>"
say "<tr><td>WWWREQUEST_METHOD</td><td>"vorb(wwwrequest_method)"</td></tr>"
say "<tr><td>WWWSCRIPT_NAME</td><td>"vorb(wwwscript_name)"</td></tr>"
say "<tr><td>WWWSERVER_NAME</td><td>"vorb(wwwserver_name)"</td></tr>"
say "<tr><td>WWWSERVER_PORT</td><td>"vorb(wwwserver_port)"</td></tr>"
say "<tr><td>WWWSERVER_PROTOCOL</td><td>"vorb(wwwserver_protocol)"</td></tr>"
say "<tr><td>WWWSERVER_SOFTWARE</td><td>"vorb(wwwserver_software)"</td></tr>"
say "</table>"
say "<p>The following are some additional variables provided to the Rexx program:"
say '<table border="1"><tr><th>Name</th><th>Value</th></tr>'
say "<tr><td>WWWDEFAULT_TYPE</td><td>"vorb(wwwdefault_type)"</td></tr>"
say "<tr><td>WWWFILENAME</td><td>"vorb(wwwfilename)"</td></tr>"
say "<tr><td>WWWFNAMETEMPLATE</td><td>"vorb(wwwfnametemplate)"</td></tr>"
say "<tr><td>WWWIS_MAIN_REQUEST</td><td>"vorb(wwwis_main_request)"</td></tr>"
say "<tr><td>WWWRSPCOMPILER</td><td>"vorb(wwwrspcompiler)"</td></tr>"
say "<tr><td>WWWSERVER_ROOT</td><td>"vorb(wwwserver_root)"</td></tr>"
say "<tr><td>WWWUNPARSEDURI</td><td>"vorb(wwwunparseduri)"</td></tr>"
say "<tr><td>WWWURI</td><td>"vorb(wwwuri)"</td></tr>"
say "</table>"
say "</body>"
say "</html>"
return OK
/* vorb: return the value or a required space */
vorb:
if length(arg(1)) > 0 then return arg(1)
else return ' '
|
リスト1の最初の数行は、処理の成功または失敗、あるいはスクリプトの戻り値に関する特別な情報をApacheが判別するための標準戻りコードです。戻りコードがゼロ (OK) の場合は、ハンドラーがそのフェーズの処理を完了し、Apacheによる追加処理は必要がないということを示します。戻りコードが -1 (DECLINED) の場合は、このハンドラーが要求の処理を拒否し、他のモジュールが要求を処理する必要が生じたことをApacheに指示します。この場合、スクリプトはHTMLドキュメントを戻しません。
次のREXXステートメントは、スクリプトに渡された主要な引数を取得し、引数をローカル変数に割り当てます。Mod_Rexxは、常に処理の対象となる各REXXスクリプトに1つの引数を渡します。その引数には、スクリプトが使用できる外部関数のほとんどに渡す必要のある数値 (要求レコード・ポインター) が含まれます。これは、以下のステートメントで確認できます。
call WWWSendHTTPHeader r, "text/html" |
このステートメントは、ブラウザーに返される要求ヘッダーにcontent-type (またはMIME-type) を割り当てます。応答ハンドラーとして使用されるすべてのスクリプトはこのREXX外部関数を呼び出して、戻されたドキュメントをブラウザーが処理できるようにしなければなりません。
次のステートメントは、Apacheからの照会ストリング引数を取り出します。これは必要なステートメントですが、これについての説明はこの記事では取り上げません。
次のステートメントのセットでは、実際のドキュメント・テキストをブラウザーに戻し始めます。ご覧のとおり、REXXのsay ステートメントにより、実際のHTMLテキストがブラウザーに戻されます。
次のステートメントでは、Mod_Rexx実行環境で提供された事前定義変数のいずれかをREXXスクリプトに対して使用し、Mod_Rexx版のストリングをブラウザーに戻します。この後、ブラウザーに戻される事前定義変数の値も2つのセクションに分けられます。一方のセクションは、標準的なCGIプログラムが通常使用できる変数を戻します。これらの変数の値は、仮にREXXスクリプトが実際のCGIプログラムであり、Apacheの応答ハンドラーでない場合の値とまさに同じようなものです。もう一方の変数のセットも、Mod_Rexxによって定義された別の実用的な変数です。
最後のREXXステートメントは、標準のHTMLの終了タグと、REXX変数がゼロ長であるかどうかをテストする標準的REXX内部関数/サブルーチンを提供します。この関数により、戻されるHTMLページ内のテーブルが見やすくなります。
ご覧のとおり、REXXの応答ハンドラー・スクリプトは、記述と保守が簡単です。このスクリプトにより、動的HTMLコンテンツを作成するための堅固な環境を構築できます。他にも、Mod_Rexx環境で用意された数多くの外部REXX関数や事前定義変数があり、これらを用いて、Apache環境やアプリケーション・プログラミング・インターフェース (API)に直接アクセスできます。さらに、IBMのObject REXXクラスのセット (参考文献を参照) があり、これによりApache APIへのアクセスがより容易になります。
UNIXなどの環境において、Mod_Rexxが実行するためにREXXプログラム・ファイルに実行可能の属性を与える必要はありません。実行可能属性としないことで、Mod_Rexx環境外で、偶然にせよ悪意からにせよ、標準的のApacheCGIインターフェースを介してそれらを実行することが出来なくなります。
Mod_Rexx応答ハンドラー・スクリプトを使用して、ドキュメント・サブディレクトリー内のHTMLページのセットに規定のフッターを追加することができます。ご使用のApache構成ファイル (httpd.conf) に以下を追加してください。
リスト2. Apacheの非応答構成ディレクティブ
<Location /mytest>
SetHandler rexx_handler
RexxHandler '/apache/rexx/footer.rex'
</Location>
|
RexxHandler ディレクティブは、指定のREXXスクリプトを呼び出して /mytestドキュメント・パス内に含まれる各HTMLファイルを処理するよう、Apacheに指示を出します。ドキュメントが指定のドキュメント・パスから検索されると、REXXスクリプトが呼び出されて、以下のHTMLドキュメントが実際に処理されます。
http://www.mydomain.com/mytest/testdoc.html |
以下はREXXスクリプト (footer.rex) の一例です。このスクリプトでは、testdoc.htmlを読み取り、フッターを追加します。
リスト3. 規定のフッターを追加するREXX応答ハンドラー・スクリプト
/* these are some typical Apache return codes */
OK = 0 /* Module has handled this stage. */
NOT_FOUND = 404 /* Main document not found. */
/* get the Apache request record ptr */
r = arg(1)
body = '</BODY>'
/* try to open the main document HTML file */
retc = stream(wwwfilename, 'c', 'open read')
if retc <> 'READY:' then do
return NOT_FOUND
end
/* set content-type and send the HTTP header */
call WWWSendHTTPHeader r, "text/html"
/* read in the document and look for the </BODY> tag */
call on notready name seteof
eof = 0
line = linein(wwwfilename)
x = pos(body, translate(line))
do while x = 0 & eof = 0
say line
line = linein(wwwfilename)
x = pos(body, translate(line))
end
if eof = 1 then return OK
/* we found a </BODY> tag so send out the footer */
say substr(line, 1, x - 1)
call send_footer
say substr(line, x)
/* read in the rest of the document */
line = linein(wwwfilename)
do while eof = 0
say line
line = linein(wwwfilename)
end
/* we are done */
return OK
/* function which indicates end-of-file */
seteof:
eof = 1
return
/* send the footer */
send_footer:
say '<br />'
say '<hr />'
say '<br />'
say '© 2001 <a href="http://www.ibm.com/">IBM Corporation</a>'
say '<br />'
say '<em>Last Modified:' date()'</em>'
say '<br />'
return
|
リスト3の例では、www.ibm.com Webサイトを参照する/mytest/testdoc.htmlドキュメントにフッターを追加します。このスクリプトは、/mytestサブディレクトリー・ツリー内のすべてのドキュメントに対して実行されます。これにより、ツリー内の全ドキュメントに標準のフッターが追加されます。
Mod_RexxにおけるREXXサーバー・ページのサポートの使用
REXXサーバー・ページ (RSP) は、JavaServer Pages (JSP) およびPHPページに類似したものです。RSPにより、HTMLページにREXXコードを埋め込むことができ、HTMLページを実行時に動的に作成することができます。以下がRSPの簡単な例です。
リスト4. サンプルRSPページ
<html>
<body>
<center><h1>RSP Test Page</h1></center>
<p>This is some straight HTML text in the RSP file.
<p>The current date and time is
<?rexx
/* the following is a REXX statement */
say date() time()
?>
</body>
</html>
|
一般的なHTMLを作成する場合と同様、任意のエディターを使用して、RSPを使用できるWebページを作成できます。REXXステートメントは、特別なタグを使用して、RSP内のHTML行から区切られています。タグ区切り文字には、短縮区切り文字、長区切り文字、使用すべきでない長区切り文字の3つのタイプがあります。
簡単かつ最短フォームのREXXステートメント区切り文字は<?rexx および?> というフォームです。以下に例を示します。
<p>The current date and time is
<?rexx
/* the following is a REXX statement */
say date() time()
?> |
タグの<?rexx および?> 部分は、RSPファイル内の独立した行として記述する点に注意してください。
長区切り文字のフォームは、標準のHTML<script> タグを使用してREXXステートメントを区切ります。以下に例を示します。
リスト6. 長区切り文字を使用したRSPページの例
<p>The current date and time is
<script type="rexx">
/* the following is a REXX statement */
say date() time()
</script>
|
<script> および</script> タグは、RSPファイル内の独立した行として記述する点に注意してください。
長区切り文字のフォームとして、使用すべきではありませんが、HTMLの<script> タグのフォームを使用して、REXXステートメントを区切ることもできます。このフォームは、HTML 4.0仕様では使用が推奨されていない点に注意してください。以下に例を示します。
リスト7. 使用すべきでない長区切り文字を使用したRSPページの例
<p>The current date and time is
<script language="rexx">
/* the following is a REXX statement */
say date() time()
</script>
|
Mod_RexxのRSP処理は、Apacheに対してRSPが使用できるファイルが要求された時点で実行されます。要求は、Mod_RexxおよびREXXプログラム/スクリプト (RSPコンパイラー) によって4つの段階で処理されます。
- Mod_Rexxによって、RSPファイルのコンパイル済みバージョンを含める一時ファイルが作成されます。
- RSPCOMP.REX (RSPコンパイラー) が呼び出され、RSPファイルが実際のREXXプログラムにコンパイルされ、このファイルが一時ファイルに含められます。
- Mod_Rexxが新たに作成されたREXXプログラムを呼び出します。
- Mod_Rexxが一時ファイルを削除します。
このコンパイル処理は非常に高速で、この処理で作成されたREXXプログラムの実行は、プログラムが呼び出すアクションに限定されます。一般的に、作成したプログラムがデータベースや他の外部環境にアクセスしない限り、作成したプログラムの実行も高速です。
RSPコンパイラー自身はREXXスクリプトであるため、Apacheの管理者はこれを変更してWeb開発者のニーズに応えることができます。RSPコンパイラーは他の関数も実行できます。例えば、RSPドキュメントを標準REXXプログラムにプリコンパイルして、そのREXXプログラムをApacheの応答ハンドラーとして実行することができます。
Apacheの構成ファイル (http.conf) を以下のディレクティブに置いて、Apacheのドキュメント・ツリー内のRSPドキュメントを使用することができます。
リスト8. ApacheのRSP構成ディレクティブ
AddType application/x-httpd-rexx-rsp .rsp
RexxTempFileNameTemplate "c:/temp/execrsp????.rex"
RexxRspCompiler "c:/Program Files/IBM HTTP Server/rspcomp.rex" |
AddType ディレクティブにより、Apacheのドキュメント・ツリー内のRSPファイルの拡張子が指定されます。RexxTempFileNameTemplate ディレクティブにより、Mod_Rexxがコンパイル済みバージョンのRSPファイルを含む一時ファイルを作成する際に使用するパス名およびファイル名のテンプレートが指定されます。また、RexxRspCompiler によって、REXX RSPコンパイラー・スクリプト (Mod_Rexxを備えている) へのパスが指定されます。
この記事では、Mod_Rexxで使用できる関数のごく一部のみを説明しました。しかしながら、Mod_Rexxの持つ、動的Webコンテンツの作成方法を改善する潜在機能を十分にご理解していただいたことを期待しております。
- 最新のMod_Rexxパッケージは、developerWorks のMod_Rexxプロジェクト・サイト からダウンロードできます。
-
REXX Language AssociationのWebサイト には、数多くの有益なサイトへのリンクがあります。
- オブジェクト指向プログラミング言語であり、オブジェクト指向プログラミングの初心者にも熟練者にも有益であるIBM Object REXX の学習をお勧めします。これは、標準的なREXXの前バージョンとの上位互換性があり、既存のアプリケーション (DB2、C、およびC++ アプリケーションなど) 向けの数多くのプログラミング・インターフェースが用意されています。
-
IBM REXX製品ファミリーは、VM/ESA、VSE/ESA、MVS/ESA、およびAIX、OS/2、Linux、およびWindowsのようなワークステーション環境などのホスト・システムで実行されます。
-
Regina REXXのWebサイトでは、SourceForge で、このオープン・ソース・プロジェクトについての詳細が説明されています。
- developerWorks のその他のオープン・ソース・リソースを参照してください。
W. David AshleyはIBM Global ServicesのITアーキテクトであり、カスタムWebソリューションを専門としています。彼の連絡先はdashley@us.ibm.com です。