How to write and compile an Apache module..
Have you ever had the need of handling an http request and modifying it in a very customized way, well one of the great things about Apache is that if you don't like what it does, you can change it, because it have a set of extended modules that can be added to it, or you can add you're own!
The most common way in writing apache modules is using perl or C APIs, its not that hard task! All you need to do is writing the main method (request handler) that will modify the request, hook into this method , and add the hook into your modules pool!
Here i'll show you how to do it in C step by step, we'll write a module that reads a cookie and based on its value it sets another one:
1- Add the required includes:
#include "httpd.h" /*Note that httpd.h is required for all Apache source code*/
#include "http_config.h" /*Contains the module structure, must always be included */
2- Write the main method (the handler), in this method do what ever handling you want to do in your request! as we all know apache stores the request in a table and you can access this table fields using methods like "apr_table_get", and you can add to it using "apr_table_add".
For more information about apache's request table structure, and allowed methods please refer to the following document:
http://thomas.eibner.dk/apache/table.html
An example of a main method is:
static int moduleName_method_handler (request_rec *r)
{
char *value = apr_table_get(r->headers_in,"Cookie"); /* Reading cookies from request headers */
char *exist = strstr(value,"valid"); /* checking for a certain cookie called valid*/
/* if cookie values is 1
set authorized cookie to 1 and reply with OK
else to 0 and reply with DECLINED*/
if ( exist == 1 ) {
char *cookie = (char *)apr_pstrcat(r->pool,"authorized=","1",";path=/",";domain=mysite.com",NULL);
apr_table_add(r->headers_out,"Set-Cookie",cookie);
return OK;
} else {
char *cookie = (char *)apr_pstrcat(r->pool,"authorized=",0,";path=/",";domain=mysite.com",NULL);
apr_table_add(r->headers_out,"Set-Cookie",cookie);
return DECLINED;
}
}
Its up to you to write what ever you want in this method with the best way that acheives your needs in handling the HTTP request.
2- Hook into the handler method you wrote:
You can do this by writing a simple hook like this:
/* This piece of code makes the name of the content handler known to Apache */
static void moduleName_register_hooks (apr_pool_t *p)
{
ap_hook_handler(moduleName_method_handler,NULL, NULL, APR_HOOK_FIRST);
}
APR_HOOK_FIRST: defines the order of hooking this method, it can be either FIRST, MIDDLE, or LAST.
3- Add the hook to your pool, this is how the module structure looks like:
module AP_MODULE_DECLARE_DATA moduleName=
{
STANDARD_MODULE_STUFF, /*Initializer */
NULL, /* create per-directory config structure */
NULL, /* merge per-directory config structures */
NULL, /* create per-server config structure */
NULL, /* merge per-server config structures */
NULL, /* command apr_table_t */
moduleName_register_hooks /* register hooks */
};
4- after you're done with your module all you need to do is add it to apache and compile it, in order to do this follow these steps:
A- In your apache modules directory create a folder with the name of your new module
/modules/moduleName
B- Add your .c module to this folder
C- Create modules/moduleName/config.m4 and add the following to it:
"APACHE_MODPATH_INIT(moduleName)
APACHE_MODULE(moduleName, changing request headeras, , , no)
APACHE_MODPATH_FINISH"
D- Create module/moduleName/Makefile.in. If your module doesn't need special build instructions, all you need to have in that file is include
"$(top_srcdir)/build/special.mk. "
E- Run configure command with --enable to enable all the modules you want including yours.
F- Run the command: make
G- Run the command: make install
Thats it! your module is compiled and added, all you need to do is testing it using any development tool, like firebug or HTTPfox :)
The most common way in writing apache modules is using perl or C APIs, its not that hard task! All you need to do is writing the main method (request handler) that will modify the request, hook into this method , and add the hook into your modules pool!
Here i'll show you how to do it in C step by step, we'll write a module that reads a cookie and based on its value it sets another one:
1- Add the required includes:
#include "httpd.h" /*Note that httpd.h is required for all Apache source code*/
#include "http_config.h" /*Contains the module structure, must always be included */
2- Write the main method (the handler), in this method do what ever handling you want to do in your request! as we all know apache stores the request in a table and you can access this table fields using methods like "apr_table_get", and you can add to it using "apr_table_add".
For more information about apache's request table structure, and allowed methods please refer to the following document:
http://thomas.eibner.dk/apache/table.html
An example of a main method is:
static int moduleName_method_handler (request_rec *r)
{
char *value = apr_table_get(r->headers_in,"Cookie"); /* Reading cookies from request headers */
char *exist = strstr(value,"valid"); /* checking for a certain cookie called valid*/
/* if cookie values is 1
set authorized cookie to 1 and reply with OK
else to 0 and reply with DECLINED*/
if ( exist == 1 ) {
char *cookie = (char *)apr_pstrcat(r->pool,"authorized=","1",";path=/",";domain=mysite.com",NULL);
apr_table_add(r->headers_out,"Set-Cookie",cookie);
return OK;
} else {
char *cookie = (char *)apr_pstrcat(r->pool,"authorized=",0,";path=/",";domain=mysite.com",NULL);
apr_table_add(r->headers_out,"Set-Cookie",cookie);
return DECLINED;
}
}
Its up to you to write what ever you want in this method with the best way that acheives your needs in handling the HTTP request.
2- Hook into the handler method you wrote:
You can do this by writing a simple hook like this:
/* This piece of code makes the name of the content handler known to Apache */
static void moduleName_register_hooks (apr_pool_t *p)
{
ap_hook_handler(moduleName_method_handler,NULL, NULL, APR_HOOK_FIRST);
}
APR_HOOK_FIRST: defines the order of hooking this method, it can be either FIRST, MIDDLE, or LAST.
3- Add the hook to your pool, this is how the module structure looks like:
module AP_MODULE_DECLARE_DATA moduleName=
{
STANDARD_MODULE_STUFF, /*Initializer */
NULL, /* create per-directory config structure */
NULL, /* merge per-directory config structures */
NULL, /* create per-server config structure */
NULL, /* merge per-server config structures */
NULL, /* command apr_table_t */
moduleName_register_hooks /* register hooks */
};
4- after you're done with your module all you need to do is add it to apache and compile it, in order to do this follow these steps:
A- In your apache modules directory create a folder with the name of your new module
/modules/moduleName
B- Add your .c module to this folder
C- Create modules/moduleName/config.m4 and add the following to it:
"APACHE_MODPATH_INIT(moduleName)
APACHE_MODULE(moduleName, changing request headeras, , , no)
APACHE_MODPATH_FINISH"
D- Create module/moduleName/Makefile.in. If your module doesn't need special build instructions, all you need to have in that file is include
"$(top_srcdir)/build/special.mk. "
E- Run configure command with --enable to enable all the modules you want including yours.
F- Run the command: make
G- Run the command: make install
Thats it! your module is compiled and added, all you need to do is testing it using any development tool, like firebug or HTTPfox :)
I have 2 questions:
ReplyDelete1. Does this mean that on each request to the server the code that sets the cookie will be executed ?
2. What more sophisticated scenarios are there where there is need to modify the server ?
@Fahad
ReplyDelete1- For this piece of code, yes every single request will pass through it, but of course you can write more sophisticated code not to allow this, this is just a sample.
2- One of the scenarios is using third parties integrations with your services (e.g java policy agent), most of the time these integrations cause modification on headers and may also change host name, don't forget that apache have lots of useful services like rewriting request, proxying... etc.