开发apache module日志

1.一个apache module在httpd.conf文件中加载,如
LoadModule example_module modules/mod_example.dll
要点:example_module这个名字是唯一能和你写的模块的dll联系起来的方法,具体如下:
module AP_MODULE_DECLARE_DATA example_module =
{
    STANDARD20_MODULE_STUFF,
    x_create_dir_config,    /*per-directory config creator */
    x_merge_dir_config,     /* dir config merger */
    x_create_server_config, /* server config creator */
    x_merge_server_config,  /* server config merger */
    x_cmds,                 /* command table */
    x_register_hooks,       /* set up other request processing hooks */
};
这个定义把example_module作为符号导出(具体看AP_MODULE_DECLARE_DATA宏)使apche可以找到你的模块定义:
具体结构成员含义如下:
(1)STANDARD20_MODULE_STUFF是个宏,填充了模块的几个常用字段.
(2)x_create_dir_config, 函数指针:它是一个回调函数,在apache创建pre-directory时被调用,pre-directory是指apache在碰到<Directory><Location>, or .htaccess 文件在你的module处理范围内的时候.返回值是你模块内的控制的数据结构.
(3)x_merge_dir_config, 本函数是在合并两个pre-directory时被调用,有可能你创建了两个指向同一目录的<direcotry>或.<location>apache会尝试合并它们. 注意:你不要改变这个函数传进来的任何部分.返回值是你模块内的控制的数据结构.
(4)x_create_server_config,, 函数指针:它是一个回调函数,在apache创建pre-server时被调用,你可以在这个里面初始化你的一些参数.
(5)x_merge_server_config, 基本上同x_merge_dir_config只不过它是pre-server的.
(6)x_cmds, 这个是用于定义命令,命令的名称很重要不可以和其它模块的名称重复,一个命令可以对应apache配置文件中的一个directive终于理解为什么叫directive了,一个directive的名字,对应模块里命令的名字,直接调模块的函数.如:Listen 80, Listen就是一个命令,它会调apache模块中的listen命令.
(7)x_register_hooks, 定义一个注册钩子函数.在此函数中你可以注册好多钩子函数,apache会调用.这里比较重要的是你可以在这里定义handle, 一个handle就是处理浏览器请求的函数,你可以在一个handle中定义要给浏览器返回些什么东东,html或rar或几个字符.或都读一段服务器脚本,解释一下返回给客户端等等…….
三,一些结构
当apache的内容handle调用时会传给咱一个request_rec结构,这个结构包含可许多我们要的东东.
(1)如何取得客户端是以哪种方法请求服务器如,GET, POST
在request_rec结构的method_number字段里,如if (r->method_number == M_GET) /M_POST
(2)如何取得GET方式的参数信息呢?
在args字段里:以下代码向客户端返取get串
    if (r->method_number == M_GET && r->args)
    {
        ap_rputs(r->args, r);
    }
(3)如何取得post方式的提交的数据呢?
static int process_se_request(request_rec * r)
{
    apr_bucket_brigade *bb;
    apr_status_t rv;
    int seen_eos, child_stopped_reading;
    char* pRealContent;
    unsigned int nContentLength;
    unsigned int nCurPostion;
    apr_pool_t *p;
   
    if (strcmp(r->handler, ”se-handle”))
        return DECLINED;
    
//    ap_log_rerror
//    if (r->method_number == M_GET && r->args)
//    {
//        ap_rputs(r->args, r);
//    }
    nCurPostion = 0;
    nContentLength = (unsigned int)apr_atoi64(apr_table_get(r->headers_in, ”Content-Length”));
    if (0 == nContentLength)
    {
        return HTTP_BAD_REQUEST;
    }
    apr_pool_create(&p, NULL);
    pRealContent = apr_palloc(p, nContentLength);
    bb = apr_brigade_create(r->pool, r->connection->bucket_alloc);
    seen_eos = 0;
    child_stopped_reading = 0;
    do
    {
        apr_bucket *bucket;

        rv = ap_get_brigade(r->input_filters, bb, AP_MODE_READBYTES,
            APR_BLOCK_READ, HUGE_STRING_LEN);
        if (rv != APR_SUCCESS)
        {
            apr_brigade_destroy(bb);
            apr_pool_destroy(p);
            return rv;
        }

        for (bucket = APR_BRIGADE_FIRST(bb);
             bucket != APR_BRIGADE_SENTINEL(bb);
             bucket = APR_BUCKET_NEXT(bucket))
        {
            const char *data;
            apr_size_t len;

            if (APR_BUCKET_IS_EOS(bucket)) {
                seen_eos = 1;
                break;
            }
            /* We can’t do much with this. */
            if (APR_BUCKET_IS_FLUSH(bucket)) {
                continue;
            }
          
            /* read */
            apr_bucket_read(bucket, &data, &len, APR_BLOCK_READ);
            if (len + nCurPostion > nContentLength)
            {
                ap_log_rerror(APLOG_MARK, APLOG_ERR, rv, r, ”mem allocterror, no morememory!!nContentLength=%d,len=%d,nCurPostion=%d.”,nContentLength,len,nCurPostion);
                apr_brigade_destroy(bb);
                apr_pool_destroy(p);
                return HTTP_INTERNAL_SERVER_ERROR;    
            }

            memcpy(pRealContent + nCurPostion, data, len);
            nCurPostion += len;
    //        ap_rputs(data, r);
        }
        apr_brigade_cleanup(bb);
    }
    while (!seen_eos);

    apr_brigade_destroy(bb);
    apr_pool_destroy(p);

    if (pRealContent[nCurPostion] != ”)
    {
        pRealContent[nCurPostion] = ”;
    }
    ap_rputs(pRealContent, r);
    return OK;
}

