任何一個模塊可以通過額外的或者可選的鉤子來擴展API,通過在這些鉤子處插入額外的邏輯,執行這些邏輯自定的功能,其他模塊也可以使用這些功能以便執行這些自定義的邏輯。
鉤子調用的代碼實現下列的邏輯:
- 在這個鉤子處按照順序運行所有的被注冊函數
- 在這個鉤子處運行所有的被注冊函數直到返回了一個不是DECLINED的值
- 運行所有的函數直到或者除非返回一個錯誤(非OK或DECLINED)
declare聲明
ap_hook_handler(helloworld_handler, NULL, NULL, APR_HOOK_MIDDLE);
ap_hook_type_checker(choices_select, NULL, NULL, APR_HOOK_FIRST);```
**the first argument**:the function we are looking in to Apache.
**the other three arguments**:are concerned with the order of execution when multiple modules have inserted functions on the same hook.
**the second and third argument**:***predecessors*** and ***successors***是對于兩個緊密相關的模塊需要特定的順序執行
**APR_HOOK_FIRST**:used for modules may need to run a function before"all other"functions on the same hook have run
**APR_HOOK_MIDDLE**:doesn't matter
**APR_HOOK_LAST**:after
###implement實行
通過在apr_hooks.h、apr_optional_hooks.h和ap_config.h這三個頭文件中定義宏的方式來實現鉤子。上面三個聲明分別和以下三個內容相對應:
- AP_IMPLEMENT_EXTERNAL_HOOK_VOID
- AP_IMPLEMENT_EXTERNAL_HOOK_RUN_FIRST
- AP_IMPLEMENT_EXERTNAL_HOOK_RUN_ALL
當一個模塊實現了一個鉤子是,它導出一個鉤子函數,它們在請求處理流程中按照順序出現。
###引入hook的原因
對HTTP的請求,我們可以進一步劃分為客戶身份驗證、客戶權限認證、請求校驗、URL重定向等階段,每一個階段調用相應的函數進行處理。
Apache中對請求的處理過程實質上就是依次調用一系列掛鉤的過程,不過由于HTTP請求類型的不同,它們所對應的掛鉤數目和類型也不盡相同。
掛鉤是用來表示在處理HTTP請求中一組類似的操作,與之對應,掛鉤函數就是操作函數。
一個掛鉤同時是和一組掛鉤函數聯系在一起的。因此請求處理過程中,調用掛鉤的時候實際上就是調用掛鉤函數組。調用過程可以用下圖示意。Apache對指定掛鉤的掛鉤函數調用有兩種,一種就是將掛鉤函數組中的每個函數都調用一次;另一種就是從前往后調用,一旦找到合適的就停止繼續調用
##編寫自己的掛鉤
假如定義一個能夠在Apache處理請求時調用的函數accelerator,該函數只允許特定IP連接,其函數原型為:
int accelerator(request_rec *r,int n);```
(1) 掛鉤聲明
使用AP_DECLEAR_HOOK宏聲明一個名為accelerator的掛鉤:
AP_DECLARE_HOOK(int,accelerator,(request_rec *r,int n))```
#####(2) 掛鉤數組聲明
由于accelerator是新聲明的掛鉤,必須同時聲明新的掛鉤數組來保存各個模塊對掛鉤的注冊使用:
APR_HOOK_STRUCT(
APR_HOOK_LINK(accelerator)
)```
(3)聲明函數調用類型
在真正被ap_run_name調用之前,聲明掛鉤的調用類型:VOID\FIRST\ALL:
AP_IMPLEMENT_HOOK_RUN_VOID(accelerator,(request_rec *r,int n),(r,n))```
#####(4)注冊掛鉤函數
至第三步為止,對掛鉤的聲明已經基本結束,也意味著下一步的工作實際上應該落實到掛鉤使用者身上了。比如如果模塊som_module中想使用掛鉤some_hook,則其必須在掛鉤注冊函數中注冊該掛鉤,掛鉤注冊函數為ap_hook_some_hook,代碼示例如下:
static void register_hooks()
{
……
ap_hook_some_hook(some_hook_function,NULL,NULL,HOOK_MIDDLE);
}
AP_DECLARE_DATA module core_module = {
……
register_hooks /* register hooks */
};```
(5) 編寫掛鉤函數
最后剩下的內容就是編寫具體的掛鉤調用函數。比如在some_module模塊中,我們希望掛鉤函數只是打印出“Hello World”語句,而且從(4)中看出掛鉤函數名稱為some_hook_function,因此掛鉤函數聲明為如下:
static void some_hook_function(request_rec* r,int n)
{
ap_rputs(“Hello World/n”);
return;
}```
需要注意的是,這邊的掛鉤函數必須符合AP_IMPLEMENT_HOOK_RUN_XXX中聲明的格式。