Apache2.4 模块开发初探

作者: print("") 分类: linux 发布时间: 2021-04-10 21:06

一、开发文档

Apache 的开发文档:http://httpd.apache.org/docs/2.2/zh-cn/developer/

二、、安装Apache 

系统 Ubuntu 20.04.2 LTS

我这里使用的宝塔一键安装的编译环境的Apache2.4 

三、开发案例

/www/server/apache/bin/apxs -g -n helloworld

这里会帮你生成三个文件

mod_helloworld.c  这个是主文件

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

先看看这个注释是什么意思吧

注释说明是怎么使用这个hello world 这个模块 通过apxs -c 的方式编译这个模块

 apxs -c -i mod_helloworld.c

然后通过在配置文件中添加配置

LoadModule helloworld_module modules/mod_helloworld.so
<Location /helloworld>
  SetHandler helloworld
 </Location>

之后重启apache 然后访问 http://localhost/helloworld 

就能看到当前模块的效果

尝试测试一下他的说明

然后在配置文件增加配置

测试访问一下

已经成功返回了演示中的字符串

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

访问一下

全部字符串变为大写了

以上代码的逻辑为:

加载 case_filter_module 模块,通过 CaseFilterRegisterHooks 注册过滤函数 CaseFilterOutFilter

相关链接:

apache filter 官方文档

http://httpd.apache.org/docs/2.0/filter.html 介绍了 filter 可接受的配置指令。

https://www.cnblogs.com/274914765qq/p/4453315.html

https://www.cnblogs.com/diylab/archive/2011/05/05/2037415.html

如果觉得我的文章对您有用,请随意打赏。您的支持将鼓励我继续创作!

发表评论

您的电子邮箱地址不会被公开。