2014年6月9日月曜日

フック関数の概要

フック関数について書く
フック関数の処理はマクロ化されているので、まず、そのあたりをまとめる。
概要は、2.4系も2.2系も異ならないのではないか。


http://httpd.apache.org/docs/2.4/en/developer/hooks.html

Apache httpdのライフサイクルには、起動時/再起動時の設定ファイルの読込みから、リクエスト処理のための子プロセス/スレッドの生成、接続の受付け、リクエストの受付け、内容を解析し、処理し、レスポンスを返すという、リクエスト処理のサイクルを通して、多数のフックポイントが用意されている。
例えば、hogehogeというフックポイントがあって、そこでフック関数を呼び出すために行われる処理は、 ap_run_hogehoge() という名前の関数だ。
このap_run_hogehoge()関数は、hogehogeフック関数の登録リストに登録されたフック関数を順に実行する。
このフック関数実行関数ap_run_hogehoge()には、登録されたフック関数をすべて無条件に実行するものと、いずれかの関数が所定の戻り値を返すと処理を終了するものが存在する。
そして、ap_run_hogehoge() で実行されるフック関数を登録するのが、ap_hook_hogehoge()という名前の関数だ。

ソースコードをgrepなどで検索すると、ap_run_hogehogeやap_hook_hogehogeという関数が使われる個所は多数見つかるが、実際にその関数が定義されている個所はない。これは、ap_run_hogehogeとap_hook_hogehogeがマクロで定義されているためだ。

と書きながら、実際にgrepしてみたところ、 post_configフック関数が検索で見つかる(server/config.c)。
マクロを展開したコードがコメントとして残されているようだ。


定義の実例:post_read_request


hogehogeでは、実例は見つからないので、たとえば、リクエストヘッダを読み込んだ後のタイミングで実行されるpost_read_requestフック関数で調べてみる。

フック関数の実行は、以下のコードだ。

