Upload
tomohiro-ikebe
View
12.457
Download
2
Embed Size (px)
Citation preview
Apache モジュール入門
( 株 ) ライブドア 池邉智洋
Apache モジュールとは?
• Apache Web サーバの機能を追加、削除する仕組み
• 標準で使われている多くの機能もモジュールとして実装されている
• 最低限必要な機能は Apache Core, Apache API として実装
Apache の構造
Apache CoreApache Core
Apache APIApache API
Apache モジュールApache モジュール
Apache モジュールの利点、欠点
• 利点– C 言語で記述するため高速– Web サーバと一体化した処理のため一般の
Web アプリケーションでは難しい処理も可能
• 欠点–コンパイルが必要–デバッグが困難–フォームがあるような一般的な Web アプリ
ケーションにはあまり向かない
使用箇所
• 大量のリクエストを高速に処理–カウンターモジュール–アクセス解析ログ取得
• 構築後の変更が少ない箇所–ポータルトップページ
• Apache モジュールならではの処理–カスタム URI => ストレージマッピング–特殊な認証
Apache のライフサイクル
• Apache のリクエストサイクルの代表的なフェーズ
• 左図の任意のフェーズにフック関数を登録して実行
クライアントの接続クライアントの接続
リクエスト読み込みリクエスト読み込み
URI 変換URI 変換
アクセス制御アクセス制御
認証認証
微調整 (fixup)微調整 (fixup)
コンテンツ出力コンテンツ出力
ロギングロギング
インプットフィルタインプットフィルタ
アウトプットフィルタアウトプットフィルタ
APR• Apache Portable Runtime - http://apr.apache.org• C 言語における移植性 (Portability) の確保を行
なってくれる抽象レイヤー• 関数名は apr_ から始まる • メモリプールの管理• 文字列操作• 複雑なデータ構造 ( 動的配列、コンテナ型 )• ファイル I/O• etc…
メモリ管理
• apr_pool_t *• 領域の確保を行なう (malloc 相当 )• 確保した領域について明示的な free は不
要
my_module_conf *conf = apr_palloc(p,sizeof(my_module_conf));my_module_conf *conf = apr_palloc(p,sizeof(my_module_conf));
領域の確保
文字列操作• C 言語では複雑になりがちな文字列操作を簡単に• 返り値の領域はメモリプールから確保される
char *str = apr_pstrdup(p, src);char *str = apr_pstrdup(p, src);
文字列のコピー
char *str = apr_pstrcat(p, str1, str2, NULL);char *str = apr_pstrcat(p, str1, str2, NULL);
文字列の連結
char *str = apr_psprintf(p, “%d\n”, n);char *str = apr_psprintf(p, “%d\n”, n);
文字列フォーマット
動的配列
• apr_array_header_t *• 動的に拡張される配列
apr_array_header_t *arr = apr_array_make(p, 10, sizeof(char *));apr_array_header_t *arr = apr_array_make(p, 10, sizeof(char *));
配列の生成
*(const char **)apr_array_push(arr) = val;*(const char **)apr_array_push(arr) = val;
値の追加
arr->nelts;arr->nelts;
要素数
char **elts = arr->elts;char **elts = arr->elts;
配列実体
テーブル• apr_table_t *• HTTP ヘッダの処理等に使用される key => value コンテナ• 動的に拡張される
apr_table_t *tbl= apr_table_make(p, 12);apr_table_t *tbl= apr_table_make(p, 12);
テーブルの作成
apr_table_set(tbl, key, val);apr_table_set(tbl, key, val);
値のセット
char *val = apr_table_get(tbl, key);char *val = apr_table_get(tbl, key);
値の取得
apr_table_unset(tbl, key);apr_table_unset(tbl, key);
値の削除
apxs
• apxs = APache eXtenSion tool• Apache のモジュール作成、コンパイル等
を支援するツール
% apxs –g –n <module_name>% apxs –g –n <module_name>
雛形の作成
# apxs –i –a -c mod_<module_name>.c# apxs –i –a -c mod_<module_name>.c
コンパイルしてインストール
雛形の作成% apxs -g -n helloCreating [DIR] helloCreating [FILE] hello/MakefileCreating [FILE] hello/modules.mkCreating [FILE] hello/mod_hello.cCreating [FILE] hello/.deps# cd hello/# apxs –i –a –c mod_hello.c
% apxs -g -n helloCreating [DIR] helloCreating [FILE] hello/MakefileCreating [FILE] hello/modules.mkCreating [FILE] hello/mod_hello.cCreating [FILE] hello/.deps# cd hello/# apxs –i –a –c mod_hello.c
<Location /hello> SetHandler hello</Location>
<Location /hello> SetHandler hello</Location>
httpd.conf
# /usr/local/apache2/bin/apachectl stop# /usr/local/apache2/bin/apachectl start# /usr/local/apache2/bin/apachectl stop# /usr/local/apache2/bin/apachectl start
確認
ソースコード 1
#include "httpd.h"#include "http_config.h"#include "http_protocol.h"#include "ap_config.h"
/* コンテントハンドラ */static int hello_handler(request_rec *r){ if (strcmp(r->handler, "hello")) { return DECLINED; } r->content_type = "text/html";
if (!r->header_only) ap_rputs("The sample page from mod_hello.c\n", r); return OK;}
#include "httpd.h"#include "http_config.h"#include "http_protocol.h"#include "ap_config.h"
/* コンテントハンドラ */static int hello_handler(request_rec *r){ if (strcmp(r->handler, "hello")) { return DECLINED; } r->content_type = "text/html";
if (!r->header_only) ap_rputs("The sample page from mod_hello.c\n", r); return OK;}
request_rec 構造体
• HTTP リクエストを表現した構造体• include/httpd.h で定義• モジュールを書く上で最もよく使う構造
体– r->handler 処理するハンドラの名称– r->content_type Content-Type ヘッダ– r->header_only HEAD リクエストかどうか
request_rec 構造体
• 代表的なメンバ– r->pool リクエスト毎のメモリプール– r->args QUERY_STRING 値– r->method_number リクエストメソッドの数値表現– r->headers_in リクエストヘッダ apr_table_t 型– r->headers_out レスポンスヘッダ apr_table_t 型– r->uri URI– r->filename DISK 上のファイル名
Apache API
• Apache から提供される API• ap_ から始まる関数群• コンテンツの出力– ap_rputs(const char *str, requst_rec *r)– ap_rwrite(const void *buf, int nbytes, requst_rec
*r)– ap_rprintf(request_rec *r, const char *fmt, …);
ハンドラの返り値
• OK - 処理成功• DECLINED – 次のモジュールに処理を任せ
る• HTTP_*– HTTP_NOT_FOUND– HTTP_FORBIDDEN– HTTP_INTERNAL_SERVER_ERROR– etc…
モジュールの連鎖• Chain of Responsibility 的• DECLINED が返された場合、次のモジュールが処理を行なう
mod_foofoo_handler()
mod_foofoo_handler()
mod_barbar_handler()
mod_barbar_handler()
defaultdefault_handler()
defaultdefault_handler()
ソースコード 2
static void hello_register_hooks(apr_pool_t *p){ ap_hook_handler(hello_handler, NULL, NULL, APR_HOOK_MIDDLE);}
module AP_MODULE_DECLARE_DATA hello_module = { STANDARD20_MODULE_STUFF, NULL, /* create per-dir config */ NULL, /* merge per-dir config */ NULL, /* create per-server config */ NULL, /* merge per-server config */ NULL, /* config file commands */ hello_register_hooks /* register hooks */};
static void hello_register_hooks(apr_pool_t *p){ ap_hook_handler(hello_handler, NULL, NULL, APR_HOOK_MIDDLE);}
module AP_MODULE_DECLARE_DATA hello_module = { STANDARD20_MODULE_STUFF, NULL, /* create per-dir config */ NULL, /* merge per-dir config */ NULL, /* create per-server config */ NULL, /* merge per-server config */ NULL, /* config file commands */ hello_register_hooks /* register hooks */};
ハンドラの登録
• ap_hook_handler コンテントハンドラを登録
• フェーズ毎に ap_hook_* 関数が存在– ap_hook_translate_name– ap_hook_access_checker– ap_hook_fixups– ap_hook_log_transaction– etc…
モジュールの定義
• モジュールを定義する構造体–ディレクトリ毎の設定の初期化–ディレクトリ毎の設定のマージ–サーバ毎の設定の作成–サーバ毎の設定のマージ–設定値のリスト–フックの登録
設定値の使用
• mod_hello を設定ファイルに指定された文字列を出力するように変更
<Location /hello> SetHandler hello HelloMessage “Hello livedoor!”</Location>
<Location /hello> SetHandler hello HelloMessage “Hello livedoor!”</Location>
httpd.conf
設定値を格納する構造体
typedef struct { char *msg;} hello_cfg;
typedef struct { char *msg;} hello_cfg;
構造体の宣言
static void *create_hello_cfg(apr_pool_t *p, char *dir){ hello_cfg *cfg = apr_palloc(p, sizeof(hello_cfg)); cfg->msg = "Hello World!"; return (void *)cfg;}
static void *create_hello_cfg(apr_pool_t *p, char *dir){ hello_cfg *cfg = apr_palloc(p, sizeof(hello_cfg)); cfg->msg = "Hello World!"; return (void *)cfg;}
初期化
ディレクティブの定義
static const char *cmd_set_message(cmd_parms *cmd, void *c, const char *v){ hello_cfg *cfg = (hello_cfg *)c; cfg->msg = apr_pstrdup(cmd->pool, v); return NULL;}
static const command_rec hello_cmds[] = { AP_INIT_TAKE1("HelloMessage",
cmd_set_message, NULL, ACCESS_CONF, "Set mod_hello message."),
{NULL}};
static const char *cmd_set_message(cmd_parms *cmd, void *c, const char *v){ hello_cfg *cfg = (hello_cfg *)c; cfg->msg = apr_pstrdup(cmd->pool, v); return NULL;}
static const command_rec hello_cmds[] = { AP_INIT_TAKE1("HelloMessage",
cmd_set_message, NULL, ACCESS_CONF, "Set mod_hello message."),
{NULL}};
HelloMessage ディレクティブを定義
ディレクティブ名の登録
• AP_INIT_NO_ARGS• AP_INIT_TAKE1• AP_INIT_TAKE2• AP_INIT_TAKE12• AP_INIT_ITERATE• AP_INIT_FLAG• AP_INIT_RAW_ARGS• etc…
ディレクティブの設定場所
• OR_LIMIT• OR_OPTIONS• OR_FILEINFO• OR_AUTHCFG• OR_INDEXES• OR_ALL• ACCESS_CONF• RSRC_CONF
モジュールに登録
module AP_MODULE_DECLARE_DATA hello_module = { STANDARD20_MODULE_STUFF, hello_create_cfg, NULL, NULL, NULL, hello_cmds, hello_register_hooks };
module AP_MODULE_DECLARE_DATA hello_module = { STANDARD20_MODULE_STUFF, hello_create_cfg, NULL, NULL, NULL, hello_cmds, hello_register_hooks };
モジュール定義を変更
設定値の利用
static int hello_handler(request_rec *r){ hello_cfg *cfg = ap_get_module_config(r->per_dir_config, &hello_module); if (strcmp(r->handler, "hello")) { return DECLINED; } r->content_type = "text/html";
if (!r->header_only) ap_rprintf(r, "%s\n", cfg->msg); return OK;}
static int hello_handler(request_rec *r){ hello_cfg *cfg = ap_get_module_config(r->per_dir_config, &hello_module); if (strcmp(r->handler, "hello")) { return DECLINED; } r->content_type = "text/html";
if (!r->header_only) ap_rprintf(r, "%s\n", cfg->msg); return OK;}
ap_get_module_config で設定値を参照
さらに複雑なモジュールを書くために
• modules ディレクトリ以下はよいお手本• http://apr.apache.org/• http://httpd.apache.org/docs/2.2/developer/• http://modules.apache.org/
おしまい