modguide.xml revision cd42ded5addf01f4ac3b3357565034572388f614
03532fb1cbb7e8c1d5cf2e93aa3719f926631cabStephen Gallagher<!DOCTYPE manualpage SYSTEM "/style/manualpage.dtd">
03532fb1cbb7e8c1d5cf2e93aa3719f926631cabStephen Gallagher<?xml-stylesheet type="text/xsl" href="/style/manual.en.xsl"?>
03532fb1cbb7e8c1d5cf2e93aa3719f926631cabStephen Gallagher<!-- $LastChangedRevision$ -->
03532fb1cbb7e8c1d5cf2e93aa3719f926631cabStephen Gallagher Licensed to the Apache Software Foundation (ASF) under one or more
03532fb1cbb7e8c1d5cf2e93aa3719f926631cabStephen Gallagher contributor license agreements. See the NOTICE file distributed with
03532fb1cbb7e8c1d5cf2e93aa3719f926631cabStephen Gallagher this work for additional information regarding copyright ownership.
03532fb1cbb7e8c1d5cf2e93aa3719f926631cabStephen Gallagher The ASF licenses this file to You under the Apache License, Version 2.0
03532fb1cbb7e8c1d5cf2e93aa3719f926631cabStephen Gallagher (the "License"); you may not use this file except in compliance with
03532fb1cbb7e8c1d5cf2e93aa3719f926631cabStephen Gallagher the License. You may obtain a copy of the License at
03532fb1cbb7e8c1d5cf2e93aa3719f926631cabStephen Gallagher http://www.apache.org/licenses/LICENSE-2.0
7b58d637c20f87e1e49ffc1d49a4de8b25ef06bbJakub Hrozek Unless required by applicable law or agreed to in writing, software
03532fb1cbb7e8c1d5cf2e93aa3719f926631cabStephen Gallagher distributed under the License is distributed on an "AS IS" BASIS,
03532fb1cbb7e8c1d5cf2e93aa3719f926631cabStephen Gallagher WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
03532fb1cbb7e8c1d5cf2e93aa3719f926631cabStephen Gallagher See the License for the specific language governing permissions and
03532fb1cbb7e8c1d5cf2e93aa3719f926631cabStephen Gallagher limitations under the License.
03532fb1cbb7e8c1d5cf2e93aa3719f926631cabStephen Gallagher<parentdocument href="./">Developer</parentdocument>
03532fb1cbb7e8c1d5cf2e93aa3719f926631cabStephen Gallagher <title>Developing modules for the Apache HTTP Server 2.4</title>
03532fb1cbb7e8c1d5cf2e93aa3719f926631cabStephen Gallagher<p>This document explains how you can develop modules for the Apache HTTP
03532fb1cbb7e8c1d5cf2e93aa3719f926631cabStephen Gallagher<seealso><a href="request.html">Request Processing in Apache 2.4</a></seealso>
03532fb1cbb7e8c1d5cf2e93aa3719f926631cabStephen Gallagher<seealso><a href="hooks.html">Apache 2.x Hook Functions</a></seealso>
03532fb1cbb7e8c1d5cf2e93aa3719f926631cabStephen Gallagher<section id="introduction"><title>Introduction</title>
03532fb1cbb7e8c1d5cf2e93aa3719f926631cabStephen Gallagher<section id="what"><title>What we will be discussing in this document</title>
03532fb1cbb7e8c1d5cf2e93aa3719f926631cabStephen GallagherThis document will discuss how you can easily create modules for the Apache
03532fb1cbb7e8c1d5cf2e93aa3719f926631cabStephen GallagherHTTP Server 2.4, by exploring an example module called
03532fb1cbb7e8c1d5cf2e93aa3719f926631cabStephen Gallagher<code>mod_example</code>. In the first part of this document, the purpose
03532fb1cbb7e8c1d5cf2e93aa3719f926631cabStephen Gallagherof this module will be to calculate and print out various digest values for
728a1812b7c5f70febb522342c5b357da598acfeJakub Hrozekexisting files on your web server, whenever we access the URL <code>
728a1812b7c5f70febb522342c5b357da598acfeJakub Hrozekhttp://hostname/filename.sum</code>. For instance, if we want to know the
728a1812b7c5f70febb522342c5b357da598acfeJakub HrozekMD5 digest value of the file located at <code>
728a1812b7c5f70febb522342c5b357da598acfeJakub Hrozekhttp://www.example.com/index.html</code>, we would visit <code>
03532fb1cbb7e8c1d5cf2e93aa3719f926631cabStephen GallagherIn the second part of this document, which deals with configuration
03532fb1cbb7e8c1d5cf2e93aa3719f926631cabStephen Gallagherdirective and context awareness, we will be looking at a module that simply
03532fb1cbb7e8c1d5cf2e93aa3719f926631cabStephen Gallagherwrite out its own configuration to the client.
03532fb1cbb7e8c1d5cf2e93aa3719f926631cabStephen Gallagher<section id="prerequisites"><title>Prerequisites</title>
03532fb1cbb7e8c1d5cf2e93aa3719f926631cabStephen GallagherFirst and foremost, you are expected to have a basic knowledge of how the C
03532fb1cbb7e8c1d5cf2e93aa3719f926631cabStephen Gallagherprogramming language works. In most cases, we will try to be as pedagogical
03532fb1cbb7e8c1d5cf2e93aa3719f926631cabStephen Gallagheras possible and link to documents describing the functions used in the
61804568ce5ede3b1a699cda17c033dd6c23f0e3Sumit Boseexamples, but there are also many cases where it is necessary to either
61804568ce5ede3b1a699cda17c033dd6c23f0e3Sumit Bosejust assume that "it works" or do some digging yourself into what the hows
61804568ce5ede3b1a699cda17c033dd6c23f0e3Sumit Boseand whys of various function calls.
5f879ab8b6c1cefbc63e1c2303f79b09b6246ca3Stephen GallagherLastly, you will need to have a basic understanding of how modules are
5f879ab8b6c1cefbc63e1c2303f79b09b6246ca3Stephen Gallagherloaded and configured in the Apache HTTP Server, as well as how to get the headers for
5f879ab8b6c1cefbc63e1c2303f79b09b6246ca3Stephen GallagherApache if you do not have them already, as these are needed for compiling
5f879ab8b6c1cefbc63e1c2303f79b09b6246ca3Stephen Gallagher<section id="compiling"><title>Compiling your module</title>
4343b618051d295cbb1a805a85feb117a91c6945Jakub HrozekTo compile the source code we are building in this document, we will be
4343b618051d295cbb1a805a85feb117a91c6945Jakub Hrozekusing <a href="/programs/apxs.html">APXS</a>. Assuming your source file
4343b618051d295cbb1a805a85feb117a91c6945Jakub Hrozekis called mod_example.c, compiling, installing and activating the module is
4343b618051d295cbb1a805a85feb117a91c6945Jakub Hrozekas simple as:
03532fb1cbb7e8c1d5cf2e93aa3719f926631cabStephen Gallagher<section id="basics"><title>Defining a module</title>
03532fb1cbb7e8c1d5cf2e93aa3719f926631cabStephen Gallagher<img src="/images/build_a_mod_3.png" alt="Module name tags"/><br/>
03532fb1cbb7e8c1d5cf2e93aa3719f926631cabStephen GallagherEvery module starts with the same declaration, or name tag if you will,
03532fb1cbb7e8c1d5cf2e93aa3719f926631cabStephen Gallagherthat defines a module as <em>a separate entity within Apache</em>:</p>
03532fb1cbb7e8c1d5cf2e93aa3719f926631cabStephen Gallagher<!-- BEGIN EXAMPLE CODE -->
03532fb1cbb7e8c1d5cf2e93aa3719f926631cabStephen Gallaghermodule AP_MODULE_DECLARE_DATA example_module =
03532fb1cbb7e8c1d5cf2e93aa3719f926631cabStephen Gallagher STANDARD20_MODULE_STUFF,
03532fb1cbb7e8c1d5cf2e93aa3719f926631cabStephen Gallagher create_dir_conf, /* Per-directory configuration handler */
03532fb1cbb7e8c1d5cf2e93aa3719f926631cabStephen Gallagher merge_dir_conf, /* Merge handler for per-directory configurations */
03532fb1cbb7e8c1d5cf2e93aa3719f926631cabStephen Gallagher create_svr_conf, /* Per-server configuration handler */
03532fb1cbb7e8c1d5cf2e93aa3719f926631cabStephen Gallagher merge_svr_conf, /* Merge handler for per-server configurations */
03532fb1cbb7e8c1d5cf2e93aa3719f926631cabStephen Gallagher directives, /* Any directives we may have for httpd */
03532fb1cbb7e8c1d5cf2e93aa3719f926631cabStephen Gallagher register_hooks /* Our hook registering function */
4cdaf239d4504966bed8ecd5e3fa07def74c7302Sumit Bose<!-- END EXAMPLE CODE -->
4cdaf239d4504966bed8ecd5e3fa07def74c7302Sumit BoseThis bit of code lets the server know that we have now registered a new module
03532fb1cbb7e8c1d5cf2e93aa3719f926631cabStephen Gallagherin the system, and that its name is <code>example_module</code>. The name
03532fb1cbb7e8c1d5cf2e93aa3719f926631cabStephen Gallagherof the module is used primarily for two things:<br/>
294e9a5521d327c5cdc49beeb9cb9e703b3134f1Jan Zeleny<li>Letting the server know how to load the module using the LoadModule</li>
03532fb1cbb7e8c1d5cf2e93aa3719f926631cabStephen Gallagher<li>Setting up a namespace for the module to use in configurations</li>
03532fb1cbb7e8c1d5cf2e93aa3719f926631cabStephen GallagherFor now, we're only concerned with the first purpose of the module name,
03532fb1cbb7e8c1d5cf2e93aa3719f926631cabStephen Gallagherwhich comes into play when we need to load the module:
03532fb1cbb7e8c1d5cf2e93aa3719f926631cabStephen Gallagher<example><pre><a href="/mod/mod_so.html#LoadModule">LoadModule</a> example_module modules/mod_example.so</pre></example>
03532fb1cbb7e8c1d5cf2e93aa3719f926631cabStephen GallagherIn essence, this tells the server to open up <code>mod_example.so</code> and look for a module
03532fb1cbb7e8c1d5cf2e93aa3719f926631cabStephen GallagherWithin this name tag of ours is also a bunch of references to how we would
03532fb1cbb7e8c1d5cf2e93aa3719f926631cabStephen Gallagherlike to handle things: Which directives do we respond to in a configuration
03532fb1cbb7e8c1d5cf2e93aa3719f926631cabStephen Gallagherfile or .htaccess, how do we operate within specific contexts, and what
03532fb1cbb7e8c1d5cf2e93aa3719f926631cabStephen Gallagherhandlers are we interested in registering with the Apache HTTP service. We'll
03532fb1cbb7e8c1d5cf2e93aa3719f926631cabStephen Gallagherreturn to all these elements later in this document.
03532fb1cbb7e8c1d5cf2e93aa3719f926631cabStephen Gallagher<section id="hooking"><title>Getting started: Hooking into the server</title>
03532fb1cbb7e8c1d5cf2e93aa3719f926631cabStephen Gallagher<section id="hook_intro"><title>An introduction to hooks</title>
03532fb1cbb7e8c1d5cf2e93aa3719f926631cabStephen GallagherWhen handling requests in Apache HTTP Server 2.4, the first thing you will need to do is
03532fb1cbb7e8c1d5cf2e93aa3719f926631cabStephen Gallaghercreate a hook into the request handling process. A hook is essentially a
03532fb1cbb7e8c1d5cf2e93aa3719f926631cabStephen Gallaghermessage telling the server that you are willing to either serve or at least
03532fb1cbb7e8c1d5cf2e93aa3719f926631cabStephen Gallaghertake a glance at certain requests given by clients. All handlers, whether
03532fb1cbb7e8c1d5cf2e93aa3719f926631cabStephen Gallagherit's mod_rewrite, mod_authn_*, mod_proxy and so on, are hooked into
03532fb1cbb7e8c1d5cf2e93aa3719f926631cabStephen Gallagherspecific parts of the request process. As you are probably aware, modules
03532fb1cbb7e8c1d5cf2e93aa3719f926631cabStephen Gallagherserve different purposes; Some are authentication/authorization handlers,
03532fb1cbb7e8c1d5cf2e93aa3719f926631cabStephen Gallagherothers are file or script handlers while some third modules rewrite URIs or
03532fb1cbb7e8c1d5cf2e93aa3719f926631cabStephen Gallagherproxies content. Furthermore, in the end, it is up to the user of the server
a679f0167b646cffdae86546ed77e105576991b0Pavel Březinahow and when each module will come into place. Thus, the server itself does not
a679f0167b646cffdae86546ed77e105576991b0Pavel Březinapresume to know which module is responsible for handling a specific
a679f0167b646cffdae86546ed77e105576991b0Pavel Březinarequest, and will ask each module whether they have an interest in a given
a679f0167b646cffdae86546ed77e105576991b0Pavel Březinarequest or not. It is then up to each module to either gently decline
a679f0167b646cffdae86546ed77e105576991b0Pavel Březinaserving a request, accept serving it or flat out deny the request from
a679f0167b646cffdae86546ed77e105576991b0Pavel Březinabeing served, as authentication/authorization modules do: <br/>
a679f0167b646cffdae86546ed77e105576991b0Pavel Březina<img src="/images/build_a_mod_2.png" alt="Hook handling in httpd"/><br/>
a679f0167b646cffdae86546ed77e105576991b0Pavel BřezinaTo make it a bit easier for handlers such as our mod_example to know
a679f0167b646cffdae86546ed77e105576991b0Pavel Březinawhether the client is requesting content we should handle or not, the server
a679f0167b646cffdae86546ed77e105576991b0Pavel Březinahas directives for hinting to modules whether their assistance is needed or
a679f0167b646cffdae86546ed77e105576991b0Pavel Březinanot. Two of these are <directive module="mod_mime">AddHandler</directive>
a679f0167b646cffdae86546ed77e105576991b0Pavel Březinaand <directive module="core">SetHandler</directive>. Let's take a look at
a679f0167b646cffdae86546ed77e105576991b0Pavel Březinaan example using <directive module="mod_mime">AddHandler</directive>. In
de4ce3477497c20416c6397adb520bb60f3c6d28Jakub Hrozekour example case, we want every request ending with .sum to be served by
de4ce3477497c20416c6397adb520bb60f3c6d28Jakub Hrozek<code>mod_example</code>, so we'll add a configuration directive that tells
de4ce3477497c20416c6397adb520bb60f3c6d28Jakub Hrozekthe server to do just that:
a679f0167b646cffdae86546ed77e105576991b0Pavel BřezinaAddHandler example-handler .sum
a679f0167b646cffdae86546ed77e105576991b0Pavel BřezinaWhat this tells the server is the following: <em>Whenever we receive a request
a679f0167b646cffdae86546ed77e105576991b0Pavel Březinafor a URI ending in .sum, we are to let all modules know that we are
8a05fd320a44636d120a18eb7e9956c7b35b3138Jakub Hrozeklooking for whoever goes by the name of "example-handler" </em>.
7a7fe9ace6990f20bddccfbb8fbbe91204df979eYassir ElleyThus, when a request is being served that ends in .sum, the server will let all
8a05fd320a44636d120a18eb7e9956c7b35b3138Jakub Hrozekmodules know, that this request should be served by "example-handler
8a05fd320a44636d120a18eb7e9956c7b35b3138Jakub Hrozek". As you will see later, when we start building mod_example, we will
8a05fd320a44636d120a18eb7e9956c7b35b3138Jakub Hrozekcheck for this handler tag relayed by <code>AddHandler</code> and reply to
8a05fd320a44636d120a18eb7e9956c7b35b3138Jakub Hrozekthe server based on the value of this tag.
8a05fd320a44636d120a18eb7e9956c7b35b3138Jakub Hrozek<section id="hook_declaration"><title>Hooking into httpd</title>
8a05fd320a44636d120a18eb7e9956c7b35b3138Jakub HrozekTo begin with, we only want to create a simple handler, that replies to the
8a05fd320a44636d120a18eb7e9956c7b35b3138Jakub Hrozekclient browser when a specific URL is requested, so we won't bother setting
1ce58f139699dd26b8888f4131c996263b6a80a5Jakub Hrozekup configuration handlers and directives just yet. Our initial module
1ce58f139699dd26b8888f4131c996263b6a80a5Jakub Hrozekdefinition will look like this:</p>
1ce58f139699dd26b8888f4131c996263b6a80a5Jakub Hrozek<!-- BEGIN EXAMPLE CODE -->
1ce58f139699dd26b8888f4131c996263b6a80a5Jakub Hrozekmodule AP_MODULE_DECLARE_DATA example_module =
1ce58f139699dd26b8888f4131c996263b6a80a5Jakub Hrozek STANDARD20_MODULE_STUFF,
1ce58f139699dd26b8888f4131c996263b6a80a5Jakub Hrozek register_hooks /* Our hook registering function */
1ce58f139699dd26b8888f4131c996263b6a80a5Jakub Hrozek<!-- END EXAMPLE CODE -->
1ce58f139699dd26b8888f4131c996263b6a80a5Jakub Hrozek<p>This lets the server know that we are not interesting in anything fancy, we
1ce58f139699dd26b8888f4131c996263b6a80a5Jakub Hrozekjust want to hook onto the requests and possibly handle some of them. </p>
1ce58f139699dd26b8888f4131c996263b6a80a5Jakub Hrozek<p> The reference in our example declaration, <code>register_hooks</code>
1ce58f139699dd26b8888f4131c996263b6a80a5Jakub Hrozekis the name of a function we will create to manage how we hook onto the
1ce58f139699dd26b8888f4131c996263b6a80a5Jakub Hrozekrequest process. In this example module, the function has just one purpose;
1ce58f139699dd26b8888f4131c996263b6a80a5Jakub HrozekTo create a simple hook that gets called after all the rewrites, access
1ce58f139699dd26b8888f4131c996263b6a80a5Jakub Hrozekcontrol etc has been handled. Thus, we will let the server know, that we want
1ce58f139699dd26b8888f4131c996263b6a80a5Jakub Hrozekto hook into its process as one of the last modules:
8a05fd320a44636d120a18eb7e9956c7b35b3138Jakub Hrozek<!-- BEGIN EXAMPLE CODE -->
1ce58f139699dd26b8888f4131c996263b6a80a5Jakub Hrozekstatic void register_hooks(apr_pool_t *pool)
1ce58f139699dd26b8888f4131c996263b6a80a5Jakub Hrozek /* Create a hook in the request handler, so we get called when a request arrives */
1ce58f139699dd26b8888f4131c996263b6a80a5Jakub Hrozek ap_hook_handler(example_handler, NULL, NULL, APR_HOOK_LAST);
1ce58f139699dd26b8888f4131c996263b6a80a5Jakub Hrozek<!-- END EXAMPLE CODE -->
8a05fd320a44636d120a18eb7e9956c7b35b3138Jakub HrozekThe <code>example_handler</code> reference is the function that will handle
8a05fd320a44636d120a18eb7e9956c7b35b3138Jakub Hrozekthe request. We will discuss how to create a handler in the next chapter.
8a05fd320a44636d120a18eb7e9956c7b35b3138Jakub Hrozek<section id="hook_others"><title>Other useful hooks</title>
ba4a81e933deebb416603369b447ead6ebaa040dJakub HrozekHooking into the request handling phase is but one of many hooks that you
ba4a81e933deebb416603369b447ead6ebaa040dJakub Hrozekcan create. Some other ways of hooking are:
fdaaf2525e333af04ee9b48429b6766b5fd6cab6Jakub Hrozek<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>
fdaaf2525e333af04ee9b48429b6766b5fd6cab6Jakub Hrozek<li><code>ap_hook_pre_config</code>: Place a hook that executes before any configuration data has been read (very early hook)</li>
fdaaf2525e333af04ee9b48429b6766b5fd6cab6Jakub Hrozek<li><code>ap_hook_post_config</code>: Place a hook that executes after configuration has been parsed, but before the server has forked</li>
fdaaf2525e333af04ee9b48429b6766b5fd6cab6Jakub Hrozek<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>
fdaaf2525e333af04ee9b48429b6766b5fd6cab6Jakub Hrozek<section id="handling"><title>Building a handler</title>
fdaaf2525e333af04ee9b48429b6766b5fd6cab6Jakub HrozekA handler is essentially a function that receives a callback when a request
fdaaf2525e333af04ee9b48429b6766b5fd6cab6Jakub Hrozekto the server is made. It is passed a record of the current request (how it was
ba4a81e933deebb416603369b447ead6ebaa040dJakub Hrozekmade, which headers and requests were passed along, who's giving the
ba4a81e933deebb416603369b447ead6ebaa040dJakub Hrozekrequest and so on), and is put in charge of either telling the server that it's
ba4a81e933deebb416603369b447ead6ebaa040dJakub Hrozeknot interested in the request or handle the request with the tools provided.
ba4a81e933deebb416603369b447ead6ebaa040dJakub Hrozek<section id="simple_handler"><title>A simple "Hello, world!"
ba4a81e933deebb416603369b447ead6ebaa040dJakub Hrozekhandler</title>
ba4a81e933deebb416603369b447ead6ebaa040dJakub Hrozek<p>Let's start off by making a very simple request handler
60cab26b12df9a2153823972cde0c38ca86e01b9Yassir Elleythat does the following:
60cab26b12df9a2153823972cde0c38ca86e01b9Yassir Elley<li>Check that this is a request that should be served by "example-handler"</li>
60cab26b12df9a2153823972cde0c38ca86e01b9Yassir Elley<li>Set the content type of our output to <code>text/html</code></li>
60cab26b12df9a2153823972cde0c38ca86e01b9Yassir Elley<li>Write "Hello, world!" back to the client browser</li>
60cab26b12df9a2153823972cde0c38ca86e01b9Yassir Elley<li>Let the server know that we took care of this request and everything went fine</li>
60cab26b12df9a2153823972cde0c38ca86e01b9Yassir ElleyIn C code, our example handler will now look like this:
60cab26b12df9a2153823972cde0c38ca86e01b9Yassir Elley<!-- BEGIN EXAMPLE CODE -->
60cab26b12df9a2153823972cde0c38ca86e01b9Yassir Elleystatic int example_handler(request_rec *r)
60cab26b12df9a2153823972cde0c38ca86e01b9Yassir Elley /* First off, we need to check if this is a call for the "example-handler" handler.
60cab26b12df9a2153823972cde0c38ca86e01b9Yassir Elley * If it is, we accept it and do our things, if not, we simply return DECLINED,
60cab26b12df9a2153823972cde0c38ca86e01b9Yassir Elley * and the server will try somewhere else.
60cab26b12df9a2153823972cde0c38ca86e01b9Yassir Elley if (!r->handler || strcmp(r->handler, "example-handler")) return (DECLINED);
60cab26b12df9a2153823972cde0c38ca86e01b9Yassir Elley /* Now that we are handling this request, we'll write out "Hello, world!" to the client.
60cab26b12df9a2153823972cde0c38ca86e01b9Yassir Elley * To do so, we must first set the appropriate content type, followed by our output.
60cab26b12df9a2153823972cde0c38ca86e01b9Yassir Elley ap_rprintf(r, "Hello, world!");
60cab26b12df9a2153823972cde0c38ca86e01b9Yassir Elley /* Lastly, we must tell the server that we took care of this request and everything went fine.
60cab26b12df9a2153823972cde0c38ca86e01b9Yassir Elley * We do so by simply returning the value OK to the server.
60cab26b12df9a2153823972cde0c38ca86e01b9Yassir Elley<!-- END EXAMPLE CODE -->
60cab26b12df9a2153823972cde0c38ca86e01b9Yassir ElleyNow, we put all we have learned together and end up with a program that
60cab26b12df9a2153823972cde0c38ca86e01b9Yassir Elley<a href="http://people.apache.org/~humbedooh/mods/examples/mod_example_1.c">mod_example_1.c</a>
60cab26b12df9a2153823972cde0c38ca86e01b9Yassir Elley. The functions used in this example will be explained later in the section
60cab26b12df9a2153823972cde0c38ca86e01b9Yassir Elley<a href= "#functions">"Some useful functions you should know"</a>.
60cab26b12df9a2153823972cde0c38ca86e01b9Yassir Elley<section id="request_rec"><title>The request_rec structure</title>
60cab26b12df9a2153823972cde0c38ca86e01b9Yassir Elley<p>The most essential part of any request is the <em>request record
60cab26b12df9a2153823972cde0c38ca86e01b9Yassir Elley</em>. In a call to a handler function, this is represented by the <code>
60cab26b12df9a2153823972cde0c38ca86e01b9Yassir Elleyrequest_req* </code> structure passed along with every call that is made.
60cab26b12df9a2153823972cde0c38ca86e01b9Yassir ElleyThis struct, typically just refered to as <code>r</code> in modules,
60cab26b12df9a2153823972cde0c38ca86e01b9Yassir Elleycontains all the information you need for your module to fully process any
60cab26b12df9a2153823972cde0c38ca86e01b9Yassir ElleyHTTP request and respond accordingly.</p> <p>Some key elements of the <code>
60cab26b12df9a2153823972cde0c38ca86e01b9Yassir Elleyrequest_req </code> structure are:
60cab26b12df9a2153823972cde0c38ca86e01b9Yassir Elley<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>
60cab26b12df9a2153823972cde0c38ca86e01b9Yassir Elley<li><code>r->method (char*):</code> Contains the HTTP method being used, f.x. GET or POST</li>
60cab26b12df9a2153823972cde0c38ca86e01b9Yassir Elley<li><code>r->filename (char*):</code> Contains the translated filename the client is requesting</li>
60cab26b12df9a2153823972cde0c38ca86e01b9Yassir Elley<li><code>r->args (char*):</code> Contains the query string of the request, if any</li>
60cab26b12df9a2153823972cde0c38ca86e01b9Yassir Elley<li><code>r->headers_in (apr_table_t*):</code> Contains all the headers sent by the client</li>
60cab26b12df9a2153823972cde0c38ca86e01b9Yassir Elley<li><code>r->connection (conn_rec*):</code> A record containing information about the current connection</li>
60cab26b12df9a2153823972cde0c38ca86e01b9Yassir Elley<li><code>r->useragent_ip (char*):</code> The IP address of the client connecting to us</li>
60cab26b12df9a2153823972cde0c38ca86e01b9Yassir Elley<li><code>r->pool (apr_pool_t*)</code>: The memory pool of this request. We'll discuss this in the "
60cab26b12df9a2153823972cde0c38ca86e01b9Yassir Elley<a href="#memory">Memory management</a>" chapter.</li>
ff4b603cc14ea6ea15caaf89a03e927920124af4Yassir ElleyA complete list of all the values contained with in the <code>request_req</code> structure can be found in
ff4b603cc14ea6ea15caaf89a03e927920124af4Yassir Elleythe <a href="http://svn.apache.org/repos/asf/httpd/httpd/trunk/include/httpd.h"><code>httpd.h</code></a> header
ff4b603cc14ea6ea15caaf89a03e927920124af4Yassir Elleyfile 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>.
ff4b603cc14ea6ea15caaf89a03e927920124af4Yassir ElleyLet's try out some of these variables in another example handler:<br/>
ff4b603cc14ea6ea15caaf89a03e927920124af4Yassir Elley<!-- BEGIN EXAMPLE CODE -->
ff4b603cc14ea6ea15caaf89a03e927920124af4Yassir Elleystatic int example_handler(request_rec *r)
ff4b603cc14ea6ea15caaf89a03e927920124af4Yassir Elley /* Set the appropriate content type */
74e95cfd9d3939dfe9417d79d2f6fc79b361405fJakub Hrozek /* Print out the IP address of the client connecting to us: */
74e95cfd9d3939dfe9417d79d2f6fc79b361405fJakub Hrozek ap_rprintf(r, "<h2>Hello, %s!</h2>", r->useragent_ip);
74e95cfd9d3939dfe9417d79d2f6fc79b361405fJakub Hrozek /* If we were reached through a GET or a POST request, be happy, else sad. */
31c1f3a2e699fad82258aab83d756e1e7ca923a2Jakub Hrozek if ( !strcmp(r->method, "POST") || !strcmp(r->method, "GET") ) {
31c1f3a2e699fad82258aab83d756e1e7ca923a2Jakub Hrozek ap_rputs("You used a GET or a POST method, that makes us happy!<br/>", r);
593c4a91596640eafe798e8aac700d0f3ce7ba37Ondrej Kos ap_rputs("You did not use POST or GET, that makes us sad :(<br/>", r);
74e95cfd9d3939dfe9417d79d2f6fc79b361405fJakub Hrozek /* Lastly, if there was a query string, let's print that too! */
74e95cfd9d3939dfe9417d79d2f6fc79b361405fJakub Hrozek if (r->args) {
74e95cfd9d3939dfe9417d79d2f6fc79b361405fJakub Hrozek ap_rprintf(r, "Your query string was: %s", r->args);
ad1be6fd04234f61f108773ff39aa7485abda47cJakub Hrozek<!-- END EXAMPLE CODE -->
74e95cfd9d3939dfe9417d79d2f6fc79b361405fJakub Hrozek<section id="return_value"><title>Return values</title>
74e95cfd9d3939dfe9417d79d2f6fc79b361405fJakub HrozekApache relies on return values from handlers to signify whether a request
74e95cfd9d3939dfe9417d79d2f6fc79b361405fJakub Hrozekwas handled or not, and if so, whether the request went well or not. If a
74e95cfd9d3939dfe9417d79d2f6fc79b361405fJakub Hrozekmodule is not interested in handling a specific request, it should always
74e95cfd9d3939dfe9417d79d2f6fc79b361405fJakub Hrozekreturn the value <code>DECLINED</code>. If it is handling a request, it
74e95cfd9d3939dfe9417d79d2f6fc79b361405fJakub Hrozekshould either return the generic value <code>OK</code>, or a specific HTTP
74e95cfd9d3939dfe9417d79d2f6fc79b361405fJakub Hrozekstatus code, for example:
74e95cfd9d3939dfe9417d79d2f6fc79b361405fJakub Hrozek<!-- BEGIN EXAMPLE CODE -->
74e95cfd9d3939dfe9417d79d2f6fc79b361405fJakub Hrozekstatic int example_handler(request_rec *r)
74e95cfd9d3939dfe9417d79d2f6fc79b361405fJakub Hrozek /* Return 404: Not found */
74e95cfd9d3939dfe9417d79d2f6fc79b361405fJakub Hrozek return HTTP_NOT_FOUND;
74e95cfd9d3939dfe9417d79d2f6fc79b361405fJakub Hrozek<!-- END EXAMPLE CODE -->
74e95cfd9d3939dfe9417d79d2f6fc79b361405fJakub HrozekReturning <code>OK</code> or a HTTP status code does not necessarily mean
74e95cfd9d3939dfe9417d79d2f6fc79b361405fJakub Hrozekthat the request will end. The server may still have other handlers that are
74e95cfd9d3939dfe9417d79d2f6fc79b361405fJakub Hrozekinterested in this request, for instance the logging modules which, upon a
65e454c64dbeb4b74e0cc4ad952a54861dc0c3e4Jakub Hrozeksuccessful request, will write down a summary of what was requested and how
74e95cfd9d3939dfe9417d79d2f6fc79b361405fJakub Hrozekit went. To do a full stop and prevent any further processing after your
74e95cfd9d3939dfe9417d79d2f6fc79b361405fJakub Hrozekmodule is done, you can return the value <code>DONE</code> to let the server
74e95cfd9d3939dfe9417d79d2f6fc79b361405fJakub Hrozekknow that it should cease all activity on this request and carry on with
74e95cfd9d3939dfe9417d79d2f6fc79b361405fJakub Hrozekthe next, without informing other handlers.
74e95cfd9d3939dfe9417d79d2f6fc79b361405fJakub Hrozek<li><code>DECLINED</code>: We are not handling this request</li>
74e95cfd9d3939dfe9417d79d2f6fc79b361405fJakub Hrozek<li><code>OK</code>: We handled this request and it went well</li>
74e95cfd9d3939dfe9417d79d2f6fc79b361405fJakub Hrozek<li><code>DONE</code>: We handled this request and the server should just close this thread without further processing</li>
74e95cfd9d3939dfe9417d79d2f6fc79b361405fJakub Hrozek<strong>HTTP specific return codes (excerpt):</strong>
74e95cfd9d3939dfe9417d79d2f6fc79b361405fJakub Hrozek<li><code>HTTP_OK (200)</code>: Request was okay</li>
74e95cfd9d3939dfe9417d79d2f6fc79b361405fJakub Hrozek<li><code>HTTP_MOVED_PERMANENTLY (301)</code>: The resource has moved to a new URL</li>
74e95cfd9d3939dfe9417d79d2f6fc79b361405fJakub Hrozek<li><code>HTTP_UNAUTHORIZED (401)</code>: Client is not authorized to visit this page</li>
74e95cfd9d3939dfe9417d79d2f6fc79b361405fJakub Hrozek<li><code>HTTP_FORBIDDEN (403)</code>: Permission denied</li>
74e95cfd9d3939dfe9417d79d2f6fc79b361405fJakub Hrozek<li><code>HTTP_NOT_FOUND (404)</code>: File not found</li>
74e95cfd9d3939dfe9417d79d2f6fc79b361405fJakub Hrozek<li><code>HTTP_INTERNAL_SERVER_ERROR (500)</code>: Internal server error (self explanatory)</li>
74e95cfd9d3939dfe9417d79d2f6fc79b361405fJakub Hrozek<section id="functions"><title>Some useful functions you should know</title>
74e95cfd9d3939dfe9417d79d2f6fc79b361405fJakub Hrozek <code>ap_rputs(const char *string, request_req *r)</code>: <br/>
74e95cfd9d3939dfe9417d79d2f6fc79b361405fJakub Hrozek Sends a string of text to the client. This is a shorthand version of <a
74e95cfd9d3939dfe9417d79d2f6fc79b361405fJakub Hrozek href="http://ci.apache.org/projects/httpd/trunk/doxygen/group__APACHE__CORE__PROTO.html#gac827cd0537d2b6213a7c06d7c26cc36e">
74e95cfd9d3939dfe9417d79d2f6fc79b361405fJakub Hrozek ap_rwrite</a>.
74e95cfd9d3939dfe9417d79d2f6fc79b361405fJakub Hrozek<!-- BEGIN EXAMPLE CODE -->
74e95cfd9d3939dfe9417d79d2f6fc79b361405fJakub Hrozek<highlight language="c">ap_rputs("Hello, world!", r);</highlight>
74e95cfd9d3939dfe9417d79d2f6fc79b361405fJakub Hrozek<!-- END EXAMPLE CODE -->
74e95cfd9d3939dfe9417d79d2f6fc79b361405fJakub Hrozek <a href="http://ci.apache.org/projects/httpd/trunk/doxygen/group__APACHE__CORE__PROTO.html#ga5e91eb6ca777c9a427b2e82bf1eeb81d">ap_rprintf</a></code>: <br/>
74e95cfd9d3939dfe9417d79d2f6fc79b361405fJakub Hrozek This function works just like <code>printf</code>, except it sends the result to the client.
591b0325f5d6f70ae71e61a8c563b437acfb1884Jakub Hrozek<!-- BEGIN EXAMPLE CODE -->
ae0a5011e2644eaa482ea1b9e1451eff05c676b9Lukas Slebodnik<highlight language="c">ap_rprintf(r, "Hello, %s!", r->useragent_ip);</highlight>
edaa983d094c239c3e1ba667bcd20ed3934be3b8Sumit Bose<!-- END EXAMPLE CODE -->
edaa983d094c239c3e1ba667bcd20ed3934be3b8Sumit Bose <a href="http://ci.apache.org/projects/httpd/trunk/doxygen/group__APACHE__CORE__PROTO.html#gaa2f8412c400197338ec509f4a45e4579">ap_set_content_type</a>(request_req *r, const char *type)</code>: <br/>
edaa983d094c239c3e1ba667bcd20ed3934be3b8Sumit Bose Sets the content type of the output you are sending.
edaa983d094c239c3e1ba667bcd20ed3934be3b8Sumit Bose<!-- BEGIN EXAMPLE CODE -->
edaa983d094c239c3e1ba667bcd20ed3934be3b8Sumit Bose<highlight language="c">ap_set_content_type(r, "text/plain"); /* force a raw text output */</highlight>
edaa983d094c239c3e1ba667bcd20ed3934be3b8Sumit Bose<!-- END EXAMPLE CODE -->
03532fb1cbb7e8c1d5cf2e93aa3719f926631cabStephen Gallagher<section id="memory"><title>Memory management</title>
03532fb1cbb7e8c1d5cf2e93aa3719f926631cabStephen GallagherManaging your resources in Apache HTTP Server 2.4 is quite easy, thanks to the memory pool
03532fb1cbb7e8c1d5cf2e93aa3719f926631cabStephen Gallaghersystem. In essence, each server, connection and request have their own
03532fb1cbb7e8c1d5cf2e93aa3719f926631cabStephen Gallaghermemory pool that gets cleaned up when its scope ends, e.g. when a request
03532fb1cbb7e8c1d5cf2e93aa3719f926631cabStephen Gallagheris done or when a server process shuts down. All your module needs to do is
03532fb1cbb7e8c1d5cf2e93aa3719f926631cabStephen Gallagherlatch onto this memory pool, and you won't have to worry about having to
03532fb1cbb7e8c1d5cf2e93aa3719f926631cabStephen Gallagherclean up after yourself - pretty neat, huh?
03532fb1cbb7e8c1d5cf2e93aa3719f926631cabStephen GallagherIn our module, we will primarily be allocating memory for each request, so
03532fb1cbb7e8c1d5cf2e93aa3719f926631cabStephen Gallagherit's appropriate to use the <code>r->pool</code>
03532fb1cbb7e8c1d5cf2e93aa3719f926631cabStephen Gallagherreference when creating new objects. A few of the functions for allocating
03532fb1cbb7e8c1d5cf2e93aa3719f926631cabStephen Gallaghermemory within a pool are:
03532fb1cbb7e8c1d5cf2e93aa3719f926631cabStephen Gallagher<li><code>void* <a href="http://apr.apache.org/docs/apr/1.4/group__apr__pools.html#ga85f1e193c31d109affda72f9a92c6915">apr_palloc</a>(
03532fb1cbb7e8c1d5cf2e93aa3719f926631cabStephen Gallagherapr_pool_t *p, apr_size_t size)</code>: Allocates <code>size</code> number of bytes in the pool for you</li>
03532fb1cbb7e8c1d5cf2e93aa3719f926631cabStephen Gallagher<li><code>void* <a href="http://apr.apache.org/docs/apr/1.4/group__apr__pools.html#gaf61c098ad258069d64cdf8c0a9369f9e">apr_pcalloc</a>(
03532fb1cbb7e8c1d5cf2e93aa3719f926631cabStephen Gallagherapr_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>
03532fb1cbb7e8c1d5cf2e93aa3719f926631cabStephen Gallagher<li><code>char* <a href="http://apr.apache.org/docs/apr/1.4/group__apr__strings.html#gabc79e99ff19abbd7cfd18308c5f85d47">apr_pstrdup</a>(
03532fb1cbb7e8c1d5cf2e93aa3719f926631cabStephen Gallagherapr_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>
03532fb1cbb7e8c1d5cf2e93aa3719f926631cabStephen Gallagher<li><code>char* <a href="http://apr.apache.org/docs/apr/1.4/group__apr__strings.html#ga3eca76b8d293c5c3f8021e45eda813d8">apr_psprintf</a>(
03532fb1cbb7e8c1d5cf2e93aa3719f926631cabStephen Gallagherapr_pool_t *p, const char *fmt, ...)</code>: Similar to <code>sprintf</code>, except the server supplies you with an appropriately allocated target variable</li>
03532fb1cbb7e8c1d5cf2e93aa3719f926631cabStephen Gallagher<p>Let's put these functions into an example handler:</p>
d231e95b0a5e1bd377f67e041e8b502a79fdc605Jakub Hrozek<!-- BEGIN EXAMPLE CODE -->
d231e95b0a5e1bd377f67e041e8b502a79fdc605Jakub Hrozekstatic int example_handler(request_rec *r)
d231e95b0a5e1bd377f67e041e8b502a79fdc605Jakub Hrozek const char* original = "You can't edit this!";
d231e95b0a5e1bd377f67e041e8b502a79fdc605Jakub Hrozek int* integers;
d231e95b0a5e1bd377f67e041e8b502a79fdc605Jakub Hrozek /* Allocate space for 10 integer values and set them all to zero. */
d231e95b0a5e1bd377f67e041e8b502a79fdc605Jakub Hrozek integers = apr_pcalloc(r->pool, sizeof(int)*10);
d231e95b0a5e1bd377f67e041e8b502a79fdc605Jakub Hrozek /* Create a copy of the 'original' variable that we can edit. */
d231e95b0a5e1bd377f67e041e8b502a79fdc605Jakub Hrozek copy = apr_pstrdup(r->pool, original);
8cc00c355862f5573f884efe828aa4c0f855376aJakub Hrozek<!-- END EXAMPLE CODE -->
b3f56d9e4bd065590383eb1f812a3b77e3c56f24Jakub HrozekThis is all well and good for our module, which won't need any
b3f56d9e4bd065590383eb1f812a3b77e3c56f24Jakub Hrozekpre-initialized variables or structures. However, if we wanted to
b3f56d9e4bd065590383eb1f812a3b77e3c56f24Jakub Hrozekinitialize something early on, before the requests come rolling in, we
8cc00c355862f5573f884efe828aa4c0f855376aJakub Hrozekcould simply add a call to a function in our <code>register_hooks</code>
03532fb1cbb7e8c1d5cf2e93aa3719f926631cabStephen Gallagherfunction to sort it out:
03532fb1cbb7e8c1d5cf2e93aa3719f926631cabStephen Gallagher<!-- BEGIN EXAMPLE CODE -->
03532fb1cbb7e8c1d5cf2e93aa3719f926631cabStephen Gallagherstatic void register_hooks(apr_pool_t *pool)
<a href="http://ci.apache.org/projects/httpd/trunk/doxygen/group__apr__tables.html#gad7ea82d6608a4a633fc3775694ab71e4">apr_table_t</a> *GET;
<a href="http://ci.apache.org/projects/httpd/trunk/doxygen/structapr__array__header__t.html">apr_array_header_t</a> *POST;
<a href="http://ci.apache.org/projects/httpd/trunk/doxygen/group__APACHE__CORE__SCRIPT.html#gaed25877b529623a4d8f99f819ba1b7bd">ap_args_to_table</a>(r, &GET);
<a href="http://ci.apache.org/projects/httpd/trunk/doxygen/group__APACHE__CORE__DAEMON.html#ga9d426b6382b49754d4f87c55f65af202">ap_parse_form_data</a>(r, NULL, &POST, -1, 8192);
(finfo.filetype != APR_NOFILE)
&& !(finfo.filetype & APR_DIR)
ap_rprintf(r, "<b>Size:</b> %u bytes<br/>", finfo.size);
apr_md5_final(digest.chr, &md5);
ap_rprintf(r, "%08x", digest.num[n]);
ap_rputs("<br/><a href='?digest=sha1'>View the SHA1 hash instead</a>", r);
apr_sha1_final(digest.chr, &sha1);
ap_rprintf(r, "%08x", digest.num[n]);
ap_rputs("<br/><a href='?digest=md5'>View the MD5 hash instead</a>", r);
const char *path; /* Some path to...something */
const char *path; /* Some path to...something */
ap_rprintf(r, "Enabled: %u\n", config.enabled);
ap_rprintf(r, "Path: %s\n", config.path);
ap_rprintf(r, "TypeOfAction: %x\n", config.typeOfAction);
config.enabled = 1;
config.typeOfAction = 0x00;
into the module, but by using either the httpd.conf file or possibly a
AP_INIT_TAKE1("exampleEnabled", example_set_enabled, NULL, RSRC_CONF, "Enable or disable mod_example"),
<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.
If 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
<li><code>exampleEnabled</code>: This is the name of our directive. More precisely, it is what the user must put in his/her
<li><code>example_set_enabled</code>: This is a reference to a C function that parses the directive and sets the configuration
<li><code>RSRC_CONF</code>: This tells the server where the directive is permitted. We'll go into details on this value in the
later chapters, but for now, <code>RSRC_CONF</code> means that the server will only accept these directives in a server context.</li>
<li><code>"Enable or disable...."</code>: This is simply a brief description of what the directive does.</li>
if(!strcasecmp(arg, "on")) config.enabled = 1;
else config.enabled = 0;
config.path = arg;
if(!strcasecmp(arg1, "file")) config.typeOfAction = 0x01;
else config.typeOfAction = 0x02;
if(!strcasecmp(arg2, "deny")) config.typeOfAction += 0x10;
else config.typeOfAction += 0x20;
/* mod_example_config_simple.c: */
#include <stdio.h>
#include "apr_hash.h"
#include "ap_config.h"
#include "ap_provider.h"
#include "httpd.h"
#include "http_core.h"
#include "http_config.h"
#include "http_log.h"
#include "http_protocol.h"
#include "http_request.h"
const char *path; /* Some path to...something */
if(!strcasecmp(arg, "on")) config.enabled = 1;
else config.enabled = 0;
config.path = arg;
if(!strcasecmp(arg1, "file")) config.typeOfAction = 0x01;
else config.typeOfAction = 0x02;
if(!strcasecmp(arg2, "deny")) config.typeOfAction += 0x10;
else config.typeOfAction += 0x20;
AP_INIT_TAKE1("exampleEnabled", example_set_enabled, NULL, RSRC_CONF, "Enable or disable mod_example"),
AP_INIT_TAKE1("examplePath", example_set_path, NULL, RSRC_CONF, "The path to whatever"),
AP_INIT_TAKE2("exampleAction", example_set_action, NULL, RSRC_CONF, "Special action value!"),
ap_rprintf(r, "Enabled: %u\n", config.enabled);
ap_rprintf(r, "Path: %s\n", config.path);
ap_rprintf(r, "TypeOfAction: %x\n", config.typeOfAction);
config.enabled = 1;
config.typeOfAction = 3;
In our httpd.conf file, we can now change the hard-coded configuration by
RewriteCond %{HTTP_HOST} ^example.com$
RewriteRule (.*) http://www.example.com/$1
RewriteRule ^foobar$ index.php?foobar=true
<li>Inside <code>/var/www</code>, all requests for <code>http://example.com</code> must go to <code>http://www.example.com</code></li>
<li>Inside <code>/var/www/sub</code>, all requests for <code>foobar</code> must go to <code>index.php?foobar=true</code></li>
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);
example_config *config = (example_config*) ap_get_module_config(r->per_dir_config, &example_module);
AP_INIT_TAKE1("exampleEnabled", example_set_enabled, NULL, RSRC_CONF, "Enable or disable mod_example"),
<li>Sets the configuration values according to the directives given for <code>/var/www/subdir</code></li>
<li><strong>Proposes a merge</strong> of the two configurations into a new configuration for <code>/var/www/subdir</code></li>
+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
#include <stdio.h>
#include "apr_hash.h"
#include "ap_config.h"
#include "ap_provider.h"
#include "httpd.h"
#include "http_core.h"
#include "http_config.h"
#include "http_log.h"
#include "http_protocol.h"
#include "http_request.h"
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
AP_INIT_TAKE1("exampleEnabled", example_set_enabled, NULL, ACCESS_CONF, "Enable or disable mod_example"),
AP_INIT_TAKE1("examplePath", example_set_path, NULL, ACCESS_CONF, "The path to whatever"),
AP_INIT_TAKE2("exampleAction", example_set_action, NULL, ACCESS_CONF, "Special action value!"),
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
=======================================================================================================================
=======================================================================================================================
=======================================================================================================================
=======================================================================================================================
/*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
example_config *config = (example_config *) ap_get_module_config(r->per_dir_config, &example_module);
/*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
=======================================================================================================================
=======================================================================================================================
=======================================================================================================================
=======================================================================================================================
=======================================================================================================================
=======================================================================================================================
=======================================================================================================================
=======================================================================================================================
=======================================================================================================================