(httpd-2.4.9/server/protocol.c)

    895 request_rec *ap_read_request(conn_rec *conn)
    896 {
     :

   1108     if (access_status != HTTP_OK
   1109         || (access_status = ap_run_post_read_request(r))) {
ここで、実行される
1110 ap_die(access_status, r); 1111 ap_update_child_status(conn->sbh, SERVER_BUSY_LOG, r); 1112 ap_run_log_transaction(r); 1113 r = NULL; 1114 goto traceout; 1115 }

modules/http/http_request.c にも見つかるが、こちらは「内部リダイレクト」という機能で利用されているので、別の機会にする。

また、フック関数の登録例は、以下のコードだ。

(httpd-2.4.9/modules/metadata/mod_setenvif.c)

    630 static void register_hooks(apr_pool_t *p)
    631 {
     :
    633     ap_hook_post_read_request(match_headers, NULL, NULL, APR_HOOK_MIDDLE);
これがフック関数 match_headersの登録処理 最後の引数の APR_HOOK_MIDDLE が実行時の順番を制御する。
:

このsetenvifモジュールでは、post_read_requestのフック関数として match_headersを登録している。


ap_run_post_read_request()/ap_hook_post_read_request() で実行されるのは、以下のマクロを展開して得られるコードだ。

(httpd-2.4.9/server/protocol.c)
   1785 AP_IMPLEMENT_HOOK_RUN_ALL(int,post_read_request,
   1786                           (request_rec *r), (r), OK, DECLINED)


上記のマクロを展開して改行とインデントを追加すると、次のようになる。

AP_DECLARE(void) ap_hook_post_read_request(ap_HOOK_post_read_request_t *pf,
                                           const char * const *aszPre, 
                                           const char * const *aszSucc,int nOrder) 
{ 
 ap_LINK_post_read_request_t *pHook; 

 if(!_hooks.link_post_read_request) { 
  _hooks.link_post_read_request=apr_array_make(apr_hook_global_pool,1,
                                          sizeof(ap_LINK_post_read_request_t));

_hooks.link_post_read_requestの領域を準備する。
apr_hook_sort_register("post_read_request",&_hooks.link_post_read_request);
これも sort_register というフックポイントでのフック関数登録 処理風だが、実装は異なっている。 ここで登録された配列が、後で apr_hook_sort_all()という処理の対象になる。
}
以下では、_hooks.link_post_read_requestの要素を取得して、 各値を設定している。
pHook=apr_array_push(_hooks.link_post_read_request); pHook->pFunc=pf; pHook->aszPredecessors=aszPre; pHook->aszSuccessors=aszSucc; pHook->nOrder=nOrder; pHook->szName=apr_hook_debug_current; if(apr_hook_debug_enabled) apr_hook_debug_show("post_read_request",aszPre,aszSucc); } AP_DECLARE(apr_array_header_t *) ap_hook_get_post_read_request(void) { return _hooks.link_post_read_request; } AP_DECLARE(int) ap_run_post_read_request (request_rec *r) { ap_LINK_post_read_request_t *pHook; int n; int rv = OK; ; ;
_hooks.link_post_read_requestに登録されているフック関数 (pHook[n].pFunc)順に実行している
if(_hooks.link_post_read_request) { pHook=(ap_LINK_post_read_request_t *)_hooks.link_post_read_request->elts; for(n=0 ; n < _hooks.link_post_read_request->nelts ; ++n) { ; rv=pHook[n].pFunc (r); ; if(rv != OK && rv != DECLINED) break;
このフック関数処理では、フック関数の戻り値がOKでもDECLINEでもない 場合にフック関数の処理を中止している。 従って、フック関数の実行順は、重要となる場合がある。
rv = OK; } } ; return rv; }

この _hooks.link_post_read_request が、登録されたフック関数情報の格納先になる。
ap_LINK_post_read_request_tが登録する情報を定義する構造体だ。
ap_HOOK_post_read_request_tはフック関数の型である。

これらの定義はここにはない。
次のマクロで行われている。

(httpd-2.4.9/include/http_protocol.h)

    650 /*
    651  * post_read_request --- run right after read_request or internal_redirect,
    652  *                  and not run during any subrequests.
    653  */
    654 /**
    655  * This hook allows modules to affect the request immediately after the request
    656  * has been read, and before any other phases have been processes.  This allows
    657  * modules to make decisions based upon the input header fields
    658  * @param r The current request
    659  * @return OK or DECLINED
    660  */
    661 AP_DECLARE_HOOK(int,post_read_request,(request_rec *r))

(httpd-2.4.9/server/protocol.c)

     63 APR_HOOK_STRUCT(
      :
     65     APR_HOOK_LINK(post_read_request)
      :
     70 )

これは展開すると、次のようになる。

typedef int ap_HOOK_post_read_request_t (request_rec *r); 
post_read_requestフック関数の型
AP_DECLARE(void) ap_hook_post_read_request(ap_HOOK_post_read_request_t *pf, const char * const *aszPre, const char * const *aszSucc, int nOrder);
ap_hook_post_read_request()のプロトタイプ
AP_DECLARE(int) ap_run_post_read_request (request_rec *r);
ap_run_post_read_request()のプロトタイプ
AP_DECLARE(apr_array_header_t *) ap_hook_get_post_read_request(void); typedef struct ap_LINK_post_read_request_t { ap_HOOK_post_read_request_t *pFunc; const char *szName; const char * const *aszPredecessors; const char * const *aszSuccessors; int nOrder; } ap_LINK_post_read_request_t;

static struct { 
 apr_array_header_t *link_post_read_request; 
} _hooks;


フック関数の種別


post_read_requestのフック関数の定義で利用されたマクロは AP_IMPLEMENT_HOOK_RUN_ALL だ。
他に、AP_IMPLEMENT_HOOK_RUN_FIRSTマクロ、AP_IMPLEMENT_HOOK_VOIDマクロが利用されている。


マクロ名 説明
AP_IMPLEMENT_HOOK_RUN_ALL フック関数の戻り値がOKでもDECLINEでもない場合に処理を終了する
AP_IMPLEMENT_HOOK_RUN_FIRST フック関数の戻り値がDECLINE以外の場合に処理を終了する
AP_IMPLEMENT_HOOK_VOID フック関数に戻り値がなく、登録されたフック関数をすべて実行する

今日はここまで

0 件のコメント:

コメントを投稿