apache2 流程控制
_hook 数据结构
1
2 // 从 ap_hook 到 ap_run
3 // 宏 AP_IMPLEMENT_HOOK_RUN_ALL(int,pre_connection,(conn_rec *c, void *csd),(c, csd),OK,DECLINED ); 的具体实现
4 // connection.c
5 AP_DECLARE(void) ap_hook_pre_connection(ap_HOOK_pre_connection_t *pf, const char * const *aszPre, const char * const *aszSucc,int nOrder)
6 {
7 ap_LINK_pre_connection_t *pHook;
8 if(!_hooks.link_pre_connection)
9 {
10 _hooks.link_pre_connection=apr_array_make(apr_hook_global_pool,1,sizeof(ap_LINK_pre_connection_t));
11 apr_hook_sort_register("pre_connection",&_hooks.link_pre_connection);
12 }
13 pHook=apr_array_push(_hooks.link_pre_connection);
14 pHook->pFunc=pf;
15 pHook->aszPredecessors=aszPre;
16 pHook->aszSuccessors=aszSucc;
17 pHook->nOrder=nOrder;
18 pHook->szName=apr_hook_debug_current;
19 if(apr_hook_debug_enabled)
20 apr_hook_debug_show("pre_connection",aszPre,aszSucc);
21 }
22 AP_DECLARE(apr_array_header_t *) ap_hook_get_pre_connection(void)
23 {
24 return _hooks.link_pre_connection;
25 }
26 AP_DECLARE(int) ap_run_pre_connection (conn_rec *c, void *csd)
27 {
28 ap_LINK_pre_connection_t *pHook; int n; int rv;
29 if(!_hooks.link_pre_connection)
30 return OK;
31 pHook=(ap_LINK_pre_connection_t *)_hooks.link_pre_connection->elts;
32 for(n=0 ; n < _hooks.link_pre_connection->nelts ; ++n)
33 {
34 rv=pHook[n].pFunc (c, csd);
35 if(rv != OK && rv != DECLINED) return rv;
36 }
37 return OK;
38 };
2 // 从 ap_hook 到 ap_run
3 // 宏 AP_IMPLEMENT_HOOK_RUN_ALL(int,pre_connection,(conn_rec *c, void *csd),(c, csd),OK,DECLINED ); 的具体实现
4 // connection.c
5 AP_DECLARE(void) ap_hook_pre_connection(ap_HOOK_pre_connection_t *pf, const char * const *aszPre, const char * const *aszSucc,int nOrder)
6 {
7 ap_LINK_pre_connection_t *pHook;
8 if(!_hooks.link_pre_connection)
9 {
10 _hooks.link_pre_connection=apr_array_make(apr_hook_global_pool,1,sizeof(ap_LINK_pre_connection_t));
11 apr_hook_sort_register("pre_connection",&_hooks.link_pre_connection);
12 }
13 pHook=apr_array_push(_hooks.link_pre_connection);
14 pHook->pFunc=pf;
15 pHook->aszPredecessors=aszPre;
16 pHook->aszSuccessors=aszSucc;
17 pHook->nOrder=nOrder;
18 pHook->szName=apr_hook_debug_current;
19 if(apr_hook_debug_enabled)
20 apr_hook_debug_show("pre_connection",aszPre,aszSucc);
21 }
22 AP_DECLARE(apr_array_header_t *) ap_hook_get_pre_connection(void)
23 {
24 return _hooks.link_pre_connection;
25 }
26 AP_DECLARE(int) ap_run_pre_connection (conn_rec *c, void *csd)
27 {
28 ap_LINK_pre_connection_t *pHook; int n; int rv;
29 if(!_hooks.link_pre_connection)
30 return OK;
31 pHook=(ap_LINK_pre_connection_t *)_hooks.link_pre_connection->elts;
32 for(n=0 ; n < _hooks.link_pre_connection->nelts ; ++n)
33 {
34 rv=pHook[n].pFunc (c, csd);
35 if(rv != OK && rv != DECLINED) return rv;
36 }
37 return OK;
38 };
解码解释:
第5行 ap_hook_pre_connection 的第一个参数 pf 数据类型为 ap_HOOK_pre_connection_t ,实际是一个函数指针。也是用宏定义的:
// 宏 AP_DECLARE_HOOK(int,pre_connection,(conn_rec *c, void *csd))展开
// http_connection.h
typedef int ap_HOOK_pre_connection_t (conn_rec *c, void *csd);
AP_DECLARE(void) ap_hook_pre_connection(ap_HOOK_pre_connection_t *pf, const char * const *aszPre, const char * const *aszSucc, int nOrder);
AP_DECLARE(int) ap_run_pre_connection (conn_rec *c, void *csd);
AP_DECLARE(apr_array_header_t *) ap_hook_get_pre_connection(void);
typedef struct ap_LINK_pre_connection_t
{
ap_HOOK_pre_connection_t *pFunc;
const char *szName;
const char * const *aszPredecessors;
const char * const *aszSuccessors;
int nOrder;
} ap_LINK_pre_connection_t;
// http_connection.h
typedef int ap_HOOK_pre_connection_t (conn_rec *c, void *csd);
AP_DECLARE(void) ap_hook_pre_connection(ap_HOOK_pre_connection_t *pf, const char * const *aszPre, const char * const *aszSucc, int nOrder);
AP_DECLARE(int) ap_run_pre_connection (conn_rec *c, void *csd);
AP_DECLARE(apr_array_header_t *) ap_hook_get_pre_connection(void);
typedef struct ap_LINK_pre_connection_t
{
ap_HOOK_pre_connection_t *pFunc;
const char *szName;
const char * const *aszPredecessors;
const char * const *aszSuccessors;
int nOrder;
} ap_LINK_pre_connection_t;
第7 行的 _hook 定义于 connection.c ,它是一个由宏定义的文件级的变量。
从 hook 到 run--宏的展开
展开 ap_hook_宏和 ap_run宏
/**
* 展开 apache2 的 ap_hook_宏和 ap_run宏
* 使用 gcc -E -I/usr/local/apache2/include macos.h 可得到实际的c 代码
* by fancp 2011-1-10 p_168@163.com
*
***************************************************/
#include <ap_config.h>
APR_HOOK_STRUCT(
APR_HOOK_LINK(create_request_bin)
)
AP_DECLARE_HOOK(int,create_request_bin,(conn_rec *c, void *csd))
AP_IMPLEMENT_HOOK_RUN_ALL(int, create_request_bin,
(request_rec_bin *r), (r), OK, DECLINED)
/**
* 展开 apache2 的 ap_hook_宏和 ap_run宏
* 使用 gcc -E -I/usr/local/apache2/include macos.h 可得到实际的c 代码
* by fancp 2011-1-10 p_168@163.com
*
***************************************************/
#include <ap_config.h>
APR_HOOK_STRUCT(
APR_HOOK_LINK(create_request_bin)
)
AP_DECLARE_HOOK(int,create_request_bin,(conn_rec *c, void *csd))
AP_IMPLEMENT_HOOK_RUN_ALL(int, create_request_bin,
(request_rec_bin *r), (r), OK, DECLINED)
ap_filter_rec_t 数据结构
/***************************************
*
* util_filter.h
***************************************/
struct ap_filter_rec_t {
/** The registered name for this filter */
const char *name;
/** The function to call when this filter is invoked. */
ap_filter_func filter_func;
/** The function to call directly before the handlers are invoked
* for a request. The init function is called once directly
* before running the handlers for a request or subrequest. The
* init function is never called for a connection filter (with
* ftype >= AP_FTYPE_CONNECTION). Any use of this function for
* filters for protocols other than HTTP is specified by the
* module supported that protocol.
*/
ap_init_filter_func filter_init_func;
/** The type of filter, either AP_FTYPE_CONTENT or AP_FTYPE_CONNECTION.
* An AP_FTYPE_CONTENT filter modifies the data based on information
* found in the content. An AP_FTYPE_CONNECTION filter modifies the
* data based on the type of connection.
*/
ap_filter_type ftype;
/** The next filter_rec in the list */
struct ap_filter_rec_t *next;
/** Providers for this filter */
ap_filter_provider_t *providers;
/** Trace level for this filter */
int debug;
/** Protocol flags for this filter */
unsigned int proto_flags;
};
*
* util_filter.h
***************************************/
struct ap_filter_rec_t {
/** The registered name for this filter */
const char *name;
/** The function to call when this filter is invoked. */
ap_filter_func filter_func;
/** The function to call directly before the handlers are invoked
* for a request. The init function is called once directly
* before running the handlers for a request or subrequest. The
* init function is never called for a connection filter (with
* ftype >= AP_FTYPE_CONNECTION). Any use of this function for
* filters for protocols other than HTTP is specified by the
* module supported that protocol.
*/
ap_init_filter_func filter_init_func;
/** The type of filter, either AP_FTYPE_CONTENT or AP_FTYPE_CONNECTION.
* An AP_FTYPE_CONTENT filter modifies the data based on information
* found in the content. An AP_FTYPE_CONNECTION filter modifies the
* data based on the type of connection.
*/
ap_filter_type ftype;
/** The next filter_rec in the list */
struct ap_filter_rec_t *next;
/** Providers for this filter */
ap_filter_provider_t *providers;
/** Trace level for this filter */
int debug;
/** Protocol flags for this filter */
unsigned int proto_flags;
};
/*
* Read data from the next filter in the filter stack. Data should be
* modified in the bucket brigade that is passed in. The core allocates the
* bucket brigade, modules that wish to replace large chunks of data or to
* save data off to the side should probably create their own temporary
* brigade especially for that use.
*/
AP_DECLARE(apr_status_t) ap_get_brigade(ap_filter_t *next,
apr_bucket_brigade *bb,
ap_input_mode_t mode,
apr_read_type_e block,
apr_off_t readbytes)
{
if (next) {
return next->frec->filter_func.in_func(next, bb, mode, block,
readbytes);
}
return AP_NOBODY_READ;
}
* Read data from the next filter in the filter stack. Data should be
* modified in the bucket brigade that is passed in. The core allocates the
* bucket brigade, modules that wish to replace large chunks of data or to
* save data off to the side should probably create their own temporary
* brigade especially for that use.
*/
AP_DECLARE(apr_status_t) ap_get_brigade(ap_filter_t *next,
apr_bucket_brigade *bb,
ap_input_mode_t mode,
apr_read_type_e block,
apr_off_t readbytes)
{
if (next) {
return next->frec->filter_func.in_func(next, bb, mode, block,
readbytes);
}
return AP_NOBODY_READ;
}
范晨鹏
------------------
软件是一种态度
成功是一种习惯