Apache Hook机制解析(上)——钩子机制的实现
Apache中大量使用了Hook机制,使得第三方开发Module可以扩展Apache服务器的默认处理。
Apache Hook功能可以简述如下:
1. 程序主框架根据名称声明和定义Hook
2. 第三方Module通过实现和挂载Hook来扩展主框架的行为。
3. 程序主框架在某些操作发生时显示触发Hook
例如,Apache的事务日志(也即访问日志)就是用Hook机制实现的,对应上面的3个环节如下:
1. 在Apache核心代码protocol.c中定义了名为log_transaction的Hook:
APR_HOOK_STRUCT(
…
APR_HOOK_LINK(log_transaction)
…
)
…
AP_IMPLEMENT_HOOK_RUN_ALL(int,log_transaction,
(request_rec *r), (r), OK, DECLINED)
2. 可选模块mod_log_config通过挂载Hook来扩展主程序的行为:
static void register_hooks(apr_pool_t *p)
{
…
ap_hook_log_transaction(multi_log_transaction,NULL,
NULL,APR_HOOK_MIDDLE);
…
}
3. 在Apache的核心流程ap_process_request函数中显式触发了该Hook:
void ap_process_request(request_rec *r)
{
…
ap_run_log_transaction(r)
…
}
上述机制是如何实现的呢,在此先做一个简单的描述:
1. 首先,Hook的基础实现是在apr库中,由apr_hooks.h和apr_hooks.c两个源文件来实现,这两个文件定义了大量的宏,并实现了一系列查找,排序相关的函数。
2. 其次,Hook是根据名字定义出来的,本例可以看作一个名为log_transaction的Hook。
3. 再其次,Hook通过apr_hooks.h中提供的宏被定义,这些宏扩展开来以后,将产生多个函数和结构——本例中看到的ap_run_log_transaction函数和ap_hook_log_transaction函数就是这些宏定义出来的。
我们就以log_transaction为例,来看一下Apache对此Hook的实现。
(一)声明和定义
本小结暂时不对各个函数的流程进行解释,只是先说明Apache如何通过宏来产生Hook所需函数和结构的声明和定义。
声明位于http_protocol.h文件中:
AP_DECLARE_HOOK(int,log_transaction,(request_rec *r))
这个宏展开以后如下:
typedef int ap_HOOK_log_transaction_t (request_rec *r);
AP_DECLARE(void) ap_hook_log_transaction(ap_HOOK_log_transaction_t *pf,
const char *const *aszPre,
const char * const *aszSucc, int nOrder);
AP_DECLARE(int) ap_run_log_transaction (request_rec *r);
AP_DECLARE(apr_array_header_t *) ap_hook_get_log_transaction(void);
typedef struct ap_AP_log_transaction_t {
ap_HOOK_log_transaction_t *pFunc;
const char *szName;
const char * const *aszPredecessors;
const char * const *aszSuccessors;
int nOrder;
} ap_AP_log_transaction_t;
也即声明了三个函数,并定义了一个函数指针类型和一个结构。上述三个函数的定义位于protocol.c文件的代码中,也是由一个宏来定义:
AP_IMPLEMENT_HOOK_RUN_ALL(int,log_transaction,
(request_rec *r), (r), OK, DECLINED)
此宏展开以后如下:
AP_DECLARE(void) ap_hook_log_transaction(ap_HOOK_log_transaction_t *pf,
const char *const *aszPre,
const char * const *aszSucc, int nOrder)
{
ap_AP_log_transaction_t *pHook;
if(!_hooks.link_log_transaction)
{
_hooks.link_log_transaction=apr_array_make(apr_hook_global_pool,
1,
sizeof(ap_AP_log_transaction_t));
apr_hook_sort_register(log_transaction,&_hooks.link_log_transaction);
}
pHook=apr_array_push(_hooks.link_log_transaction);
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(log_transaction,aszPre,aszSucc);
}
AP_DECLARE(apr_array_header_t *) ap_hook_get_log_transaction(void);
{
return _hooks.link_log_transaction;
}
AP_DECALRE(int) ap_run_log_transaction (request_rec *r)
{
ap_AP_log_transaction_t *pHook;
int n;
ret rv;
if(!_hooks.link_log_transaction)
return ok;
pHook=(ap_AP_log_transaction_t *)_hooks.link_log_transaction->elts;
for(n=0 ; n < _hooks.link_log_transaction->nelts ; ++n)
{
rv=pHook[n].pFunc (r);
if(rv != ok && rv != decline)
return rv;
}
return ok;
}
这里用到了一个静态变量_hooks,这个变量也是由宏定义出来的,在protocol.c文件的最开始:
APR_HOOK_STRUCT(
APR_HOOK_LINK(post_read_request)
APR_HOOK_LINK(log_transaction)
APR_HOOK_LINK(http_scheme)
APR_HOOK_LINK(default_port)
)
此宏展开以后如下:
static struct {
apr_array_header_t* link_post_read_request;
apr_array_header_t* link_log_transaction;
apr_array_header_t* link_http_scheme;
apr_array_header_t* link_default_port;
} _hooks;
也即声明了一个拥有4个成员(每个成员都是一个数组)的匿名结构,并用此结构定义了一个名为_hooks的静态变量。
(二)触发
触发是由ap_run_log_transaction函数实现的:
AP_DECALRE(int) ap_run_log_transaction (request_rec *r)
{
ap_AP_log_transaction_t *pHook;
int n;
ret rv;
if(!_hooks.link_log_transaction)
return ok;
pHook=(ap_AP_log_transaction_t *)_hooks.link_log_transaction->elts;
for(n=0 ; n < _hooks.link_log_transaction->nelts ; ++n)
{
rv=pHook[n].pFunc (r);
if(rv != ok && rv != decline)
return rv;
}
return ok;
}
此函数遍历静态变量_hooks的成员link_log_transaction(类型为apr_array_header_t*,是Apache内部使用的数组),并根据数组每个元素中的函数指针进行函数调用——此函数指针指向各个模块挂载到此Hook上的函数。
值得注意的是for循环中的条件语句——如果钩子函数的返回值既不是ok也不是decline,则终止循环,直接退出。
(三)挂载
挂载由函数ap_hook_log_transaction函数实现:
AP_DECLARE(void) ap_hook_log_transaction(ap_HOOK_log_transaction_t *pf,
const char *const *aszPre,
const char * const *aszSucc, int nOrder)
{
ap_AP_log_transaction_t *pHook;
if(!_hooks.link_log_transaction)
{
_hooks.link_log_transaction=apr_array_make(apr_hook_global_pool,
1,
sizeof(ap_AP_log_transaction_t));
apr_hook_sort_register(“log_transaction”, &_hooks.link_log_transaction);
}
pHook=apr_array_push(_hooks.link_log_transaction);
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(log_transaction,aszPre,aszSucc);
}
此函数先检查静态变量_hooks中的成员link_log_transaction是否为空,如果为空则创建一个初始大小为1的数组。然后往此数组中添加一个元素。
(四)综述
综上所述,对log_transaction这个Hook的具体实现和使用如下:
1. 框架定义静态结构变量_hooks,其成员link_log_transaction用于存放log_transaction相关的Hook。
2. 框架声明和定义Hook所需的函数:
a) ap_hook_log_transaction,此函数的功能是将一个函数指针(注册)添加到对应的Hook数组中。
b) ap_run_log_transaction,此函数的功能是执行一个Hook数组中的所有已注册函数。
3. 模块mod_log_config通过ap_hook_log_transaction注册(添加)自己的日志扩展函数multi_log_transaction
4. 框架调用ap_run_log_transaction,此时multi_log_transaction将会被执行。
Apache Hook机制解析(上)——钩子机制的实现相关推荐
- [转] js中的钩子机制(hook)
什么是钩子机制?使用钩子机制有什么好处? 钩子机制也叫hook机制,或者你可以把它理解成一种匹配机制,就是我们在代码中设置一些钩子,然后程序执行时自动去匹配这些钩子:这样做的好处就是提高了程序的执行 ...
- Apache Hook机制解析(下)——实战:在自己的代码中使用Apache的钩子
在前文<Apache Hook机制解析(上)--钩子机制的实现>和<Apache Hook机制解析(中)--细节讨论>的基础上,我们对Apache的钩子机制已经有了较多的了解, ...
- Apache Hook机制解析(中)——细节讨论
本文在上文<Apache Hook机制解析(上)--钩子机制的实现>的基础上,对钩子机制的细节了补充分析. 1. 静态变量_hooks 这个变量由宏APR_HOOK_STRUCT所定 ...
- Git之深入解析如何借助Git的配置方法和钩子机制来自定义Git需求
一.前言 到目前为止,我们已经了解了 Git 基本的运作机制和使用方式,学习了许多 Git 提供的工具简单且有效地使用它,可以高效地帮助我们工作,提升我们的效率. 如果还不清楚 Git 的基础使用流程 ...
- php ci框架 hook,CodeIgniter框架钩子机制实现方法【hooks类】
本文实例讲述了CodeIgniter框架钩子机制实现方法.分享给大家供大家参考,具体如下: 记得上一次去到喜啦面试,面试官问我一个问题:codeigniter是如何实现钩子机制的? 当时答不上来,后来 ...
- JavaScript中的钩子(钩子机制\钩子函数\hook)是什么?
我的博客https://www.ideaopen.cn/ 首先,看到我们的标题: JavaScript中的钩子(钩子机制\钩子函数\hook) 是什么? 我们前端的JavaScript中,经常提到钩子 ...
- android permission权限与安全机制解析(上)
目录(?)[-] uses-permission 自定义permission permission标签 permission-tree标签 permission-group标签 安全机制 组件权限 权 ...
- 利用钩子机制取得Windows的消息监控权
利用钩子机制取得Windows的消息监控权 我们知道,Windows系统是建立在消息传递机制基础上的,几乎所有的程序活动都由消息来驱动.Windows的钩子机制可以看作是一个消息中转站,控制系统发出消 ...
- Javascript 钩子机制——开会得出的结论
介绍 今天大家开会共同解决了一些javascript方面的问题,大家一起想办法,最终大家选择了钩子机制. 我把整个过程与大家分享一下,如果有误,请大家指正. 问题 是这样的:我们的代码已经历史很久了, ...
最新文章
- 火狐linux ubuntu16.04,Ubuntu 16.04 安装 Firefox 48.0 beta版
- 干货 | 五大实例详解,携程 Redis 跨机房双向同步实践
- 学习JS的正则表达式
- 十八种方法让你集中精力工作
- alertmanager 告警恢复_Prometheus配置企业微信告警
- AD 文档信息设置和制作模板
- 数据库应用程序为什么不能脱离数据库管理系统独立运行
- 转:oracle常见重要视图-v$sql,v$sql_plan,v$sqltext,v$sqlarea,v$sql_plan_statistcs
- Eclipse没有Web插件和JavaEE插件咋整
- web-jsp 购物车(2)
- 维纳滤波器matlab程序,维纳滤波原理及其matlab实现
- extremecomponents
- Flash遮罩之溜光字制作一
- 接口文档要写在概要设计里吗_概要设计报告怎么写
- 怎样把多个excel文件合并成一个
- 加强【圣域2】各个技能的打击感-华丽的击飞效果
- seafile-搭建自己的私有云盘
- python小学生编程小游戏打地鼠turtle
- VnlnHub Hacker_Kid-v1.0.1
- 深度学习——神经网络的种类(前馈神经网络,反馈神经网络,图网络)
热门文章
- python代码打好了怎么运行-python代码是怎样运行的
- 编程软件python中的if用法-适合Python初学者的一些编程技巧
- python四大软件-9个使用Python的世界级软件公司
- python就业前景分析-最新的Python就业前景分析一览表
- 自学python转行-转行学习python 需要多久?应该如何学习?
- python条件语句-Python中条件判断语句的简单使用方法
- python快速入门答案-Python 快速入门笔记(1):简介
- python 读下一行-Python-将前一行和下一行绑定到当前行。
- lua学习笔记之位及字节
- LeetCode Partition Equal Subset Sum(动态规划)