一、簡介
Apache HTTP服務器是一個模塊化的軟件,使管理者可以選擇核心中包含的模塊以裁剪功能。可以在編譯時選擇被靜態包含進httpd二進制映象的模塊,也可以編譯成獨立於主httpd二進制映象的動態共享對象DSO,DSO模塊可以在編譯服務器之後編譯,也可以用Apache擴展工具(apxs)編譯並增加。
Apache模塊開發主要采用掛鉤子的方法來實現模塊開發的,這和linux內核模塊開發有點像,說白了就是加一個回調函數。
二、安裝Apache的apxs
apxs是一個為Apache HTTP服務器編譯和安裝擴展模塊的工具,用於編譯一個或多個源程序或目標代碼文件為動態共享對象,使之可以用由mod_so提供的LoadModule指令在運行時加載到Apache服務器中。
apxs參考文檔:http://lamp.linux.gov.cn/Apache/ApacheMenu/programs/apxs.html
查看是否有httpd-devel這個包,如果沒有需要安裝
#rpm -qa | grep httpd #查看 #yum -y install httpd-devel #安裝
三、開發實例
程序1:apache模塊開發之內容生成器
執行以下命令,將生成helloworld的模板
apxs -g -n helloworld
生成的代碼如下:
/*
** mod_helloworld.c -- Apache sample helloworld module
** [Autogenerated via ``apxs -n helloworld -g'']
**
** To play with this sample module first compile it into a
** DSO file and install it into Apache's modules directory
** by running:
**
** $ apxs -c -i mod_helloworld.c
**
** Then activate it in Apache's httpd.conf file for instance
** for the URL /helloworld in as follows:
**
** # httpd.conf
** LoadModule helloworld_module modules/mod_helloworld.so
** <Location /helloworld>
** SetHandler helloworld
** </Location>
**
** Then after restarting Apache via
**
** $ apachectl restart
**
** you immediately can request the URL /helloworld and watch for the
** output of this module. This can be achieved for instance via:
**
** $ lynx -mime_header http://localhost/helloworld
**
** The output should be similar to the following one:
**
** HTTP/1.1 200 OK
** Date: Tue, 31 Mar 1998 14:42:22 GMT
** Server: Apache/1.3.4 (Unix)
** Connection: close
** Content-Type: text/html
**
** The sample page from mod_helloworld.c
*/
#include "httpd.h"
#include "http_config.h"
#include "http_protocol.h"
#include "ap_config.h"
/* The sample content handler */
static int helloworld_handler(request_rec *r)
{
if (strcmp(r->handler, "helloworld")) {
return DECLINED;
}
r->content_type = "text/html";
if (!r->header_only)
ap_rputs("The sample page from mod_helloworld.c\n", r);
return OK;
}
static void helloworld_register_hooks(apr_pool_t *p)
{
ap_hook_handler(helloworld_handler, NULL, NULL, APR_HOOK_MIDDLE);
}
/* Dispatch list for API hooks */
module AP_MODULE_DECLARE_DATA helloworld_module = {
STANDARD20_MODULE_STUFF,
NULL, /* create per-dir config structures */
NULL, /* merge per-dir config structures */
NULL, /* create per-server config structures */
NULL, /* merge per-server config structures */
NULL, /* table of config file commands */
helloworld_register_hooks /* register hooks */
};
編譯
apxs -c mod_helloworld.c
安裝
apxs -i mod_helloworld.la
修改配置文件httpd.conf,以加載模塊,主要添加如下內容
LoadModule helloworld_module modules/mod_helloworld.so <Location /helloworld> SetHandler helloworld </Location>
重啟服務器,進行測試
apachectl -k stop #停止
apachectl -k start #啟動
在浏覽器中輸入url,即可看到效果
http://127.0.0.1/helloworld
程序2:apache模塊開發之輸出過濾器
對於過濾器,有輸入過濾器與輸出過濾器兩種,有下面的順序:
請求--輸入過濾器--內容生成器--輸出過濾器--響應
/**
* @file: mod_casefilter.c
* @brief: 把頁面中所有的小寫字母變成大寫字母
*/
#include "httpd.h"
#include "http_config.h"
#include "apr_buckets.h"
#include "apr_general.h"
#include "apr_lib.h"
#include "util_filter.h"
#include "http_request.h"
#include <ctype.h>
static const char s_szCaseFilterName[]="CaseFilter";
module AP_MODULE_DECLARE_DATA case_filter_module;
typedef struct
{
int bEnabled;
} CaseFilterConfig;
static void *CaseFilterCreateServerConfig(apr_pool_t *p,server_rec *s)
{
CaseFilterConfig *pConfig=apr_pcalloc(p,sizeof *pConfig);
pConfig->bEnabled=0;
return pConfig;
}
static void CaseFilterInsertFilter(request_rec *r)
{
CaseFilterConfig *pConfig=ap_get_module_config(r->server->module_config,
&case_filter_module);
if (!pConfig->bEnabled)
return;
ap_add_output_filter(s_szCaseFilterName,NULL,r,r->connection);
}
static apr_status_t CaseFilterOutFilter(ap_filter_t *f,
apr_bucket_brigade *pbbIn)
{
request_rec *r = f->r;
conn_rec *c = r->connection;
apr_bucket *pbktIn;
apr_bucket_brigade *pbbOut;
pbbOut=apr_brigade_create(r->pool, c->bucket_alloc);
for (pbktIn = APR_BRIGADE_FIRST(pbbIn);
pbktIn != APR_BRIGADE_SENTINEL(pbbIn);
pbktIn = APR_BUCKET_NEXT(pbktIn))
{
const char *data;
apr_size_t len;
char *buf;
apr_size_t n;
apr_bucket *pbktOut;
if (APR_BUCKET_IS_EOS(pbktIn))
{
apr_bucket *pbktEOS=apr_bucket_eos_create(c->bucket_alloc);
APR_BRIGADE_INSERT_TAIL(pbbOut,pbktEOS);
continue;
}
/* read */
apr_bucket_read(pbktIn,&data,&len,APR_BLOCK_READ);
/* write */
buf = apr_bucket_alloc(len, c->bucket_alloc);
for (n=0 ; n < len ; ++n)
buf[n] = apr_toupper(data[n]);
pbktOut = apr_bucket_heap_create(buf, len, apr_bucket_free,
c->bucket_alloc);
APR_BRIGADE_INSERT_TAIL(pbbOut,pbktOut);
}
apr_brigade_cleanup(pbbIn);
return ap_pass_brigade(f->next,pbbOut);
}
static const char *CaseFilterEnable(cmd_parms *cmd, void *dummy, int arg)
{
CaseFilterConfig *pConfig=ap_get_module_config(cmd->server->module_config,
&case_filter_module);
pConfig->bEnabled=arg;
return NULL;
}
static const command_rec CaseFilterCmds[] =
{
AP_INIT_FLAG("CaseFilter", CaseFilterEnable, NULL, RSRC_CONF,
"Run a case filter on this host"),
{ NULL }
};
static void CaseFilterRegisterHooks(apr_pool_t *p)
{
ap_hook_insert_filter(CaseFilterInsertFilter,NULL,NULL,APR_HOOK_MIDDLE);
ap_register_output_filter(s_szCaseFilterName,CaseFilterOutFilter,NULL,
AP_FTYPE_RESOURCE);
}
module AP_MODULE_DECLARE_DATA case_filter_module =
{
STANDARD20_MODULE_STUFF,
NULL,
NULL,
CaseFilterCreateServerConfig,
NULL,
CaseFilterCmds,
CaseFilterRegisterHooks
};
編譯
apxs -c mod_filter.c
安裝
apxs -i mod_filter.la
配置httpd.conf,添加如下內容:
LoadModule case_filter_module modules/mod_casefilter.so
CaseFilter on
測試