`
andrew913
  • 浏览: 187388 次
  • 性别: Icon_minigender_1
  • 来自: 杭州
社区版块
存档分类
最新评论

apache 模块开发之输出过滤器

阅读更多
前面写了apache模块开发之hellloworld ,那个例子是一个简单的内容生成器。现在我们来讲一个过滤器的实现。过滤器是apache中一个非常精妙的设计,apache自带的很多模块都是通过过滤器来实现。

对于过滤器,有输入过滤器与输出过滤器两种。
对于输入过滤器,就是在内容生成器之前执行,而输出过滤器则在内容生成器之后。可以有下面的顺序:
http请求-》输入过滤器-》内容生成-》输出过滤器-》用户

所有的请求都会经过我们的过滤器,所以我们可以对这些进行操作,比如统计流量,压缩等等。

下面我们讲一个例子,这个例子是apache自带的一个demo,它的功能是把页面中所有的小写字母变成大写字母。
从上面的过滤器流程中我们可以找到,只要我们在输出过滤器中挂一个钩子,然后将所有的字符变成大写就OK了。
代码如下:
#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
};


首先所有程序的入口还是case_filter_module这个变量,它和之前的helloworld多了几个选项,其中CaseFilterCreateServerConfig这是一个服务器初始化函数,这个初始化会在apache启动的时候执行。
我们来看下具体的实现:

static void *CaseFilterCreateServerConfig(apr_pool_t *p,server_rec *s)
{
    CaseFilterConfig *pConfig=apr_pcalloc(p,sizeof *pConfig);
    pConfig->bEnabled=0;
    return pConfig;
}



这里我们需要讲一下在apache中申请内存空间和普通的c语言的malloc有所区别,apache的申请空间都是向池申请,然后在这个池消失的时候就自动的释放我们的空间。其效率也要高于我们普通c语言malloc的堆空间分配的。
具体语法:
CaseFilterConfig *pConfig=apr_pcalloc(p,sizeof *pConfig);


这里就是向p这个池申请了空间,这个变量初始化以后,它的生命周期是等同于整个httpd进程的。所以在我们后面的程序中都可以调用。

case_filter_module这个变量还有CaseFilterCmds这个变量,这是一个配置命令,也就是说当我们想把一些参数通过配置httpd.conf来传入apache的时候,我们就通过这个函数指针。
它的结构为:
static const command_rec CaseFilterCmds[] =
{
    AP_INIT_FLAG("CaseFilter", CaseFilterEnable, NULL, RSRC_CONF,
    "Run a case filter on this host"),
    { NULL }
};


变量第一个参数为我们配置的选项,也就是我们的key,第二个参数是这个配置命令将执行的函数,我们就是通过这个函数来传递我们的配置的。例如本例子我们需要在httpd.conf中加入CaseFilter on这个命令,我们也可以看到CaseFilterEnable的实现为:

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;
}


case_filter_module最后一个参数就是我们的注册函数,具体实现如下:
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);
}


ap_hook_insert_filter 就是通过CaseFilterInsertFilter来讲我们的过滤器加入到apache过滤链中,然后就是ap_register_output_filter这个函数将我们的过滤器模块注册起来。
当我们需要输出一个页面的时候,就会触发ap_register_output_filter中低二个参数,这个参数为我们的处理函数指针,也就是我们所有的操作都是可以在这里搞定。对于这里,我们把所有的小写字母转化为大写字母,当然我们可以做更多的事情。

最后我们在我们的httpd.conf中加入

Loadmodule******//加载我们的模块

再加上我们的配置命令
CaseFilter on  //开启我们的过滤模块,我们也可以加入很多类似的配置。

编译我们的模块,重新启动apache,在看看我们的apache中所有的页面中的小写变成了大写。

最后还需要讲一点的时候,上面用的很多函数和标准C是有区别的,都是调用的apr的库。所以我们还要去熟悉下这里的函数,总体来说和标准C是差不多的,只是做了一些优化。

4
0
分享到:
评论
2 楼 andrew913 2009-06-02  
apache的struts啊?
rrsy23 写道

总的觉得开发配置思想和今天java平台的 tomcat,servlet,spring,servicemix差不多;呵呵也许tomcat本copy apache 何况后者其他户;所以学习还是学其神其思;不过开发配置还是比高级语言平台麻烦啰嗦;呵呵LZ可以考虑自己加一层通过配置文件解决问题;我们开发servlet麻烦 有struts为什么不开发个apache的struts啊?lz可以考虑哦;就是自己定义规则[配置简化],然后apache加载你的体系,你去加载其他的 模块最早;我写过类似的一个小东西;

我对Java开发不是很熟,不是很明白你的意思,以是做底层开发的,只是最近要搞apache监控模块.比如限制某个虚拟主机的流量,监控它的cpu占用率等,相对来说不是很面向业务逻辑的。
1 楼 rrsy23 2009-06-02  
总的觉得开发配置思想和今天java平台的 tomcat,servlet,spring,servicemix差不多;

呵呵也许tomcat本copy apache 何况后者其他户;

所以学习还是学其神其思;

不过开发配置还是比高级语言平台麻烦啰嗦;


呵呵LZ可以考虑自己加一层通过配置文件解决问题;

我们开发servlet麻烦 有struts

为什么不开发个apache的struts啊?

lz可以考虑哦;

就是自己定义规则[配置简化],然后apache加载你的体系,你去加载其他的 模块

最早;我写过类似的一个小东西;

相关推荐

    PHP开发实战1200例(第1卷).(清华出版.潘凯华.刘中华).part1

    注:本系列图书的第I、II卷再版时均相应改名为《xxx开发实例大全》(基础卷)及(提高卷),但内容基本无变化,需要的童鞋可自由匹配查找。 内容简介  《PHP开发实战1200例》分为I、II两卷共计1200个例子,包括了开发...

    PHP开发实战1200例(第1卷).(清华出版.潘凯华.刘中华).part2

    注:本系列图书的第I、II卷再版时均相应改名为《xxx开发实例大全》(基础卷)及(提高卷),但内容基本无变化,需要的童鞋可自由匹配查找。 内容简介  《PHP开发实战1200例》分为I、II两卷共计1200个例子,包括了开发...

    php网络开发完全手册

    1.6 几种开发工具的介绍 20 1.6.1 Vi及Vim 20 1.6.2 Eclipse+PHPEclipse插件 21 1.6.3 UltraEdit 21 1.6.4 EditPlus 22 1.6.5 支持PHP的IDE环境 22 1.7 小结 23 第2章 PHP的基础语法 24 2.1 语言构成与工作原理 24 ...

    JAVA上百实例源码以及开源项目

     Java数据压缩与传输实例,可以学习一下实例化套按字、得到文件输入流、压缩输入流、文件输出流、实例化缓冲区、写入数据到文件、关闭输入流、关闭套接字关闭输出流、输出错误信息等Java编程小技巧。 Java数组倒置...

    JAVA上百实例源码以及开源项目源代码

     Java数据压缩与传输实例,可以学习一下实例化套按字、得到文件输入流、压缩输入流、文件输出流、实例化缓冲区、写入数据到文件、关闭输入流、关闭套接字关闭输出流、输出错误信息等Java编程小技巧。 Java数组倒置...

    PHP5 开发手册 简体中文手册

    可用过滤器列表 O. 所支持的套接字传输器(Socket Transports)列表 P. PHP 类型比较表 Q. 解析器代号列表 R. 关于本手册 S. 开放出版许可协议 T. 函数索引 X. CHM 版本 62. 关于此版本 63. Using ...

    Maven权威指南 很精典的学习教程,比ANT更好用

    平台分类器 11.8. 小结 12. Maven Assemblies 12.1. Introduction 12.2. Assembly Basics 12.2.1. Predefined Assembly Descriptors 12.2.2. Building an Assembly 12.2.3. Assemblies as Dependencies ...

    史上最全韩顺平传智播客PHP就业班视频,10月份全集

    10-25 4 内容过滤器 可见度过滤器及练习讲解 10-26 1 课程回顾 10-26 2 属性过滤选择器 10-26 3 子元素选择器 表单对象属性选择器 10-26 4 jquery对象集合遍历的四种形式及练习题讲解 jquery的dom操作 10-27 1课程...

    (全)传智播客PHP就业班视频完整课程

    10-25 4 内容过滤器 可见度过滤器及练习讲解 10-26 1 课程回顾 10-26 2 属性过滤选择器 10-26 3 子元素选择器 表单对象属性选择器 10-26 4 jquery对象集合遍历的四种形式及练习题讲解 jquery的dom操作 10-27 1课程...

    史上最全传智播客PHP就业班视频课,8月份视频

    10-25 4 内容过滤器 可见度过滤器及练习讲解 10-26 1 课程回顾 10-26 2 属性过滤选择器 10-26 3 子元素选择器 表单对象属性选择器 10-26 4 jquery对象集合遍历的四种形式及练习题讲解 jquery的dom操作 10-27 1课程...

    韩顺平PHP JS JQUERY 所有视频下载种子 货真价实

    10-25 4 内容过滤器 可见度过滤器及练习讲解 10-26 1 课程回顾 10-26 2 属性过滤选择器 10-26 3 子元素选择器 表单对象属性选择器 10-26 4 jquery对象集合遍历的四种形式及练习题讲解 jquery的dom操作 10-27 1课程...

    史上最全韩顺平传智播客PHP就业班视频,9月份全集

    10-25 4 内容过滤器 可见度过滤器及练习讲解 10-26 1 课程回顾 10-26 2 属性过滤选择器 10-26 3 子元素选择器 表单对象属性选择器 10-26 4 jquery对象集合遍历的四种形式及练习题讲解 jquery的dom操作 10-27 1课程...

    新版Android开发教程.rar

    � 源代码完全开放,便于开发人员更清楚的把握实现细节,便于提高开发人员的技术水平,有利于开发 出 更具差异性的应用。 � 采用了对有限内存、电池和 CPU 优化过的虚拟机 Dalvik , Android 的运行速度比想象的要...

    php帮助文档,php。chm,php必备的中文手册

    可用过滤器列表 O. 所支持的套接字传输器(Socket Transports)列表 P. PHP 类型比较表 Q. 解析器代号列表 R. 关于本手册 S. 开放出版许可协议 T. 函数索引 X. CHM 版本 62. 关于此版本 63. Using ...

    PHP手册2007整合中文版

    可用过滤器列表 Q. 所支持的套接字传输器(Socket Transports)列表 R. PHP 类型比较表 S. 解析器代号列表 T. Userland Naming Guide U. 关于本手册 V. 开放出版许可协议 W. 函数索引 X. 补充说明 X. CHM 版本 73. ...

    ssh(structs,spring,hibernate)框架中的上传下载

    对于那些仅封装了Connection而未包括Statement的简单数据连接池,SimpleNativeJdbcExtractor是效率最高的抽取器实现类,但具体到apache的BasicDataSource连接池,它封装了所有JDBC的对象,这时就需要使用...

    KODExplorer 芒果云-资源管理器

    - Kodexplorer为千帆网络工作室开发的一款服务器文件管理程序。 - 完美取代FTP管理:可用于服务器文件管理,zip解压缩 备份还原、支持图片、音乐、视频预览、office、pdf等格式在线预览。文件夹拖拽上传……。 - ...

Global site tag (gtag.js) - Google Analytics