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机制解析(上)——钩子机制的实现相关推荐

  1. [转] js中的钩子机制(hook)

    什么是钩子机制?使用钩子机制有什么好处?  钩子机制也叫hook机制,或者你可以把它理解成一种匹配机制,就是我们在代码中设置一些钩子,然后程序执行时自动去匹配这些钩子:这样做的好处就是提高了程序的执行 ...

  2. Apache Hook机制解析(下)——实战:在自己的代码中使用Apache的钩子

    在前文<Apache Hook机制解析(上)--钩子机制的实现>和<Apache Hook机制解析(中)--细节讨论>的基础上,我们对Apache的钩子机制已经有了较多的了解, ...

  3. Apache Hook机制解析(中)——细节讨论

    本文在上文<Apache Hook机制解析(上)--钩子机制的实现>的基础上,对钩子机制的细节了补充分析. 1.    静态变量_hooks 这个变量由宏APR_HOOK_STRUCT所定 ...

  4. Git之深入解析如何借助Git的配置方法和钩子机制来自定义Git需求

    一.前言 到目前为止,我们已经了解了 Git 基本的运作机制和使用方式,学习了许多 Git 提供的工具简单且有效地使用它,可以高效地帮助我们工作,提升我们的效率. 如果还不清楚 Git 的基础使用流程 ...

  5. php ci框架 hook,CodeIgniter框架钩子机制实现方法【hooks类】

    本文实例讲述了CodeIgniter框架钩子机制实现方法.分享给大家供大家参考,具体如下: 记得上一次去到喜啦面试,面试官问我一个问题:codeigniter是如何实现钩子机制的? 当时答不上来,后来 ...

  6. JavaScript中的钩子(钩子机制\钩子函数\hook)是什么?

    我的博客https://www.ideaopen.cn/ 首先,看到我们的标题: JavaScript中的钩子(钩子机制\钩子函数\hook) 是什么? 我们前端的JavaScript中,经常提到钩子 ...

  7. android permission权限与安全机制解析(上)

    目录(?)[-] uses-permission 自定义permission permission标签 permission-tree标签 permission-group标签 安全机制 组件权限 权 ...

  8. 利用钩子机制取得Windows的消息监控权

    利用钩子机制取得Windows的消息监控权 我们知道,Windows系统是建立在消息传递机制基础上的,几乎所有的程序活动都由消息来驱动.Windows的钩子机制可以看作是一个消息中转站,控制系统发出消 ...

  9. Javascript 钩子机制——开会得出的结论

    介绍 今天大家开会共同解决了一些javascript方面的问题,大家一起想办法,最终大家选择了钩子机制. 我把整个过程与大家分享一下,如果有误,请大家指正. 问题 是这样的:我们的代码已经历史很久了, ...

最新文章

  1. 火狐linux ubuntu16.04,Ubuntu 16.04 安装 Firefox 48.0 beta版
  2. 干货 | 五大实例详解,携程 Redis 跨机房双向同步实践
  3. 学习JS的正则表达式
  4. 十八种方法让你集中精力工作
  5. alertmanager 告警恢复_Prometheus配置企业微信告警
  6. AD 文档信息设置和制作模板
  7. 数据库应用程序为什么不能脱离数据库管理系统独立运行
  8. 转:oracle常见重要视图-v$sql,v$sql_plan,v$sqltext,v$sqlarea,v$sql_plan_statistcs
  9. Eclipse没有Web插件和JavaEE插件咋整
  10. web-jsp 购物车(2)
  11. 维纳滤波器matlab程序,维纳滤波原理及其matlab实现
  12. extremecomponents
  13. Flash遮罩之溜光字制作一
  14. 接口文档要写在概要设计里吗_概要设计报告怎么写
  15. 怎样把多个excel文件合并成一个
  16. 加强【圣域2】各个技能的打击感-华丽的击飞效果
  17. seafile-搭建自己的私有云盘
  18. python小学生编程小游戏打地鼠turtle
  19. VnlnHub Hacker_Kid-v1.0.1
  20. 深度学习——神经网络的种类(前馈神经网络,反馈神经网络,图网络)

热门文章

  1. python代码打好了怎么运行-python代码是怎样运行的
  2. 编程软件python中的if用法-适合Python初学者的一些编程技巧
  3. python四大软件-9个使用Python的世界级软件公司
  4. python就业前景分析-最新的Python就业前景分析一览表
  5. 自学python转行-转行学习python 需要多久?应该如何学习?
  6. python条件语句-Python中条件判断语句的简单使用方法
  7. python快速入门答案-Python 快速入门笔记(1):简介
  8. python 读下一行-Python-将前一行和下一行绑定到当前行。
  9. lua学习笔记之位及字节
  10. LeetCode Partition Equal Subset Sum(动态规划)