32
Apache モモモモモモモ ( モ ) モモモモモ モモモモ

Apache Module

Embed Size (px)

Citation preview

Page 1: Apache Module

Apache モジュール入門

( 株 ) ライブドア 池邉智洋

Page 2: Apache Module

Apache モジュールとは?

• Apache Web サーバの機能を追加、削除する仕組み

• 標準で使われている多くの機能もモジュールとして実装されている

• 最低限必要な機能は Apache Core, Apache API として実装

Page 3: Apache Module

Apache の構造

Apache CoreApache Core

Apache APIApache API

Apache モジュールApache モジュール

Page 4: Apache Module

Apache モジュールの利点、欠点

• 利点– C 言語で記述するため高速– Web サーバと一体化した処理のため一般の

Web アプリケーションでは難しい処理も可能

• 欠点–コンパイルが必要–デバッグが困難–フォームがあるような一般的な Web アプリ

ケーションにはあまり向かない

Page 5: Apache Module

使用箇所

• 大量のリクエストを高速に処理–カウンターモジュール–アクセス解析ログ取得

• 構築後の変更が少ない箇所–ポータルトップページ

• Apache モジュールならではの処理–カスタム URI => ストレージマッピング–特殊な認証

Page 6: Apache Module

Apache のライフサイクル

• Apache のリクエストサイクルの代表的なフェーズ

• 左図の任意のフェーズにフック関数を登録して実行

クライアントの接続クライアントの接続

リクエスト読み込みリクエスト読み込み

URI 変換URI 変換

アクセス制御アクセス制御

認証認証

微調整 (fixup)微調整 (fixup)

コンテンツ出力コンテンツ出力

ロギングロギング

インプットフィルタインプットフィルタ

アウトプットフィルタアウトプットフィルタ

Page 7: Apache Module

APR• Apache Portable Runtime - http://apr.apache.org• C 言語における移植性 (Portability) の確保を行

なってくれる抽象レイヤー• 関数名は apr_ から始まる • メモリプールの管理• 文字列操作• 複雑なデータ構造 ( 動的配列、コンテナ型 )• ファイル I/O• etc…

Page 8: Apache Module

メモリ管理

• 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));

領域の確保

Page 9: Apache Module

文字列操作• 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);

文字列フォーマット

Page 10: Apache Module

動的配列

• 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;

配列実体

Page 11: Apache Module

テーブル• 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);

値の削除

Page 12: Apache Module

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

コンパイルしてインストール

Page 13: Apache Module

雛形の作成% 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

Page 14: Apache Module

確認

Page 15: Apache Module

ソースコード 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;}

Page 16: Apache Module

request_rec 構造体

• HTTP リクエストを表現した構造体• include/httpd.h で定義• モジュールを書く上で最もよく使う構造

体– r->handler 処理するハンドラの名称– r->content_type Content-Type ヘッダ– r->header_only HEAD リクエストかどうか

Page 17: Apache Module

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 上のファイル名

Page 18: Apache Module

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, …);

Page 19: Apache Module

ハンドラの返り値

• OK - 処理成功• DECLINED – 次のモジュールに処理を任せ

る• HTTP_*– HTTP_NOT_FOUND– HTTP_FORBIDDEN– HTTP_INTERNAL_SERVER_ERROR– etc…

Page 20: Apache Module

モジュールの連鎖• Chain of Responsibility 的• DECLINED が返された場合、次のモジュールが処理を行なう

mod_foofoo_handler()

mod_foofoo_handler()

mod_barbar_handler()

mod_barbar_handler()

defaultdefault_handler()

defaultdefault_handler()

Page 21: Apache Module

ソースコード 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 */};

Page 22: Apache Module

ハンドラの登録

• ap_hook_handler コンテントハンドラを登録

• フェーズ毎に ap_hook_* 関数が存在– ap_hook_translate_name– ap_hook_access_checker– ap_hook_fixups– ap_hook_log_transaction– etc…

Page 23: Apache Module

モジュールの定義

• モジュールを定義する構造体–ディレクトリ毎の設定の初期化–ディレクトリ毎の設定のマージ–サーバ毎の設定の作成–サーバ毎の設定のマージ–設定値のリスト–フックの登録

Page 24: Apache Module

設定値の使用

• mod_hello を設定ファイルに指定された文字列を出力するように変更

<Location /hello> SetHandler hello HelloMessage “Hello livedoor!”</Location>

<Location /hello> SetHandler hello HelloMessage “Hello livedoor!”</Location>

httpd.conf

Page 25: Apache Module

設定値を格納する構造体

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;}

初期化

Page 26: Apache Module

ディレクティブの定義

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 ディレクティブを定義

Page 27: Apache Module

ディレクティブ名の登録

• AP_INIT_NO_ARGS• AP_INIT_TAKE1• AP_INIT_TAKE2• AP_INIT_TAKE12• AP_INIT_ITERATE• AP_INIT_FLAG• AP_INIT_RAW_ARGS• etc…

Page 28: Apache Module

ディレクティブの設定場所

• OR_LIMIT• OR_OPTIONS• OR_FILEINFO• OR_AUTHCFG• OR_INDEXES• OR_ALL• ACCESS_CONF• RSRC_CONF

Page 29: Apache Module

モジュールに登録

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 };

モジュール定義を変更

Page 30: Apache Module

設定値の利用

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 で設定値を参照

Page 31: Apache Module

さらに複雑なモジュールを書くために

• modules ディレクトリ以下はよいお手本• http://apr.apache.org/• http://httpd.apache.org/docs/2.2/developer/• http://modules.apache.org/

Page 32: Apache Module

おしまい