apache module 開発事始め
先日は,必要に迫られて Apache 1.3 の mod_access を改造したという話を書きました.その時は単にあるものを改造しただけでしたが,ふと思い立って,一から Apache 2.0 用のモジュールを書いてみました.書く上で色々 Web サイトを探してみたのですが,あまり日本語の入門向けの文章が見あたらなかったので,開発する上で分かったこと(と言うほど大したものじゃないですが)をまとめておこうと思います.
Apache は,リクエストを処理する上で細かくフェーズを設定して,その各フェーズで様々な処理を行います.Apache のモジュールの開発は,そのモジュールが目的の処理をする上で適切なフェーズに Apache の処理が至ったときに,Apache から呼び出してもらうための関数(hook 関数)を作ることと,そのモジュールが動作するための設定を行う関数を作ること,になります.
フェーズには,例えばそのリクエストを受け付けるか拒否するかを決めるフェーズや,リクエストされた URI と実際のディスク上のファイルとの間の対応付けを解決するフェーズ,そしてもちろん実際のレスポンスを生成するフェーズ等があります.hook 関数を挿入するポイントはこれらのフェーズになりますが,もちろんその全てのフェーズのための関数を用意する必要はありません.また個別の設定を施す必要がなければ,設定用の関数も定義する必要ありません.なので,もっとも小規模なモジュールでは,hook 関数を一つと,hook 関数を Apacheに登録するための関数が必要ですからもう一つ,都合二つの関数を定義すれば済みます.Apache の標準モジュールである mod_asis モジュールも,そのような関数が二つだけ定義されたモジュールです.
さて,モジュール開発の始め方ですが,Apache をインストールした時に一緒にインストールされている,apxs コマンドを使います.以下の話は全て Linux 上で実行した場合の話です.このコマンドは Apache のモジュール開発を取り仕切るコマンドで,新しいモジュールを作る時のソースファイルのテンプレートを出力してくれたり,モジュールをコンパイルしてくれたりする,とても便利なものです.
テンプレートを出力するには
apxs -g -n test
とします.-g がテンプレート出力コマンドで -n オプションでそのモジュールの名前を指定します.すると,カレントディレクトリに test という名前のディレクトリが作成されて,
Makefile mod_test.c modules.mk
の3つのファイルが作成されます.modules.mk は Makefile のサポート用のファイルです.mod_test.c がモジュールのソースファイルになります.基本的には,このファイルを編集して,必要な hook や設定用の関数を定義していくことになります.
mod_test.c の中身は,次のようになっています(頭のコメントは省いています).
1 #include "httpd.h"
2 #include "http_config.h"
3 #include "http_protocol.h"
4 #include "ap_config.h"
5
6 /* The sample content handler */
7 static int test_handler(request_rec *r)
8 {
9 if (strcmp(r->handler, "test")) {
10 return DECLINED;
11 }
12
13 r->content_type = "text/html";
14 if (!r->header_only)
15 ap_rputs("The sample page from mod_test.c\n", r);
16
17 return OK;
18 }
19
20 static void test_register_hooks(apr_pool_t *p)
21 {
22 ap_hook_handler(test_handler, NULL, NULL, APR_HOOK_MIDDLE);
23 }
24
25 /* Dispatch list for API hooks */
26 module AP_MODULE_DECLARE_DATA test_module = {
27 STANDARD20_MODULE_STUFF,
28 NULL, /* create per-dir config structures */
29 NULL, /* merge per-dir config structures */
30 NULL, /* create per-server config structures */
31 NULL, /* merge per-server config structures */
32 NULL, /* table of config file commands */
33 test_register_hooks /* register hooks */
34 };
このコードの要素を軽く解説すると,test_handler() 関数はリクエストに対するレスポンスデータを生成するハンドラー関数です.このハンドラーの呼び出しは後述します.test_register_hooks() はこのモジュールで定義した hookを Apache に登録するための関数です.Apache の初期化時に呼び出されます.この中で呼び出している ap_hook_handler() 関数は,名前の通り handler を登録するためのものです.登録する hook の種類毎にこのような関数が用意されています.test_module 配列は,前述の hook 登録関数や(ここでは定義されてませんが)ディレクティブを処理する関数群を Apache に渡すためのものです.詳しくは別の稿で書こうと思います.
これをコンパイルするには,mod_test.c と一緒に生成された Makefile を使って make するか,apxs コマンドを使います.
make する場合は,単に make すればコンパイルできます. install ターゲットを指定すれば,コンパイルが成功したら続けて,できあがった DSO ファイルを modules ディレクトリにコピーしてくれます.
apxs コマンドを使う場合は,
apxs -c mod_test.c
でコンパイルできます.コンパイルと同時に modules ディレクトリにコピーするには
apxs -c -i mod_test.c
とします.更に -a オプションを指定しておけば,httpd.conf ファイルにこのモジュールを読み込む設定(LoadModule ディレクティブ)を追加してくれます.
apxs -c -i -a mod_test.c
実際にこのモジュールを使うには,例えば次のような設定を httpd.conf の適当なところに追加します.
<Location "/hoge/">
SetHandler test
</Location>
設定を追加して Apache を(再)起動したら,http://localhost/hoge/ をリクエストしてみます(ホスト名やポート番号は,実際の設定に合わせてください).すると次のようなレスポンスが返ってきます.
The sample page from mod_test.c
これは,上記のコードの 15行目で書き出したものです.
さて,このリクエストに先程コンパイルしたモジュールを結びつけているのが,httpd.conf に追加した
<Location "/hoge/">
SetHandler test
</Location>
の設定です.つまり,/hoge/ で始まる URI がリクエストされれば,そのリクエストを処理するハンドラとして test を使うことを指定します.
クライアントからリクエストがあると test_handler() がリクエストの度に呼び出されます.test_handler() は呼び出されると自分がそのリクエストを処理するべきか調べます(コードの 9行目).自分が処理するべきならば,r->handler の値が test になっています(この値を設定するのが SetHandler ディレクティブの仕事です).自分が処理するべきリクエストなら,レスポンスデータを生成(15行目)します.
如何でしょうか.意外と簡単じゃないですか? 今回はさわりだけでしたが,稿を改めて他のフェーズでの処理の話や実際にモジュールを書く上で便利なライブラリの話などを書いてみたいと思います.
参考文献:
- Apache の処理の流れに関してはここのページに書いてあります.
- hook 登録関数の一覧はこちらのページの最後の方にあります.が,説明が一文づつしかないのでちょっと物足りないです.
トラックバックURL
この記事へのトラックバック
この記事へのコメント
apxsでモジュールのテンプレートを作れるなんて知りませんでした。
自分で書いてもさほど手間がかかるテンプレートではないですが、これがあるだけで敷居はぐっと低く感じられますね。
mod_test.cのコードで「>」が「>gt;」と表示されているようなので報告いたします。
本当に参考になります。
これからも記載宜しくお願いいたします。
勉強になりました。