1<?xml version="1.0" encoding="ISO-8859-1"?> 2<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd"> 3<html xmlns="http://www.w3.org/1999/xhtml" lang="en" xml:lang="en"><head><!-- 4 XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX 5 This file is generated from xml source: DO NOT EDIT 6 XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX 7 --> 8<title>Developing modules for the Apache HTTP Server 2.4 - Apache HTTP Server</title> 9<link href="/style/css/manual.css" rel="stylesheet" media="all" type="text/css" title="Main stylesheet" /> 10<link href="/style/css/manual-loose-100pc.css" rel="alternate stylesheet" media="all" type="text/css" title="No Sidebar - Default font size" /> 11<link href="/style/css/manual-print.css" rel="stylesheet" media="print" type="text/css" /><link rel="stylesheet" type="text/css" href="/style/css/prettify.css" /> 12<script src="/style/scripts/prettify.min.js" type="text/javascript"> 13</script> 14 15<link href="/images/favicon.ico" rel="shortcut icon" /></head> 16<body id="manual-page"><div id="page-header"> 17<p class="menu"><a href="/mod/">Modules</a> | <a href="/mod/directives.html">Directives</a> | <a href="http://wiki.apache.org/httpd/FAQ">FAQ</a> | <a href="/glossary.html">Glossary</a> | <a href="/sitemap.html">Sitemap</a></p> 18<p class="apache">Apache HTTP Server Version 2.4</p> 19<img alt="" src="/images/feather.gif" /></div> 20<div class="up"><a href="./"><img title="<-" alt="<-" src="/images/left.gif" /></a></div> 21<div id="path"> 22<a href="http://www.apache.org/">Apache</a> > <a href="http://httpd.apache.org/">HTTP Server</a> > <a href="http://httpd.apache.org/docs/">Documentation</a> > <a href="../">Version 2.4</a> > <a href="./">Developer</a></div><div id="page-content"><div id="preamble"><h1>Developing modules for the Apache HTTP Server 2.4</h1> 23<div class="toplang"> 24<p><span>Available Languages: </span><a href="/en/developer/modguide.html" title="English"> en </a></p> 25</div> 26 27<p>This document explains how you can develop modules for the Apache HTTP 28Server 2.4</p> 29</div> 30<div id="quickview"><ul id="toc"><li><img alt="" src="/images/down.gif" /> <a href="#introduction">Introduction</a></li> 31<li><img alt="" src="/images/down.gif" /> <a href="#basics">Defining a module</a></li> 32<li><img alt="" src="/images/down.gif" /> <a href="#hooking">Getting started: Hooking into the server</a></li> 33<li><img alt="" src="/images/down.gif" /> <a href="#handling">Building a handler</a></li> 34<li><img alt="" src="/images/down.gif" /> <a href="#configuration">Adding configuration options</a></li> 35<li><img alt="" src="/images/down.gif" /> <a href="#context">Context aware configurations</a></li> 36<li><img alt="" src="/images/down.gif" /> <a href="#summary">Summing up</a></li> 37<li><img alt="" src="/images/down.gif" /> <a href="#snippets">Some useful snippets of code</a></li> 38</ul><h3>See also</h3><ul class="seealso"><li><a href="request.html">Request Processing in Apache 2.4</a></li><li><a href="hooks.html">Apache 2.x Hook Functions</a></li></ul><ul class="seealso"><li><a href="#comments_section">Comments</a></li></ul></div> 39<div class="top"><a href="#page-header"><img alt="top" src="/images/up.gif" /></a></div> 40<div class="section"> 41<h2><a name="introduction" id="introduction">Introduction</a></h2> 42<h3><a name="what" id="what">What we will be discussing in this document</a></h3> 43<p> 44This document will discuss how you can create modules for the Apache 45HTTP Server 2.4, by exploring an example module called 46<code>mod_example</code>. In the first part of this document, the purpose 47of this module will be to calculate and print out various digest values for 48existing files on your web server, whenever we access the URL <code> 49http://hostname/filename.sum</code>. For instance, if we want to know the 50MD5 digest value of the file located at <code> 51http://www.example.com/index.html</code>, we would visit <code> 52http://www.example.com/index.html.sum</code>. 53</p> 54 55<p> 56In the second part of this document, which deals with configuration 57directive and context awareness, we will be looking at a module that simply 58writes out its own configuration to the client. 59</p> 60 61 62<h3><a name="prerequisites" id="prerequisites">Prerequisites</a></h3> 63<p> 64First and foremost, you are expected to have a basic knowledge of how the C 65programming language works. In most cases, we will try to be as pedagogical 66as possible and link to documents describing the functions used in the 67examples, but there are also many cases where it is necessary to either 68just assume that "it works" or do some digging yourself into what the hows 69and whys of various function calls. 70</p> 71<p> 72Lastly, you will need to have a basic understanding of how modules are 73loaded and configured in the Apache HTTP Server, as well as how to get the headers for 74Apache if you do not have them already, as these are needed for compiling 75new modules. 76</p> 77 78<h3><a name="compiling" id="compiling">Compiling your module</a></h3> 79<p> 80To compile the source code we are building in this document, we will be 81using <a href="/programs/apxs.html">APXS</a>. Assuming your source file 82is called mod_example.c, compiling, installing and activating the module is 83as simple as: 84</p> 85<div class="example"><pre>apxs -i -a -c mod_example.c</pre></div> 86 87 88</div><div class="top"><a href="#page-header"><img alt="top" src="/images/up.gif" /></a></div> 89<div class="section"> 90<h2><a name="basics" id="basics">Defining a module</a></h2> 91<p> 92<img src="/images/build_a_mod_3.png" alt="Module name tags" /><br /> 93Every module starts with the same declaration, or name tag if you will, 94that defines a module as <em>a separate entity within Apache</em>:</p> 95 96 97 98<pre class="prettyprint lang-c">module AP_MODULE_DECLARE_DATA example_module = 99{ 100 STANDARD20_MODULE_STUFF, 101 create_dir_conf, /* Per-directory configuration handler */ 102 merge_dir_conf, /* Merge handler for per-directory configurations */ 103 create_svr_conf, /* Per-server configuration handler */ 104 merge_svr_conf, /* Merge handler for per-server configurations */ 105 directives, /* Any directives we may have for httpd */ 106 register_hooks /* Our hook registering function */ 107};</pre> 108 109 110 111<p> 112This bit of code lets the server know that we have now registered a new module 113in the system, and that its name is <code>example_module</code>. The name 114of the module is used primarily for two things:<br /> 115</p> 116<ul> 117<li>Letting the server know how to load the module using the LoadModule</li> 118<li>Setting up a namespace for the module to use in configurations</li> 119</ul> 120<p> 121For now, we're only concerned with the first purpose of the module name, 122which comes into play when we need to load the module: 123</p> 124<pre class="prettyprint lang-config">LoadModule example_module modules/mod_example.so</pre> 125 126<p> 127In essence, this tells the server to open up <code>mod_example.so</code> and look for a module 128called <code>example_module</code>. 129</p> 130<p> 131Within this name tag of ours is also a bunch of references to how we would 132like to handle things: Which directives do we respond to in a configuration 133file or .htaccess, how do we operate within specific contexts, and what 134handlers are we interested in registering with the Apache HTTP service. We'll 135return to all these elements later in this document. 136</p> 137</div><div class="top"><a href="#page-header"><img alt="top" src="/images/up.gif" /></a></div> 138<div class="section"> 139<h2><a name="hooking" id="hooking">Getting started: Hooking into the server</a></h2> 140<h3><a name="hook_intro" id="hook_intro">An introduction to hooks</a></h3> 141<p> 142When handling requests in Apache HTTP Server 2.4, the first thing you will need to do is 143create a hook into the request handling process. A hook is essentially a 144message telling the server that you are willing to either serve or at least 145take a glance at certain requests given by clients. All handlers, whether 146it's mod_rewrite, mod_authn_*, mod_proxy and so on, are hooked into 147specific parts of the request process. As you are probably aware, modules 148serve different purposes; Some are authentication/authorization handlers, 149others are file or script handlers while some third modules rewrite URIs or 150proxies content. Furthermore, in the end, it is up to the user of the server 151how and when each module will come into place. Thus, the server itself does not 152presume to know which module is responsible for handling a specific 153request, and will ask each module whether they have an interest in a given 154request or not. It is then up to each module to either gently decline 155serving a request, accept serving it or flat out deny the request from 156being served, as authentication/authorization modules do: <br /> 157<img src="/images/build_a_mod_2.png" alt="Hook handling in httpd" /><br /> 158To make it a bit easier for handlers such as our mod_example to know 159whether the client is requesting content we should handle or not, the server 160has directives for hinting to modules whether their assistance is needed or 161not. Two of these are <code class="directive"><a href="/mod/mod_mime.html#addhandler">AddHandler</a></code> 162and <code class="directive"><a href="/mod/core.html#sethandler">SetHandler</a></code>. Let's take a look at 163an example using <code class="directive"><a href="/mod/mod_mime.html#addhandler">AddHandler</a></code>. In 164our example case, we want every request ending with .sum to be served by 165<code>mod_example</code>, so we'll add a configuration directive that tells 166the server to do just that: 167</p> 168<pre class="prettyprint lang-config">AddHandler example-handler .sum</pre> 169 170<p> 171What this tells the server is the following: <em>Whenever we receive a request 172for a URI ending in .sum, we are to let all modules know that we are 173looking for whoever goes by the name of "example-handler" </em>. 174Thus, when a request is being served that ends in .sum, the server will let all 175modules know, that this request should be served by "example-handler 176". As you will see later, when we start building mod_example, we will 177check for this handler tag relayed by <code>AddHandler</code> and reply to 178the server based on the value of this tag. 179</p> 180 181<h3><a name="hook_declaration" id="hook_declaration">Hooking into httpd</a></h3> 182<p> 183To begin with, we only want to create a simple handler, that replies to the 184client browser when a specific URL is requested, so we won't bother setting 185up configuration handlers and directives just yet. Our initial module 186definition will look like this:</p> 187 188 189 190<pre class="prettyprint lang-c">module AP_MODULE_DECLARE_DATA example_module = 191{ 192 STANDARD20_MODULE_STUFF, 193 NULL, 194 NULL, 195 NULL, 196 NULL, 197 NULL, 198 register_hooks /* Our hook registering function */ 199};</pre> 200 201 202 203 204<p>This lets the server know that we are not interesting in anything fancy, we 205just want to hook onto the requests and possibly handle some of them. </p> 206 207<p> The reference in our example declaration, <code>register_hooks</code> 208is the name of a function we will create to manage how we hook onto the 209request process. In this example module, the function has just one purpose; 210To create a simple hook that gets called after all the rewrites, access 211control etc has been handled. Thus, we will let the server know, that we want 212to hook into its process as one of the last modules: 213</p> 214 215 216<pre class="prettyprint lang-c">static void register_hooks(apr_pool_t *pool) 217{ 218 /* Create a hook in the request handler, so we get called when a request arrives */ 219 ap_hook_handler(example_handler, NULL, NULL, APR_HOOK_LAST); 220}</pre> 221 222 223 224<p> 225The <code>example_handler</code> reference is the function that will handle 226the request. We will discuss how to create a handler in the next chapter. 227</p> 228 229<h3><a name="hook_others" id="hook_others">Other useful hooks</a></h3> 230<p> 231Hooking into the request handling phase is but one of many hooks that you 232can create. Some other ways of hooking are: 233</p> 234<ul> 235<li><code>ap_hook_child_init</code>: Place a hook that executes when a child process is spawned (commonly used for initializing modules after the server has forked)</li> 236<li><code>ap_hook_pre_config</code>: Place a hook that executes before any configuration data has been read (very early hook)</li> 237<li><code>ap_hook_post_config</code>: Place a hook that executes after configuration has been parsed, but before the server has forked</li> 238<li><code>ap_hook_translate_name</code>: Place a hook that executes when a URI needs to be translated into a filename on the server (think <code>mod_rewrite</code>)</li> 239<li><code>ap_hook_quick_handler</code>: Similar to <code>ap_hook_handler</code>, except it is run before any other request hooks (translation, auth, fixups etc)</li> 240<li><code>ap_hook_log_transaction</code>: Place a hook that executes when the server is about to add a log entry of the current request</li> 241</ul> 242 243 244</div><div class="top"><a href="#page-header"><img alt="top" src="/images/up.gif" /></a></div> 245<div class="section"> 246<h2><a name="handling" id="handling">Building a handler</a></h2> 247<p> 248A handler is essentially a function that receives a callback when a request 249to the server is made. It is passed a record of the current request (how it was 250made, which headers and requests were passed along, who's giving the 251request and so on), and is put in charge of either telling the server that it's 252not interested in the request or handle the request with the tools provided. 253</p> 254<h3><a name="simple_handler" id="simple_handler">A simple "Hello, world!" 255handler</a></h3> 256<p>Let's start off by making a very simple request handler 257that does the following: 258</p> 259<ol> 260<li>Check that this is a request that should be served by "example-handler"</li> 261<li>Set the content type of our output to <code>text/html</code></li> 262<li>Write "Hello, world!" back to the client browser</li> 263<li>Let the server know that we took care of this request and everything went fine</li> 264</ol> 265<p> 266In C code, our example handler will now look like this: 267</p> 268 269 270<pre class="prettyprint lang-c">static int example_handler(request_rec *r) 271{ 272 /* First off, we need to check if this is a call for the "example-handler" handler. 273 * If it is, we accept it and do our things, if not, we simply return DECLINED, 274 * and the server will try somewhere else. 275 */ 276 if (!r->handler || strcmp(r->handler, "example-handler")) return (DECLINED); 277 278 /* Now that we are handling this request, we'll write out "Hello, world!" to the client. 279 * To do so, we must first set the appropriate content type, followed by our output. 280 */ 281 ap_set_content_type(r, "text/html"); 282 ap_rprintf(r, "Hello, world!"); 283 284 /* Lastly, we must tell the server that we took care of this request and everything went fine. 285 * We do so by simply returning the value OK to the server. 286 */ 287 return OK; 288}</pre> 289 290 291 292<p> 293Now, we put all we have learned together and end up with a program that 294looks like 295<a href="http://people.apache.org/~humbedooh/mods/examples/mod_example_1.c">mod_example_1.c</a> 296. The functions used in this example will be explained later in the section 297<a href="#functions">"Some useful functions you should know"</a>. 298</p> 299 300<h3><a name="request_rec" id="request_rec">The request_rec structure</a></h3> 301<p>The most essential part of any request is the <em>request record 302</em>. In a call to a handler function, this is represented by the <code> 303request_rec* </code> structure passed along with every call that is made. 304This struct, typically just referred to as <code>r</code> in modules, 305contains all the information you need for your module to fully process any 306HTTP request and respond accordingly.</p> <p>Some key elements of the <code> 307request_rec </code> structure are: 308</p> 309<ul> 310<li><code>r->handler (char*):</code> Contains the name of the handler the server is currently asking to do the handling of this request</li> 311<li><code>r->method (char*):</code> Contains the HTTP method being used, f.x. GET or POST</li> 312<li><code>r->filename (char*):</code> Contains the translated filename the client is requesting</li> 313<li><code>r->args (char*):</code> Contains the query string of the request, if any</li> 314<li><code>r->headers_in (apr_table_t*):</code> Contains all the headers sent by the client</li> 315<li><code>r->connection (conn_rec*):</code> A record containing information about the current connection</li> 316<li><code>r->user (char*):</code> If the URI requires authentication, this is set to the username provided</li> 317<li><code>r->useragent_ip (char*):</code> The IP address of the client connecting to us</li> 318<li><code>r->pool (apr_pool_t*)</code>: The memory pool of this request. We'll discuss this in the 319"<a href="#memory">Memory management</a>" chapter.</li> 320</ul> 321<p> 322A complete list of all the values contained within the <code>request_rec</code> structure can be found in 323the <a href="http://svn.apache.org/repos/asf/httpd/httpd/trunk/include/httpd.h"><code>httpd.h</code></a> header 324file or at <a href="http://ci.apache.org/projects/httpd/trunk/doxygen/structrequest__rec.html">http://ci.apache.org/projects/httpd/trunk/doxygen/structrequest__rec.html</a>. 325</p> 326 327 328<p> 329Let's try out some of these variables in another example handler:<br /> 330</p> 331 332 333<pre class="prettyprint lang-c">static int example_handler(request_rec *r) 334{ 335 /* Set the appropriate content type */ 336 ap_set_content_type(r, "text/html"); 337 338 /* Print out the IP address of the client connecting to us: */ 339 ap_rprintf(r, "<h2>Hello, %s!</h2>", r->useragent_ip); 340 341 /* If we were reached through a GET or a POST request, be happy, else sad. */ 342 if ( !strcmp(r->method, "POST") || !strcmp(r->method, "GET") ) { 343 ap_rputs("You used a GET or a POST method, that makes us happy!<br/>", r); 344 } 345 else { 346 ap_rputs("You did not use POST or GET, that makes us sad :(<br/>", r); 347 } 348 349 /* Lastly, if there was a query string, let's print that too! */ 350 if (r->args) { 351 ap_rprintf(r, "Your query string was: %s", r->args); 352 } 353 return OK; 354}</pre> 355 356 357 358 359 360<h3><a name="return_value" id="return_value">Return values</a></h3> 361<p> 362Apache relies on return values from handlers to signify whether a request 363was handled or not, and if so, whether the request went well or not. If a 364module is not interested in handling a specific request, it should always 365return the value <code>DECLINED</code>. If it is handling a request, it 366should either return the generic value <code>OK</code>, or a specific HTTP 367status code, for example: 368</p> 369 370 371<pre class="prettyprint lang-c">static int example_handler(request_rec *r) 372{ 373 /* Return 404: Not found */ 374 return HTTP_NOT_FOUND; 375}</pre> 376 377 378 379<p> 380Returning <code>OK</code> or a HTTP status code does not necessarily mean 381that the request will end. The server may still have other handlers that are 382interested in this request, for instance the logging modules which, upon a 383successful request, will write down a summary of what was requested and how 384it went. To do a full stop and prevent any further processing after your 385module is done, you can return the value <code>DONE</code> to let the server 386know that it should cease all activity on this request and carry on with 387the next, without informing other handlers. 388<br /> 389<strong>General response codes:</strong> 390</p> 391<ul> 392<li><code>DECLINED</code>: We are not handling this request</li> 393<li><code>OK</code>: We handled this request and it went well</li> 394<li><code>DONE</code>: We handled this request and the server should just close this thread without further processing</li> 395</ul> 396<p> 397<strong>HTTP specific return codes (excerpt):</strong> 398</p> 399<ul> 400<li><code>HTTP_OK (200)</code>: Request was okay</li> 401<li><code>HTTP_MOVED_PERMANENTLY (301)</code>: The resource has moved to a new URL</li> 402<li><code>HTTP_UNAUTHORIZED (401)</code>: Client is not authorized to visit this page</li> 403<li><code>HTTP_FORBIDDEN (403)</code>: Permission denied</li> 404<li><code>HTTP_NOT_FOUND (404)</code>: File not found</li> 405<li><code>HTTP_INTERNAL_SERVER_ERROR (500)</code>: Internal server error (self explanatory)</li> 406</ul> 407 408 409<h3><a name="functions" id="functions">Some useful functions you should know</a></h3> 410 411<ul> 412<li> 413 <code>ap_rputs(const char *string, request_rec *r)</code>: <br /> 414 Sends a string of text to the client. This is a shorthand version of <a href="http://ci.apache.org/projects/httpd/trunk/doxygen/group__APACHE__CORE__PROTO.html#gac827cd0537d2b6213a7c06d7c26cc36e"> 415 ap_rwrite</a>. 416 417 418 419<pre class="prettyprint lang-c">ap_rputs("Hello, world!", r);</pre> 420 421 422 423 424</li> 425<li> 426 <code> 427 <a href="http://ci.apache.org/projects/httpd/trunk/doxygen/group__APACHE__CORE__PROTO.html#ga5e91eb6ca777c9a427b2e82bf1eeb81d">ap_rprintf</a></code>: <br /> 428 This function works just like <code>printf</code>, except it sends the result to the client. 429 430 431 432<pre class="prettyprint lang-c">ap_rprintf(r, "Hello, %s!", r->useragent_ip);</pre> 433 434 435 436</li> 437<li> 438 <code> 439 <a href="http://ci.apache.org/projects/httpd/trunk/doxygen/group__APACHE__CORE__PROTO.html#gaa2f8412c400197338ec509f4a45e4579">ap_set_content_type</a>(request_rec *r, const char *type)</code>: <br /> 440 Sets the content type of the output you are sending. 441 442 443 444<pre class="prettyprint lang-c">ap_set_content_type(r, "text/plain"); /* force a raw text output */</pre> 445 446 447 448</li> 449 450 451</ul> 452 453 454<h3><a name="memory" id="memory">Memory management</a></h3> 455<p> 456Managing your resources in Apache HTTP Server 2.4 is quite easy, thanks to the memory pool 457system. In essence, each server, connection and request have their own 458memory pool that gets cleaned up when its scope ends, e.g. when a request 459is done or when a server process shuts down. All your module needs to do is 460latch onto this memory pool, and you won't have to worry about having to 461clean up after yourself - pretty neat, huh? 462</p> 463 464<p> 465In our module, we will primarily be allocating memory for each request, so 466it's appropriate to use the <code>r->pool</code> 467reference when creating new objects. A few of the functions for allocating 468memory within a pool are: 469</p> 470<ul> 471<li><code>void* <a href="http://apr.apache.org/docs/apr/1.4/group__apr__pools.html#ga85f1e193c31d109affda72f9a92c6915">apr_palloc</a>( 472apr_pool_t *p, apr_size_t size)</code>: Allocates <code>size</code> number of bytes in the pool for you</li> 473<li><code>void* <a href="http://apr.apache.org/docs/apr/1.4/group__apr__pools.html#gaf61c098ad258069d64cdf8c0a9369f9e">apr_pcalloc</a>( 474apr_pool_t *p, apr_size_t size)</code>: Allocates <code>size</code> number of bytes in the pool for you and sets all bytes to 0</li> 475<li><code>char* <a href="http://apr.apache.org/docs/apr/1.4/group__apr__strings.html#gabc79e99ff19abbd7cfd18308c5f85d47">apr_pstrdup</a>( 476apr_pool_t *p, const char *s)</code>: Creates a duplicate of the string <code>s</code>. This is useful for copying constant values so you can edit them</li> 477<li><code>char* <a href="http://apr.apache.org/docs/apr/1.4/group__apr__strings.html#ga3eca76b8d293c5c3f8021e45eda813d8">apr_psprintf</a>( 478apr_pool_t *p, const char *fmt, ...)</code>: Similar to <code>sprintf</code>, except the server supplies you with an appropriately allocated target variable</li> 479</ul> 480 481<p>Let's put these functions into an example handler:</p> 482 483 484 485<pre class="prettyprint lang-c">static int example_handler(request_rec *r) 486{ 487 const char* original = "You can't edit this!"; 488 char* copy; 489 int* integers; 490 491 /* Allocate space for 10 integer values and set them all to zero. */ 492 integers = apr_pcalloc(r->pool, sizeof(int)*10); 493 494 /* Create a copy of the 'original' variable that we can edit. */ 495 copy = apr_pstrdup(r->pool, original); 496 return OK; 497}</pre> 498 499 500 501<p> 502This is all well and good for our module, which won't need any 503pre-initialized variables or structures. However, if we wanted to 504initialize something early on, before the requests come rolling in, we 505could simply add a call to a function in our <code>register_hooks</code> 506function to sort it out: 507</p> 508 509 510<pre class="prettyprint lang-c">static void register_hooks(apr_pool_t *pool) 511{ 512 /* Call a function that initializes some stuff */ 513 example_init_function(pool); 514 /* Create a hook in the request handler, so we get called when a request arrives */ 515 ap_hook_handler(example_handler, NULL, NULL, APR_HOOK_LAST); 516}</pre> 517 518 519 520<p> 521In this pre-request initialization function we would not be using the 522same pool as we did when allocating resources for request-based functions. 523Instead, we would use the pool given to us by the server for allocating memory 524on a per-process based level. 525</p> 526 527 528<h3><a name="parsing" id="parsing">Parsing request data</a></h3> 529<p> 530In our example module, we would like to add a feature, that checks which 531type of digest, MD5 or SHA1 the client would like to see. This could be 532solved by adding a query string to the request. A query string is typically 533comprised of several keys and values put together in a string, for instance 534<code>valueA=yes&valueB=no&valueC=maybe</code>. It is up to the 535module itself to parse these and get the data it requires. In our example, 536we'll be looking for a key called <code>digest</code>, and if set to <code> 537md5</code>, we'll produce an MD5 digest, otherwise we'll produce a SHA1 538digest. 539</p> 540<p> 541Since the introduction of Apache HTTP Server 2.4, parsing request data from GET and 542POST requests have never been easier. All we require to parse both GET and 543POST data is four simple lines: 544</p> 545 546 547 548<pre class="prettyprint lang-c"> 549<a href="http://ci.apache.org/projects/httpd/trunk/doxygen/group__apr__tables.html#gad7ea82d6608a4a633fc3775694ab71e4">apr_table_t</a> *GET; <em> 550</em><a href="http://ci.apache.org/projects/httpd/trunk/doxygen/structapr__array__header__t.html">apr_array_header_t</a>*POST; 551<em> 552</em> 553<a href="http://ci.apache.org/projects/httpd/trunk/doxygen/group__APACHE__CORE__SCRIPT.html#gaed25877b529623a4d8f99f819ba1b7bd"> 554ap_args_to_table</a>(r, &GET); <em> 555</em><a href="http://ci.apache.org/projects/httpd/trunk/doxygen/group__APACHE__CORE__DAEMON.html#ga9d426b6382b49754d4f87c55f65af202"> 556ap_parse_form_data</a>(r, NULL, &POST, -1, 8192);</pre> 557 558 559 560<p> 561In our specific example module, we're looking for the <code>digest</code> 562value from the query string, which now resides inside a table called <code> 563GET</code>. To extract this value, we need only perform a simple operation: 564</p> 565 566 567 568<pre class="prettyprint lang-c">/* Get the "digest" key from the query string, if any. */ 569const char *digestType = apr_table_get(GET, "digest"); 570 571/* If no key was returned, we will set a default value instead. */ 572if (!digestType) digestType = "sha1";</pre> 573 574 575 576<p> 577The structures used for the POST and GET data are not exactly the same, so 578if we were to fetch a value from POST data instead of the query string, we 579would have to resort to a few more lines, as outlined in <a href="#get_post">this example</a> in the last chapter of this document. 580</p> 581 582 583<h3><a name="advanced_handler" id="advanced_handler">Making an advanced handler</a></h3> 584<p> 585Now that we have learned how to parse form data and manage our resources, 586we can move on to creating an advanced version of our module, that spits 587out the MD5 or SHA1 digest of files: 588</p> 589 590 591 592<pre class="prettyprint lang-c">static int example_handler(request_rec *r) 593{ 594 int rc, exists; 595 apr_finfo_t finfo; 596 apr_file_t *file; 597 char *filename; 598 char buffer[256]; 599 apr_size_t readBytes; 600 int n; 601 apr_table_t *GET; 602 apr_array_header_t *POST; 603 const char *digestType; 604 605 606 /* Check that the "example-handler" handler is being called. */ 607 if (!r->handler || strcmp(r->handler, "example-handler")) return (DECLINED); 608 609 /* Figure out which file is being requested by removing the .sum from it */ 610 filename = apr_pstrdup(r->pool, r->filename); 611 filename[strlen(filename)-4] = 0; /* Cut off the last 4 characters. */ 612 613 /* Figure out if the file we request a sum on exists and isn't a directory */ 614 rc = apr_stat(&finfo, filename, APR_FINFO_MIN, r->pool); 615 if (rc == APR_SUCCESS) { 616 exists = 617 ( 618 (finfo.filetype != APR_NOFILE) 619 && !(finfo.filetype & APR_DIR) 620 ); 621 if (!exists) return HTTP_NOT_FOUND; /* Return a 404 if not found. */ 622 } 623 /* If apr_stat failed, we're probably not allowed to check this file. */ 624 else return HTTP_FORBIDDEN; 625 626 /* Parse the GET and, optionally, the POST data sent to us */ 627 628 ap_args_to_table(r, &GET); 629 ap_parse_form_data(r, NULL, &POST, -1, 8192); 630 631 /* Set the appropriate content type */ 632 ap_set_content_type(r, "text/html"); 633 634 /* Print a title and some general information */ 635 ap_rprintf(r, "<h2>Information on %s:</h2>", filename); 636 ap_rprintf(r, "<b>Size:</b> %u bytes<br/>", finfo.size); 637 638 /* Get the digest type the client wants to see */ 639 digestType = apr_table_get(GET, "digest"); 640 if (!digestType) digestType = "MD5"; 641 642 643 rc = apr_file_open(&file, filename, APR_READ, APR_OS_DEFAULT, r->pool); 644 if (rc == APR_SUCCESS) { 645 646 /* Are we trying to calculate the MD5 or the SHA1 digest? */ 647 if (!strcasecmp(digestType, "md5")) { 648 /* Calculate the MD5 sum of the file */ 649 union { 650 char chr[16]; 651 uint32_t num[4]; 652 } digest; 653 apr_md5_ctx_t md5; 654 apr_md5_init(&md5); 655 readBytes = 256; 656 while ( apr_file_read(file, buffer, &readBytes) == APR_SUCCESS ) { 657 apr_md5_update(&md5, buffer, readBytes); 658 } 659 apr_md5_final(digest.chr, &md5); 660 661 /* Print out the MD5 digest */ 662 ap_rputs("<b>MD5: </b><code>", r); 663 for (n = 0; n < APR_MD5_DIGESTSIZE/4; n++) { 664 ap_rprintf(r, "%08x", digest.num[n]); 665 } 666 ap_rputs("</code>", r); 667 /* Print a link to the SHA1 version */ 668 ap_rputs("<br/><a href='?digest=sha1'>View the SHA1 hash instead</a>", r); 669 } 670 else { 671 /* Calculate the SHA1 sum of the file */ 672 union { 673 char chr[20]; 674 uint32_t num[5]; 675 } digest; 676 apr_sha1_ctx_t sha1; 677 apr_sha1_init(&sha1); 678 readBytes = 256; 679 while ( apr_file_read(file, buffer, &readBytes) == APR_SUCCESS ) { 680 apr_sha1_update(&sha1, buffer, readBytes); 681 } 682 apr_sha1_final(digest.chr, &sha1); 683 684 /* Print out the SHA1 digest */ 685 ap_rputs("<b>SHA1: </b><code>", r); 686 for (n = 0; n < APR_SHA1_DIGESTSIZE/4; n++) { 687 ap_rprintf(r, "%08x", digest.num[n]); 688 } 689 ap_rputs("</code>", r); 690 691 /* Print a link to the MD5 version */ 692 ap_rputs("<br/><a href='?digest=md5'>View the MD5 hash instead</a>", r); 693 } 694 apr_file_close(file); 695 696 } 697 /* Let the server know that we responded to this request. */ 698 return OK; 699}</pre> 700 701 702 703<p> 704This version in its entirety can be found here: 705<a href="http://people.apache.org/~humbedooh/mods/examples/mod_example_2.c">mod_example_2.c</a>. 706</p> 707 708 709</div><div class="top"><a href="#page-header"><img alt="top" src="/images/up.gif" /></a></div> 710<div class="section"> 711<h2><a name="configuration" id="configuration">Adding configuration options</a></h2> 712<p> 713In this next segment of this document, we will turn our eyes away from the 714digest module and create a new example module, whose only function is to 715write out its own configuration. The purpose of this is to examine how 716the server works with configuration, and what happens when you start writing 717advanced configurations 718for your modules. 719</p> 720<h3><a name="config_intro" id="config_intro">An introduction to configuration 721directives</a></h3> 722<p> 723If you are reading this, then you probably already know 724what a configuration directive is. Simply put, a directive is a way of 725telling an individual module (or a set of modules) how to behave, such as 726these directives control how <code>mod_rewrite</code> works: 727</p> 728<pre class="prettyprint lang-config">RewriteEngine On 729RewriteCond %{REQUEST_URI} ^/foo/bar 730RewriteRule ^/foo/bar/(.*)$ /foobar?page=$1</pre> 731 732<p> 733Each of these configuration directives are handled by a separate function, 734that parses the parameters given and sets up a configuration accordingly. 735</p> 736 737<h3><a name="config_simple" id="config_simple">Making an example configuration</a></h3> 738<p>To begin with, we'll create a basic configuration in C-space:</p> 739 740 741 742<pre class="prettyprint lang-c">typedef struct { 743 int enabled; /* Enable or disable our module */ 744 const char *path; /* Some path to...something */ 745 int typeOfAction; /* 1 means action A, 2 means action B and so on */ 746} example_config;</pre> 747 748 749 750<p> 751Now, let's put this into perspective by creating a very small module that 752just prints out a hard-coded configuration. You'll notice that we use the 753<code>register_hooks</code> function for initializing the configuration 754values to their defaults: 755</p> 756 757 758<pre class="prettyprint lang-c">typedef struct { 759 int enabled; /* Enable or disable our module */ 760 const char *path; /* Some path to...something */ 761 int typeOfAction; /* 1 means action A, 2 means action B and so on */ 762} example_config; 763 764static example_config config; 765 766static int example_handler(request_rec *r) 767{ 768 if (!r->handler || strcmp(r->handler, "example-handler")) return(DECLINED); 769 ap_set_content_type(r, "text/plain"); 770 ap_rprintf(r, "Enabled: %u\n", config.enabled); 771 ap_rprintf(r, "Path: %s\n", config.path); 772 ap_rprintf(r, "TypeOfAction: %x\n", config.typeOfAction); 773 return OK; 774} 775 776static void register_hooks(apr_pool_t *pool) 777{ 778 config.enabled = 1; 779 config.path = "/foo/bar"; 780 config.typeOfAction = 0x00; 781 ap_hook_handler(example_handler, NULL, NULL, APR_HOOK_LAST); 782} 783 784/* Define our module as an entity and assign a function for registering hooks */ 785 786module AP_MODULE_DECLARE_DATA example_module = 787{ 788 STANDARD20_MODULE_STUFF, 789 NULL, /* Per-directory configuration handler */ 790 NULL, /* Merge handler for per-directory configurations */ 791 NULL, /* Per-server configuration handler */ 792 NULL, /* Merge handler for per-server configurations */ 793 NULL, /* Any directives we may have for httpd */ 794 register_hooks /* Our hook registering function */ 795};</pre> 796 797 798 799<p> 800So far so good. To access our new handler, we could add the following to 801our configuration: 802</p> 803<pre class="prettyprint lang-config"><Location /example> 804 SetHandler example-handler 805</Location></pre> 806 807<p> 808When we visit, we'll see our current configuration being spit out by our 809module. 810</p> 811 812 813<h3><a name="register_directive" id="register_directive">Registering directives with the server</a></h3> 814<p> 815What if we want to change our configuration, not by hard-coding new values 816into the module, but by using either the httpd.conf file or possibly a 817.htaccess file? It's time to let the server know that we want this to be 818possible. To do so, we must first change our <em>name tag</em> to include a 819reference to the configuration directives we want to register with the server: 820</p> 821 822 823<pre class="prettyprint lang-c">module AP_MODULE_DECLARE_DATA example_module = 824{ 825 STANDARD20_MODULE_STUFF, 826 NULL, /* Per-directory configuration handler */ 827 NULL, /* Merge handler for per-directory configurations */ 828 NULL, /* Per-server configuration handler */ 829 NULL, /* Merge handler for per-server configurations */ 830 example_directives, /* Any directives we may have for httpd */ 831 register_hooks /* Our hook registering function */ 832};</pre> 833 834 835 836<p> 837This will tell the server that we are now accepting directives from the 838configuration files, and that the structure called <code>example_directives 839</code> holds information on what our directives are and how they work. 840Since we have three different variables in our module configuration, we 841will add a structure with three directives and a NULL at the end: 842</p> 843 844 845<pre class="prettyprint lang-c">static const command_rec example_directives[] = 846{ 847 AP_INIT_TAKE1("exampleEnabled", example_set_enabled, NULL, RSRC_CONF, "Enable or disable mod_example"), 848 AP_INIT_TAKE1("examplePath", example_set_path, NULL, RSRC_CONF, "The path to whatever"), 849 AP_INIT_TAKE2("exampleAction", example_set_action, NULL, RSRC_CONF, "Special action value!"), 850 { NULL } 851};</pre> 852 853 854 855<p> 856<img src="/images/build_a_mod_4.png" alt="Directives structure" /><br /> 857As you can see, each directive needs at least 5 parameters set: 858</p> 859<ol> 860<li><code><a href="http://ci.apache.org/projects/httpd/trunk/doxygen/group__APACHE__CORE__CONFIG.html#ga07c7d22ae17805e61204463326cf9c34">AP_INIT_TAKE1</a></code>: This is a macro that tells the server that this directive takes one and only one argument. 861If we required two arguments, we could use the macro <code><a href="http://ci.apache.org/projects/httpd/trunk/doxygen/group__APACHE__CORE__CONFIG.html#gafaec43534fcf200f37d9fecbf9247c21">AP_INIT_TAKE2</a></code> and so on (refer to httpd_conf.h 862for more macros).</li> 863<li><code>exampleEnabled</code>: This is the name of our directive. More precisely, it is what the user must put in his/her 864configuration in order to invoke a configuration change in our module.</li> 865<li><code>example_set_enabled</code>: This is a reference to a C function that parses the directive and sets the configuration 866accordingly. We will discuss how to make this in the following paragraph.</li> 867<li><code>RSRC_CONF</code>: This tells the server where the directive is permitted. We'll go into details on this value in the 868later chapters, but for now, <code>RSRC_CONF</code> means that the server will only accept these directives in a server context.</li> 869<li><code>"Enable or disable...."</code>: This is simply a brief description of what the directive does.</li> 870</ol> 871<p> 872(<em>The "missing" parameter in our definition, which is usually set to 873<code>NULL</code>, is an optional function that can be run after the 874initial function to parse the arguments have been run. This is usually 875omitted, as the function for verifying arguments might as well be used to 876set them.</em>) 877</p> 878 879<h3><a name="directive_handler" id="directive_handler">The directive handler function</a></h3> 880<p> 881Now that we have told the server to expect some directives for our module, it's 882time to make a few functions for handling these. What the server reads in the 883configuration file(s) is text, and so naturally, what it passes along to 884our directive handler is one or more strings, that we ourselves need to 885recognize and act upon. You'll notice, that since we set our <code> 886exampleAction</code> directive to accept two arguments, its C function also 887has an additional parameter defined:</p> 888 889 890<pre class="prettyprint lang-c">/* Handler for the "exampleEnabled" directive */ 891const char *example_set_enabled(cmd_parms *cmd, void *cfg, const char *arg) 892{ 893 if(!strcasecmp(arg, "on")) config.enabled = 1; 894 else config.enabled = 0; 895 return NULL; 896} 897 898/* Handler for the "examplePath" directive */ 899const char *example_set_path(cmd_parms *cmd, void *cfg, const char *arg) 900{ 901 config.path = arg; 902 return NULL; 903} 904 905/* Handler for the "exampleAction" directive */ 906/* Let's pretend this one takes one argument (file or db), and a second (deny or allow), */ 907/* and we store it in a bit-wise manner. */ 908const char *example_set_action(cmd_parms *cmd, void *cfg, const char *arg1, const char* arg2) 909{ 910 if(!strcasecmp(arg1, "file")) config.typeOfAction = 0x01; 911 else config.typeOfAction = 0x02; 912 913 if(!strcasecmp(arg2, "deny")) config.typeOfAction += 0x10; 914 else config.typeOfAction += 0x20; 915 return NULL; 916}</pre> 917 918 919 920 921 922<h3><a name="directive_complete" id="directive_complete">Putting it all together</a></h3> 923<p> 924Now that we have our directives set up, and handlers configured for them, 925we can assemble our module into one big file: 926</p> 927 928 929<pre class="prettyprint lang-c">/* mod_example_config_simple.c: */ 930#include <stdio.h> 931#include "apr_hash.h" 932#include "ap_config.h" 933#include "ap_provider.h" 934#include "httpd.h" 935#include "http_core.h" 936#include "http_config.h" 937#include "http_log.h" 938#include "http_protocol.h" 939#include "http_request.h" 940 941/* 942 ============================================================================== 943 Our configuration prototype and declaration: 944 ============================================================================== 945 */ 946typedef struct { 947 int enabled; /* Enable or disable our module */ 948 const char *path; /* Some path to...something */ 949 int typeOfAction; /* 1 means action A, 2 means action B and so on */ 950} example_config; 951 952static example_config config; 953 954/* 955 ============================================================================== 956 Our directive handlers: 957 ============================================================================== 958 */ 959/* Handler for the "exampleEnabled" directive */ 960const char *example_set_enabled(cmd_parms *cmd, void *cfg, const char *arg) 961{ 962 if(!strcasecmp(arg, "on")) config.enabled = 1; 963 else config.enabled = 0; 964 return NULL; 965} 966 967/* Handler for the "examplePath" directive */ 968const char *example_set_path(cmd_parms *cmd, void *cfg, const char *arg) 969{ 970 config.path = arg; 971 return NULL; 972} 973 974/* Handler for the "exampleAction" directive */ 975/* Let's pretend this one takes one argument (file or db), and a second (deny or allow), */ 976/* and we store it in a bit-wise manner. */ 977const char *example_set_action(cmd_parms *cmd, void *cfg, const char *arg1, const char* arg2) 978{ 979 if(!strcasecmp(arg1, "file")) config.typeOfAction = 0x01; 980 else config.typeOfAction = 0x02; 981 982 if(!strcasecmp(arg2, "deny")) config.typeOfAction += 0x10; 983 else config.typeOfAction += 0x20; 984 return NULL; 985} 986 987/* 988 ============================================================================== 989 The directive structure for our name tag: 990 ============================================================================== 991 */ 992static const command_rec example_directives[] = 993{ 994 AP_INIT_TAKE1("exampleEnabled", example_set_enabled, NULL, RSRC_CONF, "Enable or disable mod_example"), 995 AP_INIT_TAKE1("examplePath", example_set_path, NULL, RSRC_CONF, "The path to whatever"), 996 AP_INIT_TAKE2("exampleAction", example_set_action, NULL, RSRC_CONF, "Special action value!"), 997 { NULL } 998}; 999/* 1000 ============================================================================== 1001 Our module handler: 1002 ============================================================================== 1003 */ 1004static int example_handler(request_rec *r) 1005{ 1006 if(!r->handler || strcmp(r->handler, "example-handler")) return(DECLINED); 1007 ap_set_content_type(r, "text/plain"); 1008 ap_rprintf(r, "Enabled: %u\n", config.enabled); 1009 ap_rprintf(r, "Path: %s\n", config.path); 1010 ap_rprintf(r, "TypeOfAction: %x\n", config.typeOfAction); 1011 return OK; 1012} 1013 1014/* 1015 ============================================================================== 1016 The hook registration function (also initializes the default config values): 1017 ============================================================================== 1018 */ 1019static void register_hooks(apr_pool_t *pool) 1020{ 1021 config.enabled = 1; 1022 config.path = "/foo/bar"; 1023 config.typeOfAction = 3; 1024 ap_hook_handler(example_handler, NULL, NULL, APR_HOOK_LAST); 1025} 1026/* 1027 ============================================================================== 1028 Our module name tag: 1029 ============================================================================== 1030 */ 1031module AP_MODULE_DECLARE_DATA example_module = 1032{ 1033 STANDARD20_MODULE_STUFF, 1034 NULL, /* Per-directory configuration handler */ 1035 NULL, /* Merge handler for per-directory configurations */ 1036 NULL, /* Per-server configuration handler */ 1037 NULL, /* Merge handler for per-server configurations */ 1038 example_directives, /* Any directives we may have for httpd */ 1039 register_hooks /* Our hook registering function */ 1040};</pre> 1041 1042 1043 1044 1045<p> 1046In our httpd.conf file, we can now change the hard-coded configuration by 1047adding a few lines: 1048</p> 1049<pre class="prettyprint lang-config">ExampleEnabled On 1050ExamplePath "/usr/bin/foo" 1051ExampleAction file allow</pre> 1052 1053<p> 1054And thus we apply the configuration, visit <code>/example</code> on our 1055web site, and we see the configuration has adapted to what we wrote in our 1056configuration file. 1057</p> 1058 1059 1060 1061</div><div class="top"><a href="#page-header"><img alt="top" src="/images/up.gif" /></a></div> 1062<div class="section"> 1063<h2><a name="context" id="context">Context aware configurations</a></h2> 1064<h3><a name="context_intro" id="context_intro">Introduction to context aware configurations</a></h3> 1065<p> 1066In Apache HTTP Server 2.4, different URLs, virtual hosts, directories etc can have very 1067different meanings to the user of the server, and thus different contexts 1068within which modules must operate. For example, let's assume you have this 1069configuration set up for mod_rewrite: 1070</p> 1071<pre class="prettyprint lang-config"><Directory "/var/www"> 1072 RewriteCond %{HTTP_HOST} ^example.com$ 1073 RewriteRule (.*) http://www.example.com/$1 1074</Directory> 1075<Directory "/var/www/sub"> 1076 RewriteRule ^foobar$ index.php?foobar=true 1077</Directory></pre> 1078 1079<p> 1080In this example, you will have set up two different contexts for 1081mod_rewrite:</p> 1082<ol> 1083<li>Inside <code>/var/www</code>, all requests for <code>http://example.com</code> must go to <code>http://www.example.com</code></li> 1084<li>Inside <code>/var/www/sub</code>, all requests for <code>foobar</code> must go to <code>index.php?foobar=true</code></li> 1085</ol> 1086<p> 1087If mod_rewrite (or the entire server for that matter) wasn't context aware, then 1088these rewrite rules would just apply to every and any request made, 1089regardless of where and how they were made, but since the module can pull 1090the context specific configuration straight from the server, it does not need 1091to know itself, which of the directives are valid in this context, since 1092the server takes care of this.</p> 1093 1094<p> 1095So how does a module get the specific configuration for the server, 1096directory or location in question? It does so by making one simple call: 1097</p> 1098 1099 1100<pre class="prettyprint lang-c">example_config *config = (example_config*) <a href="http://ci.apache.org/projects/httpd/trunk/doxygen/group__APACHE__CORE__CONFIG.html#ga1093a5908a384eacc929b028c79f2a02">ap_get_module_config</a>(r->per_dir_config, &example_module);</pre> 1101 1102 1103 1104<p> 1105That's it! Of course, a whole lot goes on behind the scenes, which we will 1106discuss in this chapter, starting with how the server came to know what our 1107configuration looks like, and how it came to be set up as it is in the 1108specific context. 1109</p> 1110 1111 1112<h3><a name="context_base" id="context_base">Our basic configuration setup</a></h3> 1113<p>In this chapter, we will be working with a slightly modified version of 1114our previous context structure. We will set a <code>context</code> 1115variable that we can use to track which context configuration is being 1116used by the server in various places: 1117</p> 1118 1119<pre class="prettyprint lang-c">typedef struct { 1120 char context[256]; 1121 char path[256]; 1122 int typeOfAction; 1123 int enabled; 1124} example_config;</pre> 1125 1126 1127 1128<p>Our handler for requests will also be modified, yet still very simple:</p> 1129 1130 1131 1132<pre class="prettyprint lang-c">static int example_handler(request_rec *r) 1133{ 1134 if(!r->handler || strcmp(r->handler, "example-handler")) return(DECLINED); 1135 example_config *config = (example_config*) ap_get_module_config(r->per_dir_config, &example_module); 1136 ap_set_content_type(r, "text/plain"); 1137 ap_rprintf("Enabled: %u\n", config->enabled); 1138 ap_rprintf("Path: %s\n", config->path); 1139 ap_rprintf("TypeOfAction: %x\n", config->typeOfAction); 1140 ap_rprintf("Context: %s\n", config->context); 1141 return OK; 1142}</pre> 1143 1144 1145 1146 1147 1148<h3><a name="context_which" id="context_which">Choosing a context</a></h3> 1149<p> 1150Before we can start making our module context aware, we must first define, 1151which contexts we will accept. As we saw in the previous chapter, defining 1152a directive required five elements be set:</p> 1153 1154 1155 1156<pre class="prettyprint lang-c">AP_INIT_TAKE1("exampleEnabled", example_set_enabled, NULL, RSRC_CONF, "Enable or disable mod_example"),</pre> 1157 1158 1159 1160 1161<p>The <code>RSRC_CONF</code> definition told the server that we would only allow 1162this directive in a global server context, but since we are now trying out 1163a context aware version of our module, we should set this to something 1164more lenient, namely the value <code>ACCESS_CONF</code>, which lets us use 1165the directive inside <Directory> and <Location> blocks. For more 1166control over the placement of your directives, you can combine the following 1167restrictions together to form a specific rule: 1168</p> 1169<ul> 1170<li><code>RSRC_CONF</code>: Allow in .conf files (not .htaccess) outside <Directory> or <Location></li> 1171<li><code>ACCESS_CONF</code>: Allow in .conf files (not .htaccess) inside <Directory> or <Location></li> 1172<li><code>OR_OPTIONS</code>: Allow in .conf files and .htaccess when <code>AllowOverride Options</code> is set</li> 1173<li><code>OR_FILEINFO</code>: Allow in .conf files and .htaccess when <code>AllowOverride FileInfo</code> is set</li> 1174<li><code>OR_AUTHCFG</code>: Allow in .conf files and .htaccess when <code>AllowOverride AuthConfig</code> is set</li> 1175<li><code>OR_INDEXES</code>: Allow in .conf files and .htaccess when <code>AllowOverride Indexes</code> is set</li> 1176<li><code>OR_ALL</code>: Allow anywhere in .conf files and .htaccess</li> 1177</ul> 1178 1179 1180<h3><a name="context_pool" id="context_pool">Using the server to allocate configuration slots</a></h3> 1181<p> A much smarter way to manage your configurations is by letting the server 1182help you create them. To do so, we must first start off by changing our 1183<em>name tag</em> to let the server know, that it should assist us in creating 1184and managing our configurations. Since we have chosen the per-directory 1185(or per-location) context for our module configurations, we'll add a 1186per-directory creator and merger function reference in our tag:</p> 1187 1188 1189<pre class="prettyprint lang-c">module AP_MODULE_DECLARE_DATA example_module = 1190{ 1191 STANDARD20_MODULE_STUFF, 1192 create_dir_conf, /* Per-directory configuration handler */ 1193 merge_dir_conf, /* Merge handler for per-directory configurations */ 1194 NULL, /* Per-server configuration handler */ 1195 NULL, /* Merge handler for per-server configurations */ 1196 directives, /* Any directives we may have for httpd */ 1197 register_hooks /* Our hook registering function */ 1198};</pre> 1199 1200 1201 1202 1203 1204 1205 1206<h3><a name="context_new" id="context_new">Creating new context configurations</a></h3> 1207<p> 1208Now that we have told the server to help us create and manage configurations, 1209our first step is to make a function for creating new, blank 1210configurations. We do so by creating the function we just referenced in 1211our name tag as the Per-directory configuration handler:</p> 1212 1213<pre class="prettyprint lang-c">void* example_create_dir_conf(apr_pool_t* pool, char* context) { 1214 context = context ? context : "(undefined context)"; 1215 example_config *cfg = apr_pcalloc(pool, sizeof(example_config)); 1216 if(cfg) { 1217 /* Set some default values */ 1218 strcpy(cfg->context, x); 1219 cfg->enabled = 0; 1220 cfg->path = "/foo/bar"; 1221 cfg->typeOfAction = 0x11; 1222 } 1223 return cfg; 1224}</pre> 1225 1226 1227 1228 1229 1230 1231<h3><a name="context_merge" id="context_merge">Merging configurations</a></h3> 1232<p> 1233Our next step in creating a context aware configuration is merging 1234configurations. This part of the process particularly applies to scenarios 1235where you have a parent configuration and a child, such as the following: 1236</p> 1237<pre class="prettyprint lang-config"><Directory "/var/www"> 1238 ExampleEnabled On 1239 ExamplePath /foo/bar 1240 ExampleAction file allow 1241</Directory> 1242<Directory "/var/www/subdir"> 1243 ExampleAction file deny 1244</Directory></pre> 1245 1246<p> 1247In this example, it is natural to assume that the directory <code> 1248/var/www/subdir</code> should inherit the values set for the <code>/var/www 1249</code> directory, as we did not specify an <code>ExampleEnabled</code> nor 1250an <code>ExamplePath</code> for this directory. The server does not presume to 1251know if this is true, but cleverly does the following: 1252</p> 1253<ol> 1254<li>Creates a new configuration for <code>/var/www</code></li> 1255<li>Sets the configuration values according to the directives given for <code>/var/www</code></li> 1256<li>Creates a new configuration for <code>/var/www/subdir</code></li> 1257<li>Sets the configuration values according to the directives given for <code>/var/www/subdir</code></li> 1258<li><strong>Proposes a merge</strong> of the two configurations into a new configuration for <code>/var/www/subdir</code></li> 1259</ol> 1260<p> 1261This proposal is handled by the <code>merge_dir_conf</code> function we 1262referenced in our name tag. The purpose of this function is to assess the 1263two configurations and decide how they are to be merged:</p> 1264 1265 1266 1267<pre class="prettyprint lang-c">void* merge_dir_conf(apr_pool_t* pool, void* BASE, void* ADD) { 1268 example_config* base = (example_config *) BASE ; /* This is what was set in the parent context */ 1269 example_config* add = (example_config *) ADD ; /* This is what is set in the new context */ 1270 example_config* conf = (example_config *) create_dir_conf(pool, "Merged configuration"); /* This will be the merged configuration */ 1271 1272 /* Merge configurations */ 1273 conf->enabled = ( add->enabled == 0 ) ? base->enabled : add->enabled ; 1274 conf->typeOfAction = add->typeOfAction ? add->typeOfAction : base->typeOfAction; 1275 strcpy(conf->path, strlen(add->path) ? add->path : base->path); 1276 1277 return conf ; 1278}</pre> 1279 1280 1281 1282 1283 1284 1285<h3><a name="context_example" id="context_example">Trying out our new context aware configurations</a></h3> 1286<p> 1287Now, let's try putting it all together to create a new module that is 1288context aware. First off, we'll create a configuration that lets us test 1289how the module works: 1290</p> 1291<pre class="prettyprint lang-config"><Location "/a"> 1292 SetHandler example-handler 1293 ExampleEnabled on 1294 ExamplePath "/foo/bar" 1295 ExampleAction file allow 1296</Location> 1297 1298<Location "/a/b"> 1299 ExampleAction file deny 1300 ExampleEnabled off 1301</Location> 1302 1303<Location "/a/b/c"> 1304 ExampleAction db deny 1305 ExamplePath "/foo/bar/baz" 1306 ExampleEnabled on 1307</Location></pre> 1308 1309<p> 1310Then we'll assemble our module code. Note, that since we are now using our 1311name tag as reference when fetching configurations in our handler, I have 1312added some prototypes to keep the compiler happy: 1313</p> 1314 1315 1316<pre class="prettyprint lang-c">/*$6 1317 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1318 * mod_example_config.c 1319 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1320 */ 1321 1322 1323#include <stdio.h> 1324#include "apr_hash.h" 1325#include "ap_config.h" 1326#include "ap_provider.h" 1327#include "httpd.h" 1328#include "http_core.h" 1329#include "http_config.h" 1330#include "http_log.h" 1331#include "http_protocol.h" 1332#include "http_request.h" 1333 1334/*$1 1335 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 1336 Configuration structure 1337 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 1338 */ 1339 1340typedef struct 1341{ 1342 char context[256]; 1343 char path[256]; 1344 int typeOfAction; 1345 int enabled; 1346} example_config; 1347 1348/*$1 1349 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 1350 Prototypes 1351 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 1352 */ 1353 1354static int example_handler(request_rec *r); 1355const char *example_set_enabled(cmd_parms *cmd, void *cfg, const char *arg); 1356const char *example_set_path(cmd_parms *cmd, void *cfg, const char *arg); 1357const char *example_set_action(cmd_parms *cmd, void *cfg, const char *arg1, const char *arg2); 1358void *create_dir_conf(apr_pool_t *pool, char *context); 1359void *merge_dir_conf(apr_pool_t *pool, void *BASE, void *ADD); 1360static void register_hooks(apr_pool_t *pool); 1361 1362/*$1 1363 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 1364 Configuration directives 1365 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 1366 */ 1367 1368static const command_rec directives[] = 1369{ 1370 AP_INIT_TAKE1("exampleEnabled", example_set_enabled, NULL, ACCESS_CONF, "Enable or disable mod_example"), 1371 AP_INIT_TAKE1("examplePath", example_set_path, NULL, ACCESS_CONF, "The path to whatever"), 1372 AP_INIT_TAKE2("exampleAction", example_set_action, NULL, ACCESS_CONF, "Special action value!"), 1373 { NULL } 1374}; 1375 1376/*$1 1377 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 1378 Our name tag 1379 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 1380 */ 1381 1382module AP_MODULE_DECLARE_DATA example_module = 1383{ 1384 STANDARD20_MODULE_STUFF, 1385 create_dir_conf, /* Per-directory configuration handler */ 1386 merge_dir_conf, /* Merge handler for per-directory configurations */ 1387 NULL, /* Per-server configuration handler */ 1388 NULL, /* Merge handler for per-server configurations */ 1389 directives, /* Any directives we may have for httpd */ 1390 register_hooks /* Our hook registering function */ 1391}; 1392 1393/* 1394 ======================================================================================================================= 1395 Hook registration function 1396 ======================================================================================================================= 1397 */ 1398static void register_hooks(apr_pool_t *pool) 1399{ 1400 ap_hook_handler(example_handler, NULL, NULL, APR_HOOK_LAST); 1401} 1402 1403/* 1404 ======================================================================================================================= 1405 Our example web service handler 1406 ======================================================================================================================= 1407 */ 1408static int example_handler(request_rec *r) 1409{ 1410 if(!r->handler || strcmp(r->handler, "example-handler")) return(DECLINED); 1411 1412 /*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/ 1413 example_config *config = (example_config *) ap_get_module_config(r->per_dir_config, &example_module); 1414 /*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/ 1415 1416 ap_set_content_type(r, "text/plain"); 1417 ap_rprintf(r, "Enabled: %u\n", config->enabled); 1418 ap_rprintf(r, "Path: %s\n", config->path); 1419 ap_rprintf(r, "TypeOfAction: %x\n", config->typeOfAction); 1420 ap_rprintf(r, "Context: %s\n", config->context); 1421 return OK; 1422} 1423 1424/* 1425 ======================================================================================================================= 1426 Handler for the "exampleEnabled" directive 1427 ======================================================================================================================= 1428 */ 1429const char *example_set_enabled(cmd_parms *cmd, void *cfg, const char *arg) 1430{ 1431 /*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/ 1432 example_config *conf = (example_config *) cfg; 1433 /*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/ 1434 1435 if(conf) 1436 { 1437 if(!strcasecmp(arg, "on")) 1438 conf->enabled = 1; 1439 else 1440 conf->enabled = 0; 1441 } 1442 1443 return NULL; 1444} 1445 1446/* 1447 ======================================================================================================================= 1448 Handler for the "examplePath" directive 1449 ======================================================================================================================= 1450 */ 1451const char *example_set_path(cmd_parms *cmd, void *cfg, const char *arg) 1452{ 1453 /*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/ 1454 example_config *conf = (example_config *) cfg; 1455 /*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/ 1456 1457 if(conf) 1458 { 1459 strcpy(conf->path, arg); 1460 } 1461 1462 return NULL; 1463} 1464 1465/* 1466 ======================================================================================================================= 1467 Handler for the "exampleAction" directive ; 1468 Let's pretend this one takes one argument (file or db), and a second (deny or allow), ; 1469 and we store it in a bit-wise manner. 1470 ======================================================================================================================= 1471 */ 1472const char *example_set_action(cmd_parms *cmd, void *cfg, const char *arg1, const char *arg2) 1473{ 1474 /*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/ 1475 example_config *conf = (example_config *) cfg; 1476 /*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/ 1477 1478 if(conf) 1479 { 1480 { 1481 if(!strcasecmp(arg1, "file")) 1482 conf->typeOfAction = 0x01; 1483 else 1484 conf->typeOfAction = 0x02; 1485 if(!strcasecmp(arg2, "deny")) 1486 conf->typeOfAction += 0x10; 1487 else 1488 conf->typeOfAction += 0x20; 1489 } 1490 } 1491 1492 return NULL; 1493} 1494 1495/* 1496 ======================================================================================================================= 1497 Function for creating new configurations for per-directory contexts 1498 ======================================================================================================================= 1499 */ 1500void *create_dir_conf(apr_pool_t *pool, char *context) 1501{ 1502 context = context ? context : "Newly created configuration"; 1503 1504 /*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/ 1505 example_config *cfg = apr_pcalloc(pool, sizeof(example_config)); 1506 /*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/ 1507 1508 if(cfg) 1509 { 1510 { 1511 /* Set some default values */ 1512 strcpy(cfg->context, context); 1513 cfg->enabled = 0; 1514 memset(cfg->path, 0, 256); 1515 cfg->typeOfAction = 0x00; 1516 } 1517 } 1518 1519 return cfg; 1520} 1521 1522/* 1523 ======================================================================================================================= 1524 Merging function for configurations 1525 ======================================================================================================================= 1526 */ 1527void *merge_dir_conf(apr_pool_t *pool, void *BASE, void *ADD) 1528{ 1529 /*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/ 1530 example_config *base = (example_config *) BASE; 1531 example_config *add = (example_config *) ADD; 1532 example_config *conf = (example_config *) create_dir_conf(pool, "Merged configuration"); 1533 /*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/ 1534 1535 conf->enabled = (add->enabled == 0) ? base->enabled : add->enabled; 1536 conf->typeOfAction = add->typeOfAction ? add->typeOfAction : base->typeOfAction; 1537 strcpy(conf->path, strlen(add->path) ? add->path : base->path); 1538 return conf; 1539}</pre> 1540 1541 1542 1543 1544 1545 1546 1547</div><div class="top"><a href="#page-header"><img alt="top" src="/images/up.gif" /></a></div> 1548<div class="section"> 1549<h2><a name="summary" id="summary">Summing up</a></h2> 1550<p> 1551We have now looked at how to create simple modules for Apache HTTP Server 2.4 and 1552configuring them. What you do next is entirely up to you, but it is my 1553hope that something valuable has come out of reading this documentation. 1554If you have questions on how to further develop modules, you are welcome 1555to join our <a href="http://httpd.apache.org/lists.html">mailing lists</a> 1556or check out the rest of our documentation for further tips. 1557</p> 1558</div><div class="top"><a href="#page-header"><img alt="top" src="/images/up.gif" /></a></div> 1559<div class="section"> 1560<h2><a name="snippets" id="snippets">Some useful snippets of code</a></h2> 1561 1562<h3><a name="get_post" id="get_post">Retrieve variables from POST form data</a></h3> 1563 1564 1565 1566<pre class="prettyprint lang-c">typedef struct { 1567 const char* key; 1568 const char* value; 1569} keyValuePair; 1570 1571keyValuePair* readPost(request_rec* r) { 1572 apr_array_header_t *pairs = NULL; 1573 apr_off_t len; 1574 apr_size_t size; 1575 int res; 1576 int i = 0; 1577 char *buffer; 1578 keyValuePair* kvp; 1579 1580 res = ap_parse_form_data(r, NULL, &pairs, -1, HUGE_STRING_LEN); 1581 if (res != OK || !pairs) return NULL; /* Return NULL if we failed or if there are is no POST data */ 1582 kvp = apr_pcalloc(r->pool, sizeof(keyValuePair) * (pairs->nelts + 1)); 1583 while (pairs && !apr_is_empty_array(pairs)) { 1584 ap_form_pair_t *pair = (ap_form_pair_t *) apr_array_pop(pairs); 1585 apr_brigade_length(pair->value, 1, &len); 1586 size = (apr_size_t) len; 1587 buffer = apr_palloc(r->pool, size + 1); 1588 apr_brigade_flatten(pair->value, buffer, &size); 1589 buffer[len] = 0; 1590 kvp[i].key = apr_pstrdup(r->pool, pair->name); 1591 kvp[i].value = buffer; 1592 i++; 1593 } 1594 return kvp; 1595} 1596 1597static int example_handler(request_rec *r) 1598{ 1599 /*~~~~~~~~~~~~~~~~~~~~~~*/ 1600 keyValuePair* formData; 1601 /*~~~~~~~~~~~~~~~~~~~~~~*/ 1602 1603 formData = readPost(r); 1604 if (formData) { 1605 int i; 1606 for (i = 0; &formData[i]; i++) { 1607 if (formData[i].key && formData[i].value) { 1608 ap_rprintf(r, "%s = %s\n", formData[i].key, formData[i].value); 1609 } else if (formData[i].key) { 1610 ap_rprintf(r, "%s\n", formData[i].key); 1611 } else if (formData[i].value) { 1612 ap_rprintf(r, "= %s\n", formData[i].value); 1613 } else { 1614 break; 1615 } 1616 } 1617 } 1618 return OK; 1619}</pre> 1620 1621 1622 1623 1624 1625 1626 <h3><a name="headers_out" id="headers_out">Printing out every HTTP header received</a></h3> 1627 1628 1629 1630<pre class="prettyprint lang-c">static int example_handler(request_rec *r) 1631{ 1632 /*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/ 1633 const apr_array_header_t *fields; 1634 int i; 1635 apr_table_entry_t *e = 0; 1636 /*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/ 1637 1638 fields = apr_table_elts(r->headers_in); 1639 e = (apr_table_entry_t *) fields->elts; 1640 for(i = 0; i < fields->nelts; i++) { 1641 ap_rprintf(r, "%s: %s\n", e[i].key, e[i].val); 1642 } 1643 return OK; 1644}</pre> 1645 1646 1647 1648 1649 1650 1651 <h3><a name="request_body" id="request_body">Reading the request body into memory</a></h3> 1652 1653 1654 1655<pre class="prettyprint lang-c">static int util_read(request_rec *r, const char **rbuf, apr_off_t *size) 1656{ 1657 /*~~~~~~~~*/ 1658 int rc = OK; 1659 /*~~~~~~~~*/ 1660 1661 if((rc = ap_setup_client_block(r, REQUEST_CHUNKED_ERROR))) { 1662 return(rc); 1663 } 1664 1665 if(ap_should_client_block(r)) { 1666 1667 /*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/ 1668 char argsbuffer[HUGE_STRING_LEN]; 1669 apr_off_t rsize, len_read, rpos = 0; 1670 apr_off_t length = r->remaining; 1671 /*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/ 1672 1673 *rbuf = (const char *) apr_pcalloc(r->pool, (apr_size_t) (length + 1)); 1674 *size = length; 1675 while((len_read = ap_get_client_block(r, argsbuffer, sizeof(argsbuffer))) > 0) { 1676 if((rpos + len_read) > length) { 1677 rsize = length - rpos; 1678 } 1679 else { 1680 rsize = len_read; 1681 } 1682 1683 memcpy((char *) *rbuf + rpos, argsbuffer, (size_t) rsize); 1684 rpos += rsize; 1685 } 1686 } 1687 return(rc); 1688} 1689 1690static int example_handler(request_rec* r) 1691{ 1692 /*~~~~~~~~~~~~~~~~*/ 1693 apr_off_t size; 1694 const char *buffer; 1695 /*~~~~~~~~~~~~~~~~*/ 1696 1697 if(util_read(r, &buffer, &size) == OK) { 1698 ap_rprintf(r, "We read a request body that was %" APR_OFF_T_FMT " bytes long", size); 1699 } 1700 return OK; 1701}</pre> 1702 1703 1704 1705 1706 1707 1708 1709</div></div> 1710<div class="bottomlang"> 1711<p><span>Available Languages: </span><a href="/en/developer/modguide.html" title="English"> en </a></p> 1712</div><div class="top"><a href="#page-header"><img src="/images/up.gif" alt="top" /></a></div><div class="section"><h2><a id="comments_section" name="comments_section">Comments</a></h2><div class="warning"><strong>Notice:</strong><br />This is not a Q&A section. Comments placed here should be pointed towards suggestions on improving the documentation or server, and may be removed again by our moderators if they are either implemented or considered invalid/off-topic. Questions on how to manage the Apache HTTP Server should be directed at either our IRC channel, #httpd, on Freenode, or sent to our <a href="http://httpd.apache.org/lists.html">mailing lists</a>.</div> 1713<script type="text/javascript"><!--//--><![CDATA[//><!-- 1714var comments_shortname = 'httpd'; 1715var comments_identifier = 'http://httpd.apache.org/docs/2.4/developer/modguide.html'; 1716(function(w, d) { 1717 if (w.location.hostname.toLowerCase() == "httpd.apache.org") { 1718 d.write('<div id="comments_thread"><\/div>'); 1719 var s = d.createElement('script'); 1720 s.type = 'text/javascript'; 1721 s.async = true; 1722 s.src = 'https://comments.apache.org/show_comments.lua?site=' + comments_shortname + '&page=' + comments_identifier; 1723 (d.getElementsByTagName('head')[0] || d.getElementsByTagName('body')[0]).appendChild(s); 1724 } 1725 else { 1726 d.write('<div id="comments_thread">Comments are disabled for this page at the moment.<\/div>'); 1727 } 1728})(window, document); 1729//--><!]]></script></div><div id="footer"> 1730<p class="apache">Copyright 2014 The Apache Software Foundation.<br />Licensed under the <a href="http://www.apache.org/licenses/LICENSE-2.0">Apache License, Version 2.0</a>.</p> 1731<p class="menu"><a href="/mod/">Modules</a> | <a href="/mod/directives.html">Directives</a> | <a href="http://wiki.apache.org/httpd/FAQ">FAQ</a> | <a href="/glossary.html">Glossary</a> | <a href="/sitemap.html">Sitemap</a></p></div><script type="text/javascript"><!--//--><![CDATA[//><!-- 1732if (typeof(prettyPrint) !== 'undefined') { 1733 prettyPrint(); 1734} 1735//--><!]]></script> 1736</body></html>