1. 程式人生 > >apache 模組編寫(c++)

apache 模組編寫(c++)

注:

路徑為:/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

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 下面是我寫的一個函式,用來得到引數的,僅供參考!
  1. char* get_args_param(request_rec* r, constchar* name)  
  2. {/*{{{*/
  3.     constchar* args = r->args;  
  4.     constchar* start_args;  
  5.     if (NULL != args)  
  6.     {  
  7.         for (start_args = ap_strstr_c(args, name); start_args;  
  8.                 start_args = ap_strstr_c(start_args + 1, name))  
  9.         {  
  10.             if (start_args == args || start_args[-1] == '&' || isspace(start_args[-1]))  
  11.             {  
  12.                 start_args += strlen(name);  
  13.                 while (*start_args && isspace(*start_args))  
  14.                     ++start_args;  
  15.                 if (*start_args == '=' && start_args[1])  
  16.                 {  
  17.                     char* end_args;  
  18.                     char* arg;  
  19.                     ++start_args;  
  20.                     arg = apr_pstrdup(r->pool, start_args);  
  21.                     if ((end_args = strchr(arg, '&')) != NULL)  
  22.                         *end_args = '/0';  
  23.                     return arg;  
  24.                 }  
  25.             }  
  26.         }  
  27.     }  
  28.     return NULL;  
  29. }/*}}}*/
  這裡借鑑了原始碼中的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吧!
  1. char *get_cookie_param(request_rec *r, constchar *name)  
  2. {/*{{{*/
  3.     constchar *cookies;  
  4.     constchar *start_cookie;  
  5.     if ((cookies = apr_table_get(r->headers_in, "Cookie"))) {  
  6.         for (start_cookie = ap_strstr_c(cookies, name); start_cookie;  
  7.                 start_cookie = ap_strstr_c(start_cookie + 1, name)) {  
  8.             if (start_cookie == cookies ||  
  9.                     start_cookie[-1] == ';' ||  
  10.                     start_cookie[-1] == ',' ||  
  11.                     isspace(start_cookie[-1])) {  
  12.                 start_cookie += strlen(name);  
  13.                 while(*start_cookie && isspace(*start_cookie))  
  14.                     ++start_cookie;  
  15.                 if (*start_cookie == '=' && start_cookie[1]) {  
  16.                     char *end_cookie, *cookie;  
  17.                     ++start_cookie;  
  18.                     cookie = apr_pstrdup(r->pool, start_cookie);  
  19.                     if ((end_cookie = strchr(cookie, ';')) != NULL)  
  20.                         *end_cookie = '/0';   
  21.                     if((end_cookie = strchr(cookie, ',')) != NULL)  
  22.                         *end_cookie = '/0';   
  23.                     return cookie;   
  24.                 }  
  25.             }  
  26.         }  
  27.     }  
  28.     return NULL;  
  29. }/*}}}*/
  還有很多其他引數,比如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>