apache module 基础开发

路径为:/home/xxx/

工具为:apxs

框架搭建:

 

1、准备工作:安装apache对应的httpd-devel,主要是为了安装apxs。

 

2、生成一个apache的模块框架:cd /home/xxx/; apache module:apxs -g -n mytest

这里的mytest就是apache模块的名字,但是实际生成的so名为:mod_mytest.so

/usr/local/apache2/bin/apxs -i -a -c mod_rewrite.c
自动编译
-a 在httpd.conf文件中添加 LoadModule rewrite_module modules/mod_rewrite.so
-i 此选项表示需要执行安装操作,以安装一个或多个动态共享对象到服务器的modules目录中

 

 

3、编译apache模块:使用c++语言编写apache模块,网上有说使用extern”C”的方法(见http://hi.baidu.com/zhangsilly/blog/item/a43fa11f869f4efae1fe0bf3.html),但是没有实验成功。extern”C”会有警告,而且编译不过~!

最后,将我的所有后台处理程序做成了一个liblogic.so,然后apache的模块mytest加载这个liblogic.so,而apache模块mytest中只是接收请求,传递参数给liblogic.so进行处理!而在mytest的模块编译时,使用apxs的参数-S进行CC重命名,如下:

apxs -c -a -S CC=g++  -I./src -I./src/common/ -llogic -L./src/  mod_mytest.c -Wl,-rpath=/home/xxx/mytest/src/

这里需要注意,即使你的mod_mytest.c中使用c++语言来编写,但是这个文件不能使用mod_mytest.cpp来进行命名,必须使用.c的后缀,否则不能编译!具体原因不明,待查!在使用-Wl,-rpath的时候,应用程序对实际的动态库路径寻找,需要注意!

可以通过/usr/lib64/apr-1/build/libtool –silent –mode=link g++ …… 这里的silent去掉,看到具体的编译命令,前面有-Wl,–rpath -Wl,…可以看看!~

编译链接成功以后,在.libs/下会生成我们所用的mod_mytest.so

 

 

 

4、修改httpd.conf,添加:

LoadModule mytest_module  /home/xxx/mytest/.libs/mod_mytest.so

<Location /index>

SetHandler mytest

</Location>

这里的index,表示index所对应的请求,比如:http://www.baidu.com/index?a=1&b=2 — 这里的index将会使用module mytest去处理@!

重启apache即可!
上面讲了整个apache模块的搭建工作,以及编译和链接的命令和步骤,下面讲讲关于apache模块的开发:

apache模块的开发

 

 

 

经常会看的一个头文件:/usr/include/httpd/httpd.h

我们需要从哪儿入手:

打开mod_mytest.c文件,找到:static int mytest_handler(request_rec *r)这行!

这个函数就是我们需要修改的函数!

 

这里需要指出,对于所有的请求信息,都在这个r参数里!

第一个问题:取得url中的参数

http://www.baidu.com/index?a=1&b=2
比如,要取得上面的a/b两个参数,如何搞?
答案在r->args里,如上的url,r->args=”a=1&b=2″,我们所要做的事情是从这个串里取得a=1/b=2
下面是我写的一个函数,用来得到参数的,仅供参考!

char* get_args_param(request_rec* r, const char* name)  

{/*{{{*/  

    const char* args = r->args;  

    const char* start_args;  

    if (NULL != args)  

    {  

        for (start_args = ap_strstr_c(args, name); start_args;  

                start_args = ap_strstr_c(start_args + 1, name))  

        {  

            if (start_args == args || start_args[-1] == ‘&’ || isspace(start_args[-1]))  

            {  

                start_args += strlen(name);  

                while (*start_args && isspace(*start_args))  

                    ++start_args;  

                if (*start_args == ‘=’ && start_args[1])  

                {  

                    char* end_args;  

                    char* arg;  

                    ++start_args;  

                    arg = apr_pstrdup(r->pool, start_args);  

                    if ((end_args = strchr(arg, ‘&’)) != NULL)  

                        *end_args = ‘/0′;  

                    return arg;  

                }  

            }  

        }  

    }  

    return NULL;  

}/*}}}*/  

 

这里借鉴了源码中的get_cookie_param的编写!下面会提到!
这里需要注意,对于apr_pstrdup函数的调用,需要包含头文件:#include ”apr_strings.h”,否则会有警告,并且在运行的时候会core掉!
这里的apr_pstrdup所分配的内存,不需要显式free,它是基于apr_pool_t,当request end后,一次性释放!
第二个问题:如何得到特定的cookie

这里需要用到r->headers_in,这是一个apr_table_t类型的hashmap!下面会详细说下。
因为cookie是类似于:abc=ui230jklsiu;def=uiore0832jhh1;这样的
这里就要使用到我上面所说的apache中proxy模块的源码:
apache-2.2.11-src/modules/proxy/mod_proxy_balancer.c中有get_cookie_param函数!
去看吧,google吧!

char *get_cookie_param(request_rec *r, const char *name)  

{/*{{{*/  

    const char *cookies;  

    const char *start_cookie;  

    if ((cookies = apr_table_get(r->headers_in, “Cookie”))) {  

        for (start_cookie = ap_strstr_c(cookies, name); start_cookie;  

                start_cookie = ap_strstr_c(start_cookie + 1, name)) {  

            if (start_cookie == cookies ||  

                    start_cookie[-1] == ‘;’ ||  

                    start_cookie[-1] == ‘,’ ||  

                    isspace(start_cookie[-1])) {  

                start_cookie += strlen(name);  

                while(*start_cookie && isspace(*start_cookie))  

                    ++start_cookie;  

                if (*start_cookie == ‘=’ && start_cookie[1]) {  

                    char *end_cookie, *cookie;  

                    ++start_cookie;  

                    cookie = apr_pstrdup(r->pool, start_cookie);  

                    if ((end_cookie = strchr(cookie, ‘;’)) != NULL)  

                        *end_cookie = ‘/0′;   

                    if((end_cookie = strchr(cookie, ‘,’)) != NULL)  

                        *end_cookie = ‘/0′;   

                    return cookie;   

                }  

            }  

        }  

    }  

    return NULL;  

}/*}}}*/  

 

还有很多其他参数,比如User-Agent,Referer,Accept-Charset,Keep-Alive等很多头信息都在这个headers_in里,下面的这个网址可以找到你想要的:
http://en.wikipedia.org/wiki/List_of_HTTP_header_fields
比如,取到User-Agent:apr_table_get(r->headers_in, ”User-Agent”);
第三个问题:如何取得ip

r->connection->remote_ip
不多说了!

第四个问题:如何输出:

apache 提供了很多的输出函数,都是使用ap_打头的,在/usr/include/httpd/http_protocol.h中可以看到。下面摘录几个:

AP_DECLARE(int) ap_rputc(int c, request_rec *r);

AP_DECLARE(int) ap_rputs(const char *str, request_rec *r);

AP_DECLARE(int) ap_rwrite(const void *buf, int nbyte, request_rec *r);

AP_DECLARE_NONSTD(int) ap_rvputs(request_rec *r,…);

AP_DECLARE(int) ap_vrprintf(request_rec *r, const char *fmt, va_list vlist);

……

 

需要注意,对于ap_rputs,str不可为NULL,否则会引起core!

 

参考:

 

还有更多的说明,可以参考头文件:/usr/include/httpd/httpd.h

或者下面的网址对你有帮助:

对apache的一些常见问题说明:http://blog.sina.com.cn/s/blog_5bf18faf0100aph8.html

一个helloworld的例子:http://andrew913.javaeye.com/blog/398648

reqeust_rec的结构说明:http://hi.baidu.com/start_and_end/blog/item/f344224ecadcc9c1d0c86a79.html

server_rec的结构说明:http://book.51cto.com/art/200805/72067.htm

apxs工具简介:http://lamp.linux.gov.cn/Apache/ApacheMenu/programs/apxs.html

关于filter模块的一个实例:http://www.cnblogs.com/ithurricane/archive/2009/01/01/1366312.html

 

后续补充:

1.对于apache的输出压缩需要考虑(使用mod_deflate.so),可以参考http://www.bestchao.net/archives/134

比较重要的一段:

<IfModule mod_deflate.c>
SetOutputFilter DEFLATE
</IfModule>

发表评论

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

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