撰文一个httpd module
撰写一个httpd module
撰写一个httpd module
本文简单介绍如何给httpd 2.4写一个module。首先得保证httpd和httpd的开发库被正确安装:
安装httpd-devel的原因是因为我们给httpd 2.4写module时,需要调用httpd相关的header文件。接下来我们写一个简单的模块:
这个模块通过`AP_MODULE_DECLARE_DATA`来注册一个`foo_module`,并会在运行时通过`foo_hooks`中调用`ap_hook_handler`将我们的逻辑函数`foo_handler`注册进httpd。
我们的`foo_handler`功能非常简单,并不处理用户请求`request_rec`,只是先判断在httpd.conf中模块是否设置为`{foo_handler}`。判断完成后,这个模块会直接返回html数据:
理解了这个module的作用以后,接下来是编译这个module。
使用apxs来编译httpd modules
httpd自己提供了一个很方便的模块编译工具叫做apxs,我们可以用它来编译所写的`module_foo`:
以下是使用apxs编译`module_foo.c`的过程:
可以看到apxs帮我们生成了复杂的libtool编译命令,生成了`module_foo.so`:
此外还帮我们在httpd中加载好了这个module:
加载了这个模块后,我们来使用它。
使用`module_foo`
还记得我们在`module_foo.c`中写的:
因此,在httpd.conf的最后添加一行配置:
这样,当用户请求/foo这个位置时,由`foo_handler`负责处理请求并返回。可以重启一下httpd服务然后访问这个url来验证:
可以看到我们的module已经工作了。
小结
在本文中,简单介绍了httpd module的开发流程,以及module的加载及配置方式。进一步的学习可以参考httpd的这篇写得很棒的{官方文档}。
撰写一个httpd module
本文简单介绍如何给httpd 2.4写一个module。首先得保证httpd和httpd的开发库被正确安装:
[weli@localhost work]$ yum list -q httpd httpd-devel Available Packages httpd.x86_64 2.4.6-31.el7 rhel-7-server-htb-rpms httpd-devel.x86_64 2.4.6-31.el7 rhel-7-server-htb-rpms [weli@localhost work]$
安装httpd-devel的原因是因为我们给httpd 2.4写module时,需要调用httpd相关的header文件。接下来我们写一个简单的模块:
// module_foo.c #include <stdio.h> #include "apr_hash.h" #include "ap_config.h" #include "ap_provider.h" #include "httpd.h" #include "http_core.h" #include "http_config.h" #include "http_log.h" #include "http_protocol.h" #include "http_request.h" static int foo_handler(request_rec *r) { if (!r->handler || strcmp(r->handler, "foo_handler")) return (DECLINED); ap_set_content_type(r, "text/html"); ap_rprintf(r, "Hello, martian!"); return OK; } static void foo_hooks(apr_pool_t *pool) { ap_hook_handler(foo_handler, NULL, NULL, APR_HOOK_MIDDLE); } module AP_MODULE_DECLARE_DATA foo_module = { STANDARD20_MODULE_STUFF, NULL, NULL, NULL, NULL, NULL, foo_hooks };
这个模块通过`AP_MODULE_DECLARE_DATA`来注册一个`foo_module`,并会在运行时通过`foo_hooks`中调用`ap_hook_handler`将我们的逻辑函数`foo_handler`注册进httpd。
我们的`foo_handler`功能非常简单,并不处理用户请求`request_rec`,只是先判断在httpd.conf中模块是否设置为`{foo_handler}`。判断完成后,这个模块会直接返回html数据:
ap_set_content_type(r, "text/html"); ap_rprintf(r, "Hello, martian!");
理解了这个module的作用以后,接下来是编译这个module。
使用apxs来编译httpd modules
httpd自己提供了一个很方便的模块编译工具叫做apxs,我们可以用它来编译所写的`module_foo`:
httpd/sbin/apxs Usage: apxs -g [-S <var>=<val>] -n <modname> apxs -q [-v] [-S <var>=<val>] [<query> ...] apxs -c [-S <var>=<val>] [-o <dsofile>] [-D <name>[=<value>]] [-I <incdir>] [-L <libdir>] [-l <libname>] [-Wc,<flags>] [-Wl,<flags>] [-p] <files> ... apxs -i [-S <var>=<val>] [-a] [-A] [-n <modname>] <dsofile> ... apxs -e [-S <var>=<val>] [-a] [-A] [-n <modname>] <dsofile> ...
以下是使用apxs编译`module_foo.c`的过程:
[weli@localhost work]$ sudo ../sbin/apxs -i -a -c module_foo.c [sudo] password for weli: httpd/lib/build/libtool --silent --mode=compile gcc -std=gnu99 -prefer-pic -O2 -g -pipe -Wall -Wp,-D_FORTIFY_SOURCE=2 -fexceptions -fstack-protector-strong --param=ssp-buffer-size=4 -grecord-gcc-switches -m64 -mtune=generic -DLINUX -D_REENTRANT -D_GNU_SOURCE -pthread -Ihttpd/include -c -o module_foo.lo module_foo.c && touch module_foo.slo httpd/lib/build/libtool --silent --mode=link gcc -std=gnu99 -Wl,-z,relro,-z,now -o module_foo.la -rpath httpd/modules -module -avoid-version module_foo.lo httpd/lib/build/instdso.sh SH_LIBTOOL='httpd/lib/build/libtool' module_foo.la httpd/modules httpd/lib/build/libtool --mode=install install module_foo.la httpd/modules/ libtool: install: install .libs/module_foo.so httpd/modules/module_foo.so libtool: install: install .libs/module_foo.lai httpd/modules/module_foo.la libtool: install: install .libs/module_foo.a httpd/modules/module_foo.a libtool: install: chmod 644 httpd/modules/module_foo.a libtool: install: ranlib httpd/modules/module_foo.a libtool: finish: PATH="/sbin:/bin:/usr/sbin:/usr/bin:/sbin" ldconfig -n httpd/modules ---------------------------------------------------------------------- Libraries have been installed in: httpd/modules If you ever happen to want to link against installed libraries in a given directory, LIBDIR, you must either use libtool, and specify the full pathname of the library, or use the `-LLIBDIR' flag during linking and do at least one of the following: - add LIBDIR to the `LD_LIBRARY_PATH' environment variable during execution - add LIBDIR to the `LD_RUN_PATH' environment variable during linking - use the `-Wl,-rpath -Wl,LIBDIR' linker flag - have your system administrator add LIBDIR to `/etc/ld.so.conf' See any operating system documentation about shared libraries for more information, such as the ld(1) and ld.so(8) manual pages. ---------------------------------------------------------------------- chmod 755 httpd/modules/module_foo.so [activating module `foo' in httpd/conf/httpd.conf]
可以看到apxs帮我们生成了复杂的libtool编译命令,生成了`module_foo.so`:
[weli@localhost httpd]$ ls modules/*foo* modules/module_foo.so
此外还帮我们在httpd中加载好了这个module:
[weli@localhost httpd]$ grep 'foo' conf/httpd.conf LoadModule foo_module modules/module_foo.so
加载了这个模块后,我们来使用它。
使用`module_foo`
还记得我们在`module_foo.c`中写的:
static int foo_handler(request_rec *r) { if (!r->handler || strcmp(r->handler, "foo_handler")) return (DECLINED); ...
因此,在httpd.conf的最后添加一行配置:
<Location /foo> SetHandler foo_handler </Location>
这样,当用户请求/foo这个位置时,由`foo_handler`负责处理请求并返回。可以重启一下httpd服务然后访问这个url来验证:
$ curl http://localhost/foo Hello, martian!
可以看到我们的module已经工作了。
小结
在本文中,简单介绍了httpd module的开发流程,以及module的加载及配置方式。进一步的学习可以参考httpd的这篇写得很棒的{官方文档}。