モジュールの宣言
1|module AP_MODULE_DECLARE_DATA foo_module = { 2| STANDARD20_MODULE_STUFF, 3| foo_dir_config_creater, /* dir config creater */ 4| NULL, /* dir merger --- default is to override */ 5| NULL, /* server config */ 6| NULL, /* merge server config */ 7| foo_command_table, /* command table */ 8| foo_register_hooks /* register hooks */ 9|};
いわゆる「おまじない」。
ソースコードの上の方で
module AP_MODULE_DECLARE_DATA foo_module;
と宣言しているものもあった。意味はまだわからない。
3行目。初期化を行う関数のポインタを渡すっぽい。
7行目。独自のディレクティブの設定を行う配列のポインタを渡すっぽい。
8行目。ハンドラやフィルタの登録を行う関数のポインタを渡す。
初期化関数
1|static void *foo_dir_config_creater(apr_pool_t *p, char *dir) { 2| struct Foo *f = (Foo *) apr_palloc(p, sizeof(struct Foo)); 3| 4| return (void *) f; 5|}
ここで確保したメモリ領域を返すと「ap_filter_t::ctx」に保持されるっぽい。解放はApacheがやってくれるのかな?
フィルタの主処理でメモリ領域を取得するには
static apr_status_t foo_filter(ap_filter_t *f, apr_bucket_brigade *bb) { struct Foo *soo = f->ctx;
とするらしい。
コマンドテーブル
1|static const command_rec foo_command_table[] = { 2| AP_INIT_FLAG("FooCommand", ...), 3| ..., 4| {NULL} 5|};
AP_INIT_FLAGとか、AP_INIT_TAKE1などのマクロを使って、独自のディレクティブを登録するみたい。詳細はこれから調査。マクロはこのへんに載ってる。
最後は「{NULL}」で終わり?
主処理
こちらからほぼ転載。
1|apr_status_t foo_filter(ap_filter_t *f, apr_bucket_brigade *in_bb) { 2| const request_rec* const r = f->r; 3| 4| if (APR_BRIGADE_EMPTY(in_bb)) { 5| return APR_SUCCESS; 6| } 7| 8| apr_bucket_brigade* const out_bb = apr_brigade_create(r->pool, f->c->bucket_alloc); 9| 10| while (!APR_BRIGADE_EMPTY(in_bb)) { 11| apr_bucket* const e = APR_BRIGADE_FIRST(in_bb); 12| 13| if (APR_BUCKET_IS_EOS(e)) { 14| APR_BUCKET_REMOVE(e); 15| APR_BRIGADE_INSERT_TAIL(out_bb, e); 16| break; 17| } 18| 19| if (APR_BUCKET_IS_FLUSH(e)) { 20| apr_bucket_delete(e); 21| 22| apr_bucket* const bkt = apr_bucket_flush_create(f->c->bucket_alloc); 23| APR_BRIGADE_INSERT_TAIL(out_bb, bkt); 24| 25| const apr_status_t rv = ap_pass_brigade(f->next, out_bb); 26| 27| if (rv != APR_SUCCESS) { 28| return rv; 29| } 30| 31| continue; 32| } 33| 34| apr_size_t len; 35| const char* data; 36| apr_bucket_read(e, &data, &len, APR_BLOCK_READ); 37| 38| char* const buf = (char*)apr_palloc(r->pool, len); 39| memcpy(buf, data, len); 40| 41| apr_bucket* const b = apr_bucket_pool_create(buf, len, r->pool, f->c->bucket_alloc); 42| APR_BRIGADE_INSERT_TAIL(out_bb, b); 43| apr_bucket_delete(e); 44| } 45| 46| ap_remove_output_filter(f); 47| apr_brigade_cleanup(in_bb); 48| return ap_pass_brigade(f->next, out_bb); 49|}
処理の流れ。
- 「while (!APR_BRIGADE_EMPTY(in_bb))」でバケットブリッジをぐるぐるまわす。
- 「APR_BRIGADE_FIRST(in_bb)」でバケットブリッジからバケットを取り出す。
- 「apr_bucket_read()」でデータを読み込んで、新しいバケットにコピー。
- 新しいバケットを新しいバケットブリッジに追加。
- 新しいバケットブリッジを次に渡す。
ブラウザにキャッシュがあるときは「APR_BUCKET_IS_EOS()」に引っかかって、その後の処理が実行されないみたい。
APR_BUCKET_IS_FLUSH()の詳細はこれから調査。
APR_BUCKET_REMOVE()とapr_bucket_delete()の違いも不明。
apr_brigade_cleanup()を呼んでないものもあったきがするなぁ。
メモリ領域の確保は基本的に「r->pool」を介して行うものらしい。