Monday, December 12, 2011

Start with apache httpd module development...

Apache by name is the start of a giant in http server which is more than 50% of the web world. currently known as httpd, its on such useful because of its popularization architecture where anyone can do there own changes by just  mounting a module.

So, today i'm going to demonstrate how to start with apache httpd dynamic module development with a hello world sample.

This tutorial is done on linux Mint destro. But any linux version will be no problem. Developing apache modules for windows is pretty straight forward, but need to prepare some tools which is not directly downloadable. The tool used is c/c++ compiler and apxs[APache eXtenSion] tool. apxs for windows is a purl module, and it need to have some configurations. But there wont be any change on application source of on development procedure. For the moment i'll continue for linux and will hope to continue windows instructions later.

Required components:
Apache httpd server[remember its not tomcat]
Apache Extension installed
gcc/g++ compiler
root access on mounting module to httpd and for restarting server

Steps
1.install apache2 and verify its running...

$ sudo apt-get install apache2



2.install apache extension tool


sudo apt-get install apache2-threaded-dev 
this will install required apache libs and includes. apache portable runtime[apr] may be install with apache server installation. so no need to bother on those.


3.Start development now


apache portable runtime is a world class c/c++ library for save coding  on a portable platform with light weight, but high performance. apache httpd server is the main project which was done using apr. so all the developments we are doing here is on top of apr. we only use major c/c++ libraries here.


If you have experience on linux kernel development, as you know there is a separate/dedicated set of libraries/include intended for kernel developments. Ideal situations here as well. instead of printf on std , we used printk in kernel modules. Here we use ap_rprintf. apache httpd modules are also very similar on functionality to linux kernel modules. You'll get to know those greatly.


There are two necessary includes in the module



#include "httpd.h" 
#include "http_config.h"

apache module is identified by httpd with a well defined data structure: AP_MODULE_DECLARE_DATA

there are major difference from apache 1.3x to 2.xx versions of httpd. So please be alert on which version you are using.here i'm doing with the latest[updated for version 1.4 on Feb 2012].


module AP_MODULE_DECLARE_DATA foo_module = {
    STANDARD20_MODULE_STUFF,
    foo_config_perdir_create,   /* create per-dir    config structures */
    foo_config_perdir_merge,    /* merge  per-dir    config structures */
    foo_config_server_create,   /* create per-server config structures */
    foo_config_server_merge,    /* merge  per-server config structures */
    foo_config_cmds,            /* table of configuration directives   */
    foo_register_hooks          /* register hooks */
};


The most important of here is the "register hooks"  other config's are kept NULL on this sample.
This hook is the join between httpd server and the module. This hook is created on server start. Actually speaking, this is a fork pipe name or a socket pipe in deep.

All requests to the httpd server will be mirrored to this hook and its the responsible of this hook to use a handler to execute the http request. So, lets see how we achieve this.







module AP_MODULE_DECLARE_DATA apache_test_module = 

        STANDARD20_MODULE_STUFF, 
        NULL, /* per-directory config creator */ 
        NULL, /* directory config merger */ 
        NULL, /* server config creator */ 
        NULL, /* server config merger */ 
        NULL, /* command table */ 
        apache_test_register_hook, /* request processing*/ 
}; 


This hook has a  definition of
static void 
apache_test_register_hook
(apr_pool_t *p) ;


What we have to do is to define a function to be handled by the requests coming from apache httpd pool.
Within this function lets define a separate handler function to look better coding.


static int ap_hook_http_req_handler(request_rec *r) ;


So, here is the actual hook function definition:


static void apache_test_register_hook(apr_pool_t *p) 

        ap_hook_handler( apache_test_handler, NULL, NULL, APR_HOOK_MIDDLE); 
}


What we have done now are, we have asked httpd to send us http sequests by sending a hook, and within the hook we have set a handler function to get the http request parameters.
Then what we have to do is to do the actual work we are all wanted to do from the start. To do something with the http requests. For example, lets say we want to send our own html tags to the browser from our module. What we have to do is to return the request with a proper html tag and with status 200k http response code. Now lets see how to achieve this.

static int apache_test_handler(request_rec *r) ;

so we define the actual handler function.


 #include "httpd.h"   
 #include "http_config.h"   
 static int apache_test_handler(request_rec *r)   
 {  
     if (strcmp(r->handler, "apache_test_module"))  
     {  
         return DECLINED;   
     }  
     ap_set_content_type(r, "text/html");   
     ap_rputs("<HTML>\n", r);  
     ap_rputs("\t<HEAD>\n", r);  
     ap_rputs("\t\t<TITLE>\n\t\t\tApache Test Module\n\t\t</TITLE>\n", r);  
     ap_rputs("\t</HEAD>\n\n", r);  
     ap_rputs("<H1>Hello Idiots....</H1>\n", r);  
     ap_rprintf(r, "Engineers are inside too..!!! <br>");  
     ap_rprintf(r, "<a href=\"http://blog.friendly.lk\">back to blog</a>\n");  
     ap_rputs("</BODY></HTML>\n" ,r);   
     return OK;   
 }   
 static void apache_test_register_hook(apr_pool_t *p)   
 {   
     ap_hook_handler(apache_test_handler, NULL, NULL, APR_HOOK_MIDDLE);   
 }   
 module AP_MODULE_DECLARE_DATA apache_test_module =   
 {   
     STANDARD20_MODULE_STUFF,   
     NULL, /* per-directory config creator */   
     NULL, /* directory config merger */   
     NULL, /* server config creator */   
     NULL, /* server config merger */   
     NULL, /* command table */   
     apache_test_register_hook, /* other request processing hooks */   
 };   

here at the first if() we check whether the request is from url http://localhost/apache_test_module otherwise we avoid processing.




so.. here is the final source save this in a file apache_test_module.c

and now its time to compile and install this module on apache server.

fist cd to the place where source apache_test_module.c is. then do the following with root privileged.

$ sudo apxs2 -ci apache_test_module.c 


Ok.. now the development part is done.But still, how the server will identify and forward requests to our module? for that, we need to configure our module in httpd.conf configuration file located at /etc/apache2/httpd.conf

 $ sudo gedit /etc/apache2/httpd.conf


add the following two two configurations on the fly.

LoadModule apache_test_module /usr/lib/apache2/modules/apache_test_module.so

SetHandler apache_test_module


the first tells httpd to load a new module called apache_test_module.so with the handler named apache_test_module.

the second says httpd request path handler to forwaard /apache_test_module URLs to above handler.



now its time to restart apache2 and check how it works...

$ sudo /etc/init.d/apache2 restart


then go to http://localhost/apache_test_module from your browser....

give me some comments on your results!!!!

Thanks!!!

3 comments:

  1. This tutorial was quite helpful, for initializing my 1st step for developing my own module in apache.

    ReplyDelete
  2. thank u.. useful article for apache beginners.

    ReplyDelete
  3. thanks for the detailed instruction on the apache module develement..

    ReplyDelete