二,一些apache api
(1)内存池相关
/*
作用: 初始化内存池,本函数会在 apr_initialize中自动被调用
*/
APR_DECLARE(apr_status_t) apr_pool_initialize(void);
/*
作用: 结束内存池, 本函数会在 apr_terminate中自动被调用
*/
APR_DECLARE(void) apr_pool_terminate(void);
/*
作用:  从apache 内存池中分配一块内存出来,并初始化为0
参数: p, apache内存池
  size: 要分配的大小
返回: 内存指针
*/
void* apr_pcalloc (apr_pool_t *p, apr_size_t size);
/*
作用:创建一个新的内存池
参数: newpool 要创建的内存池是个二级指针
parent 父池,如果此值为空,那么创建出来的池是根池,否则新池将继承父池的所有属性而且这个池会成为子池
*/
apr_status_t apr_pool_create(apr_pool_t **newpool, apr_pool_t *parent)
/*
作用:清除内存池, 并且清除他所有的子池
参数: p 要清除的内存池
注意:本函数不真正的释放内存,它只是将它拥有的已分配出去的内存重新变成可用的.
*/
APR_DECLARE(void) apr_pool_clear(apr_pool_t *p);

/*
作用:销毁池和他所有的子池,并且释放内存
参数:p要清除的内存池
*/
APR_DECLARE(void) apr_pool_destroy(apr_pool_t *p);

(2)字符串相关:
/*
作用: 连接多个字符串,内存从指定的内存池中分配
参数: p, apache内存池
… : 多个字符串
返回: 新字符串指针
*/
char * apr_pstrcat(apr_pool_t *p, …);

/*
作用: 复制一个新字符串,内存到指定的内存池中分配 
参数: p, 指定的内存池
  s: 要复制的字符串
返回: 新的字符串
*/
APR_DECLARE(char *) apr_pstrdup(apr_pool_t *p, const char *s);

(3)table(talbe包括数组与hash表)相关
/*
作用:生成一个新的表
参数:p: 指定的内存池
nelts: 初始化时分配的元素个数
*/
APR_DECLARE(apr_table_t *) apr_table_make(apr_pool_t *p, int nelts);

/*
作用: 删除所有在表中的元素
参数:   t  要删除的表指针
*/
APR_DECLARE(void) apr_table_clear(apr_table_t *t);

/*
作用:取得一个关联在一个key上的值. 在本函数调用之后,数据仍然在表中
参数:  t 指定的表
      key 指定的key
返回:NULL表示没有值与这个key关联,其它表示这个值的指针
*/
APR_DECLARE(const char *) apr_table_get(const apr_table_t *t, const char *key);

/*
作用:在指定的表中设置一对key和值, 如果表中已经有相同的key存在,则覆盖
参数; t 指定的表
  key: key
  val : 值
注意:函数将拷贝新的内容到新的指针中去,而不仅仅是拷贝一下指针
*/
APR_DECLARE(void) apr_table_set(apr_table_t *t, const char *key, const char *val);

/*
作用:在指定的表中设置一对key和值, 如果表中已经有相同的key存在,则覆盖
参数; t 指定的表
  key: key
  val : 值
注意:函数仅仅是拷贝一下指针,而不拷贝新的内容到新的指针中去. 
*/
APR_DECLARE(void) apr_table_setn(apr_table_t *t, const char *key, const char *val);

/*
作用:从指定的表中,移除一个key
参数: t 指定的表
    key: key
*/
APR_DECLARE(void) apr_table_unset(apr_table_t *t, const char *key);(4)bucket,filter, brigade相关
简介:什么是bucket,fiter,brigade呢?我的理解:bucket是内存块,fiter是一种过滤数据的容器,要过滤的数据可能从socket或file上来,brigade是把他们两联系起来的桥,数据从filter到bucket的一座桥.
/*
作用: 建立一个新的bucket_brigade(桶桥).新的桶桥是空的.
参数:p: 桥关联的内存池
list: 桶列表
返回:新的桶桥
*/
APU_DECLARE(apr_bucket_brigade *) apr_brigade_create(apr_pool_t *p, apr_bucket_alloc_t *list);

/*
作用:销毁所有的关联在这个桥上的桶列表,并把桥从内存池中注销
参数:b 要销毁的桶桥
*/
APU_DECLARE(apr_status_t) apr_brigade_destroy(apr_bucket_brigade *b);

/*
作用:清除所有的关联在这个桥上的桶列表,不把桥从内存池中注销
参数:date要清除的桶列表数据
*/
APU_DECLARE(apr_status_t) apr_brigade_cleanup(void *data);

/*
作用: 在过滤器栈中从下一个过滤器中取出当前的桶桥
参数:filter 下一下过滤器
bucket 当前的桶桥,必须为空
mode 输入模式
readbytes 读取的字节数
*/
AP_DECLARE(apr_status_t)ap_get_brigade(ap_filter_t *filter,  apr_bucket_brigade *bucket, ap_input_mode_t mode,apr_read_type_e block,  apr_off_t readbytes);

发表评论

电子邮件地址不会被公开。 必填项已用 * 标注

您可以使用这些 HTML 标签和属性: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>