手軽に出来るApacheモジュール開発②

こんにちは、井川です。

前回、Apacheモジュールの手軽な作り方をご紹介しました。Webページに先頭に"hello world"を追加するモジュール(mod_hello_world)は意外と簡単に作成できたことと思います。今回は、モジュール開発を一歩進め、モジュールのOn/Offをディレクトリ毎に設定する方法をご紹介します。

前回(手軽に出来るApacheモジュール開発)と比べていささか複雑にはなりますが、モジュール起動の切り替えを使えるようになると開発の幅が大きく広がります。ぜひ試してみて下さい。

今回の開発の流れは以下の通りです。

① テンプレートの作成
② コード(mod_hello_world.c)の修正・追記
③ コンパイルしてインストール
④ Apacheの設定と再起動

検証環境は次の通りです。

・ CentOS 5.5
・ Apache 2.2.3

① テンプレートの作成

まずは、apxsを使ってひな形を作りましょう。適当なディレクトリに移動して、次のコマンドを実行します。


> /usr/sbin/apxs -g -n hello_world
(-g:テンプレート生成、-n:モジュール名指定)

これでhello_worldディレクトリが作成されました。そのディレクトリへ移動します。

② コードの修正・追記

ソースコード(mod_hello_world.c)を次のように修正・追記します。

  1. /**
  2.  * mod_hello_world.c -- Apache sample hello_world module
  3.  */
  4.  
  5. #include "httpd.h"
  6. #include "http_config.h"
  7. #include "http_protocol.h"
  8. #include "ap_config.h"
  9.  
  10. #define DEFAULT_AVAILABLE 0
  11.  
  12. /**
  13.  * モジュールの設定に関する部分
  14.  */
  15. /* モジュールの設定を表す構造体を定義する */
  16. typedef struct {
  17. int is_available;
  18. } hello_world_cfg;
  19.  
  20. module AP_MODULE_DECLARE_DATA hello_world_module;
  21.  
  22. /* ディレクトリ設定データを初期化する */
  23. static void *create_dir_config(apr_pool_t *p, char *dir)
  24. {
  25. hello_world_cfg *conf =
  26. (hello_world_cfg *)apr_palloc(p, sizeof(hello_world_cfg));
  27.  
  28. conf->is_available = DEFAULT_AVAILABLE;
  29.  
  30. return conf;
  31. }
  32. /* ディレクティブに値を設定する */
  33. static const char *set_available(cmd_parms *cmd, void *cfg, int flag)
  34. {
  35. hello_world_cfg *conf = (hello_world_cfg *)cfg;
  36. conf->is_available = flag;
  37. return NULL;
  38. }
  39. /* ディレクティブを定義する */
  40. static const command_rec hello_world_cmds[] =
  41. {
  42. AP_INIT_FLAG("HelloWorld", set_available, NULL, OR_ALL, "Use or not"),
  43. {NULL}
  44. };
  45. /**
  46.  * モジュールの機能・登録に関する部分
  47.  */
  48. /* ハンドラを定義する */
  49. static int hello_world_handler(request_rec *r)
  50. {
  51. hello_world_cfg *conf =
  52. (hello_world_cfg *)
  53. ap_get_module_config(r->per_dir_config, &hello_world_module);
  54.  
  55. if (conf->is_available && !r->header_only) {
  56. ap_rputs("hello world<br />", r);
  57. }
  58.  
  59. return DECLINED;
  60. }
  61. /* ハンドラを登録する */
  62. static void hello_world_register_hooks(apr_pool_t *p)
  63. {
  64. ap_hook_handler(hello_world_handler, NULL, NULL, APR_HOOK_MIDDLE);
  65. }
  66. /* モジュールに登録する */
  67. module AP_MODULE_DECLARE_DATA hello_world_module = {
  68. STANDARD20_MODULE_STUFF,
  69. create_dir_config, /* create per-dir config structures */
  70. NULL, /* merge per-dir config structures */
  71. NULL, /* create per-server config structures */
  72. NULL, /* merge per-server config structures */
  73. hello_world_cmds, /* table of config file commands */
  74. hello_world_register_hooks /* register hooks */
  75. };

このコードでは、Apacheのディレクティブ(HelloWorld)を定義・設定し、その設定をモジュールに渡すことで、ディレクトリ毎にモジュールの挙動を切り替えます。そこで、このコードを次のように大きく2つに分けると理解しやすいと思います。

a)モジュールの設定に関する部分


・ モジュールの設定を表す構造体を定義する(16行目)
 &nbsp; &nbsp; &nbsp; &nbsp;→ この構造体にモジュールのOn/Offの設定を格納する
 &nbsp;
・ ディレクトリ毎に構造体を初期化する関数を定義する(23行目)
 &nbsp; &nbsp; &nbsp; &nbsp;→ DEFAULT_AVAILABEが初期値として使われる
 &nbsp;
・ ディレクティブを定義する(40行目)
 &nbsp; &nbsp; &nbsp; &nbsp;→ HelloWorldディレクティブを定義(httpd.confに記述)
 &nbsp; &nbsp; &nbsp; &nbsp;→ AP_INIT_FLAGはOn/Offのみの設定を行うマクロ
 &nbsp;
・ ディレクティブを受け取って構造体に設定する関数を定義する(33行目)
 &nbsp; &nbsp; &nbsp; &nbsp;→ ディレクトリ毎の設定を読み込む
 &nbsp; &nbsp; &nbsp; &nbsp;→ この関数はAP_INIT_FLAGにより登録される

b)モジュールの機能・登録に関する部分


・ モジュールの機能を実装したハンドラを修正する(49行目)
 &nbsp; &nbsp; &nbsp; &nbsp;→ 構造体からモジュールのOn/Offを受け取って挙動を決める
 &nbsp;
・ ハンドラを登録する(62行目)
 &nbsp;
・ 各設定・機能をモジュールに設定する(67行目)

ここでは"HelloWorld"というディレクティブを定義しています。そして、httpd.confで"HelloWorld"が"On"に設定されているディレクトリやLocationでのみ、mod_hello_worldが有効になります。

③コンパイルとインストール

前回と同様に、コンパイルしてインストールします(rootもしくはsudoで実行)。


[コンパイルとインストールを同時に実行]
> /usr/sbin/apxs -i -a -c mod_hello_world.c

④Apacheの設定と再起動

ドキュメントルート以下にtestディレクトリを作成し、httpd.conf(/etc/httpd/conf/httpd.conf)でディレクティブを次のように設定します。


<Location "/test">
  HelloWorld on
</Location>

VirtualHostを使っているなら、この設定をVirtualHost内に記述して下さい。最後に、Apacheを再起動します。


/sbin/service httpd restart

これで準備は終わりました。

/testディレクトリにアクセスしてみて下さい。ページの先頭に"hello world"が付いているでしょうか?一方で、testディレクトリ以外の部分にアクセスすると、通常のページがきちんと表示されていれば成功です(先頭に"hello world"がなければOK)。

ディレクトリ毎の設定を行えるようになると、特定のディレクトリへのアクセスに関しては特別な処理を行うことなどが出来るようになります。実用上も必要不可欠な技術ですので、ぜひ実際に試してみて下さい。