4.試験用Apache Module「mod_test」の作成
では早速Apache Moduleの作成に入ります。この章ではapxs
コマンドを利用した雛形作成を行います。手順は以下のとおりです。
- Apache Moduleの雛形作成
- Apache HTTP Serverの設定ファイル変更
- Apache Moduleの動作確認
Apache Moduleの雛形作成
apxs
は、Apache Moduleの雛形を作成してくれるコマンドです。Apache HTTP Serverのインストールディレクトリ以下の「bin」に格納されています。まずはこのコマンドを利用して、「/usr/local/src/modtest」にtest
モジュールを作成しましょう。
cd /usr/local/src mkdir modtest cd modtest apxs -g -n test
コマンドを実行すると、test
ディレクトリといくつかのファイルが生成されます。
ls -a ./test . .. .deps Makefile mod_ test.c modules.mk
続いて生成されたモジュールのコンパイルとインストールを行いましょう。
cd test make make all install
上記の手順が完了したら、下記のコマンドを実行し、インストールファイル「mod_test.so」が存在することを確認してください。
cd /usr/local/apache22/modules ls | grep test
Apache HTTP Serverの設定ファイル変更
Apache HTTP Serverの設定ファイルも変更する必要があります。「/usr/local/apache22/conf/httpd.conf」の末尾に以下の内容を追加してください。
LoadModule test_module modules/mod_test.so <Location /test> SetHandler test </Location>
設定ファイルの修正が終わったら、Apache HTTP Serverを再起動します。
apachectl restart
Apache Moduleの動作確認
ブラウザから追加したApache Moduleにアクセスして動作を確認してみましょう。「http://(ApahceHTTPサーバが動作しているホスト)/test/」にアクセスし、以下のように表示されればモジュールは正常に動作しています。
5.「mod_test.c」の内容確認
さて、前章で自動生成したApache Moduleの内部はどのようになっているのでしょうか。「mod_test.c」のコードを確認してみましょう。
- P2\test\mod_test.c (サンプルコードはこちら)
前半部分はコメントなので、実際のコードは30行ちょっとの小さなプログラムでしかないことが分かります。定義されている関数は2つです。
static int test_handler(request_rec *r) static void test_register_hooks(apr_pool_t *p)
またモジュールを定義する構造体は1つ存在します。
module AP_MODULE_DECLARE_DATA test_module
AP_MODULE_DECLARE_DATA
は「ap_config.h」に記載されている、Windowsのみに効力をもつマクロです。具体的にはDLLエクスポート時に必要となる__declspec(dllexport)
が指定されます。それ以外の環境では特に実行力を持たないことが「ap_config.h」の107行目から136行目で確認することができます。 まず、コメント部分を見ると、15~23行目に先程行った手順が記載されています。ここでは使用するモジュールのファイル「mod_test.so」の登録とアクセス場所の登録、およびハンドラ名test
の設定を行っています。
ハンドラ名はApahceモジュール内で処理を実行するかどうかを判断するために使用されます。この内容は次の「mod_test.c」で再度説明します。
015 ** # httpd.conf 016 ** LoadModule test_module modules/mod_test.so 017 ** <Location /test> 018 ** SetHandler test 019 ** </Location> 020 ** 021 ** Then after restarting Apache via 022 ** 023 ** $ apachectl restart
次にコードを見てみましょう。まず72行目を見てください。ApacheモジュールはApacheCoreからフックで呼ばれて実行されます。ここではフックの登録関連を行う関数として、test_register_hooks
を指定しています。
064 /* Dispatch list for API hooks */ 065 module AP_MODULE_DECLARE_DATA test_module = { 066 STANDARD20_MODULE_STUFF, 067 NULL, /* create per-dir config structures */ 068 NULL, /* merge per-dir config structures */ 069 NULL, /* create per-server config structures */ 070 NULL, /* merge per-server config structures */ 071 NULL, /* table of config file commands */ 072 test_register_hooks /* register hooks */ 073 };
関数の定義自体は59~62行目にあります。今回はフック登録用関数の中からap_hook_handler
を選択し、47~57行目で定義した関数test_handler
を登録しました。
ところでこのmodule構造体は「http_config.h」の321行目から記載があります。この内容を確認すると構成要素が14項目あることが分かります。これではこのソースコードで登録されている要素数の7項目とは数が合いません。
しかし、登録済みの要素STANDARD20_MODULE_STUFF
に注目して、再度「http_config.h」の内容を確認すると414行目付近にその記述が見つかります。この内容がマクロとして展開されると、8項目が追加され要素の数が合うことになります(7項目 - 1項目 + 8項目 = 14項目)。
なお、module構造体の要素に関する説明は「http_config.h」のコメントとして記載されていますので、関心のある方は是非確認してみてください。
059 static void test_register_hooks(apr_pool_t *p) 060 { 061 ap_hook_handler(test_handler, NULL, NULL, APR_HOOK_MIDDLE); 062 }
フック登録用関数の第4引数では優先順位を指定する必要があります。優先順位とはApacheHTTPサーバが各モジュールを実行する際の大まかな順序を示すものです。
ここではAPR_HOOK_MIDDLEを
指定していますが、定数の宣言自体は「srclib/apr-util/include/apr_hooks.h」で行われています。大抵の場合はAPR_HOOK_MIDDLE
としておけば問題ないでしょう。通常APR_HOOK_REALLY_FIRST
、APR_HOOK_REALLY_LAST
が使われることはありません。
/** run this hook first, before ANYTHING */ #define APR_HOOK_REALLY_FIRST (-10) /** run this hook first */ #define APR_HOOK_FIRST 0 /** run this hook somewhere */ #define APR_HOOK_MIDDLE 10 /** run this hook after every other hook which is defined*/ #define APR_HOOK_LAST 20 /** run this hook last, after EVERYTHING */ #define APR_HOOK_REALLY_LAST 30
クライアントへの出力を担当する関数static int test_handler(request_rec *r)
では、49行目から51行目の部分で設定ファイル内のSetHandler
の値を確認しています。設定された値がtest
の場合のみ、52行目から55行目の部分で出力内容の作成を行います。これは先程「httpd.conf」で設定したtest
に対応しています。コードの中に直接書いているのが気になりますが、他モジュールでも同様の記述をしていることから従っておきます。正常に処理が終了したら、戻り値として「OK」を返します。
045 046 /* The sample content handler */ 047 static int test_handler(request_rec *r) 048 { 049 if (strcmp(r->handler, "test")) { 050 return DECLINED; 051 } 052 r->content_type = "text/html"; 053 054 if (!r->header_only) 055 ap_rputs("The sample page from mod_test.c\n", r); 056 return OK; 057 } 058