设为首页 收藏本站
查看: 990|回复: 0

[经验分享] Apache模块开发学习笔记(一)

[复制链接]

尚未签到

发表于 2017-1-5 10:20:17 | 显示全部楼层 |阅读模式
先祝大家2009年心想事成,万事如意,工作顺利,心情愉快啊!

最近开始研究Apache模块的开发,在博客里记录一下学习的过程吧,
本来没什么头绪,现在研究下来,
主要学习Apache的基础对象和 API头文件,例如http_头文件里的函数,
APR(Apache Portable Runtime)函数库,请求处理流程,过滤器架构,页面内容生成等等
我是在Fedora10上开发的,现介绍一下环境的搭建:

# yum install httpd-devel
# yum install automake autoconf
# yum install libtool
# yum install ImageMagick
# yum install ImageMagick-devel
# yum install pcre-devel


现在看一个apache2自带的一个非常简单的filter:
首先创建一个Module工程

cd /usr/local/src
mkdir modtest
cd modtest
apxs -g -n case_filter


自动声称如下文件:

ls -a ./test
.  ..  .deps  Makefile  case_filter.c  modules.mk


修改case_filter.c,代码如下:

#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"
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);
}
/* XXX: is there any advantage to passing a brigade for each bucket? */
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 -i mod_case_filter


确认模块安装完毕:

cd /etc/httpd/modules
ls | grep mod_case_filter


在httpd.conf中加入:

LoadModule case_filter_module modules/mod_case_filter.so
<Location /mod_case_filter>
SetHandler mod_case_filter   
</Location>
CaseFilter on


这个时候访问启动apache,

apachectl restart


访问一个页面看看,发现页面中的每个字符都变成了大写。
这就是filter改变了输出的内容的结果。
这个是一个很好的例子,在这个例子上做一些改变可以很方便的实现自己对所有经过apache出去的内容做更改。
效果图:
DSC0000.png
简单的介绍一下代码,首先实现几个Apache的钩子,比如:ap_hook_insert_filter和ap_register_output_filter
具体Apache钩子函数的介绍可以参考:
http://httpd.apache.org/docs/2.0/developer/modules.html
然后写filter模块的话 ,有一个非常重要的数据结构apr_bucket
简单的说bucket是流数据的抽象,数据源包括了文件,管道,网络,内存等,抽象化了之后,不管是什么数据源,都统一了操作,
主要可以进行read、split、copy三个操作,
apr_bucket* b ; //当前元素
apr_bucket_brigade* bbin ; //链表
遍历客户端输入的内容内容
  for ( b = APR_BRIGADE_FIRST(bbin) ;
    b != APR_BRIGADE_SENTINEL(bbin) ;
    b = APR_BUCKET_NEXT(b) ) {
{ }
//从当前apr_bucket_brigade中删除apr_bucket,但不释放资源
APR_BUCKET_REMOVE(b);
//从当前apr_bucket_brigade中删除apr_bucket,且释放资源
apr_bucket_delete(b);
输出结果的话有这几个函数apr_brigade_puts(),apr_brigade_printf(),apr_brigade_write(),apr_brigade_putc()
filter模块可以在请求数据可以在到达内容生成器之前被输入过滤器
进行处理,回复数据可以在发送到客户端之前被输出过滤器进行处理。过滤器使得数据处
理的实现比以往的版本更加简洁有效,同时将内容生成器从它的变换(transformation)和
集合(aggregation)中分离出来。

说了这么多,我想 每个真正的Web程序员,有机会都应该看看Apache的源代码,都会有可能要修改甚至新作一个Apache模块的,
不光是Apache,lighttpd和nginx等服务器也是一样的道理,祝大家新年快乐啊!

运维网声明 1、欢迎大家加入本站运维交流群:群②:261659950 群⑤:202807635 群⑦870801961 群⑧679858003
2、本站所有主题由该帖子作者发表,该帖子作者与运维网享有帖子相关版权
3、所有作品的著作权均归原作者享有,请您和我们一样尊重他人的著作权等合法权益。如果您对作品感到满意,请购买正版
4、禁止制作、复制、发布和传播具有反动、淫秽、色情、暴力、凶杀等内容的信息,一经发现立即删除。若您因此触犯法律,一切后果自负,我们对此不承担任何责任
5、所有资源均系网友上传或者通过网络收集,我们仅提供一个展示、介绍、观摩学习的平台,我们不对其内容的准确性、可靠性、正当性、安全性、合法性等负责,亦不承担任何法律责任
6、所有作品仅供您个人学习、研究或欣赏,不得用于商业或者其他用途,否则,一切后果均由您自己承担,我们对此不承担任何法律责任
7、如涉及侵犯版权等问题,请您及时通知我们,我们将立即采取措施予以解决
8、联系人Email:admin@iyunv.com 网址:www.yunweiku.com

所有资源均系网友上传或者通过网络收集,我们仅提供一个展示、介绍、观摩学习的平台,我们不对其承担任何法律责任,如涉及侵犯版权等问题,请您及时通知我们,我们将立即处理,联系人Email:kefu@iyunv.com,QQ:1061981298 本贴地址:https://www.yunweiku.com/thread-324146-1-1.html 上篇帖子: [转]了解Apache Felix OSGi容器 下篇帖子: Apache模块开发学习笔记(一)
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

扫码加入运维网微信交流群X

扫码加入运维网微信交流群

扫描二维码加入运维网微信交流群,最新一手资源尽在官方微信交流群!快快加入我们吧...

扫描微信二维码查看详情

客服E-mail:kefu@iyunv.com 客服QQ:1061981298


QQ群⑦:运维网交流群⑦ QQ群⑧:运维网交流群⑧ k8s群:运维网kubernetes交流群


提醒:禁止发布任何违反国家法律、法规的言论与图片等内容;本站内容均来自个人观点与网络等信息,非本站认同之观点.


本站大部分资源是网友从网上搜集分享而来,其版权均归原作者及其网站所有,我们尊重他人的合法权益,如有内容侵犯您的合法权益,请及时与我们联系进行核实删除!



合作伙伴: 青云cloud

快速回复 返回顶部 返回列表