modguide.xml revision d29d9ab4614ff992b0e8de6e2b88d52b6f1f153e
97a9a944b5887e91042b019776c41d5dd74557aferikabele<!DOCTYPE manualpage SYSTEM "/style/manualpage.dtd">
97a9a944b5887e91042b019776c41d5dd74557aferikabele<?xml-stylesheet type="text/xsl" href="/style/manual.en.xsl"?>
a945f35eff8b6a88009ce73de6d4c862ce58de3cslive<!-- $LastChangedRevision$ -->
b686b6a420bde7f78c416b90be11db94cb789979nd Licensed to the Apache Software Foundation (ASF) under one or more
b686b6a420bde7f78c416b90be11db94cb789979nd contributor license agreements. See the NOTICE file distributed with
b686b6a420bde7f78c416b90be11db94cb789979nd this work for additional information regarding copyright ownership.
b686b6a420bde7f78c416b90be11db94cb789979nd The ASF licenses this file to You under the Apache License, Version 2.0
b686b6a420bde7f78c416b90be11db94cb789979nd (the "License"); you may not use this file except in compliance with
b686b6a420bde7f78c416b90be11db94cb789979nd the License. You may obtain a copy of the License at
b686b6a420bde7f78c416b90be11db94cb789979nd Unless required by applicable law or agreed to in writing, software
b686b6a420bde7f78c416b90be11db94cb789979nd distributed under the License is distributed on an "AS IS" BASIS,
4b5981e276e93df97c34e4da05ca5cf8bbd937dand WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
3b3b7fc78d1f5bfc2769903375050048ff41ff26nd See the License for the specific language governing permissions and
ad74a0524a06bfe11b7de9e3b4ce7233ab3bd3f7nd limitations under the License.
3b3b7fc78d1f5bfc2769903375050048ff41ff26nd <title>Developing modules for the Apache HTTP Server 2.4</title>
06ba4a61654b3763ad65f52283832ebf058fdf1cslive<p>This document explains how you can develop modules for the Apache HTTP
06ba4a61654b3763ad65f52283832ebf058fdf1csliveServer 2.4</p>
06ba4a61654b3763ad65f52283832ebf058fdf1cslive<seealso><a href="request.html">Request Processing in Apache 2.4</a></seealso>
80d3dc69b0e6ad772135f6a78af3d16bd6cccc42nd<seealso><a href="hooks.html">Apache 2.x Hook Functions</a></seealso>
5b10fd3977e6dfff19afe770e612e276962f7950nd<section id="what"><title>What we will be discussing in this document</title>
a63f0ab647ad2ab72efc9bea7a66e24e9ebc5cc2ndThis document will discuss how you can easily create modules for the Apache
a63f0ab647ad2ab72efc9bea7a66e24e9ebc5cc2ndHTTP Server 2.4, by exploring an example module called
a63f0ab647ad2ab72efc9bea7a66e24e9ebc5cc2nd<code>mod_example</code>. In the first part of this document, the purpose
a63f0ab647ad2ab72efc9bea7a66e24e9ebc5cc2ndof this module will be to calculate and print out various digest values for
a63f0ab647ad2ab72efc9bea7a66e24e9ebc5cc2ndexisting files on your web server, whenever we access the URL <code>
80d3dc69b0e6ad772135f6a78af3d16bd6cccc42ndhttp://hostname/filename.sum</code>. For instance, if we want to know the
5b10fd3977e6dfff19afe770e612e276962f7950ndMD5 digest value of the file located at <code>
5b10fd3977e6dfff19afe770e612e276962f7950ndhttp://www.example.com/index.html</code>, we would visit <code>
2aff288113d772cedca6add888eb643afffe9fb1ndIn the second part of this document, which deals with configuration
a63f0ab647ad2ab72efc9bea7a66e24e9ebc5cc2nddirective and context awareness, we will be looking at a module that simply
7fa75a06a4fee19e995c069ee00310455d1452e1pquernawrite out its own configuration to the client.
a63f0ab647ad2ab72efc9bea7a66e24e9ebc5cc2ndFirst and foremost, you are expected to have a basic knowledge of how the C
a63f0ab647ad2ab72efc9bea7a66e24e9ebc5cc2ndprogramming language works. In most cases, we will try to be as pedagogical
a63f0ab647ad2ab72efc9bea7a66e24e9ebc5cc2ndas possible and link to documents describing the functions used in the
2aff288113d772cedca6add888eb643afffe9fb1ndexamples, but there are also many cases where it is necessary to either
a63f0ab647ad2ab72efc9bea7a66e24e9ebc5cc2ndjust assume that "it works" or do some digging yourself into what the hows
a63f0ab647ad2ab72efc9bea7a66e24e9ebc5cc2ndand whys of various function calls.
2aff288113d772cedca6add888eb643afffe9fb1ndLastly, you will need to have a basic understanding of how modules are
2aff288113d772cedca6add888eb643afffe9fb1ndloaded and configured in the Apache HTTP Server, as well as how to get the headers for
80d3dc69b0e6ad772135f6a78af3d16bd6cccc42ndApache if you do not have them already, as these are needed for compiling
80d3dc69b0e6ad772135f6a78af3d16bd6cccc42ndnew modules.
7ec4d5cc4aa574e3191bc5a612e68fd8f25ab7earpluem<section id="compiling"><title>Compiling your module</title>
7ec4d5cc4aa574e3191bc5a612e68fd8f25ab7earpluemTo compile the source code we are building in this document, we will be
2aff288113d772cedca6add888eb643afffe9fb1ndusing <a href="/programs/apxs.html">APXS</a>. Assuming your source file
2aff288113d772cedca6add888eb643afffe9fb1ndis called mod_example.c, compiling, installing and activating the module is
2aff288113d772cedca6add888eb643afffe9fb1ndas simple as:
2aff288113d772cedca6add888eb643afffe9fb1ndapxs -i -a -c mod_example.c
aa0b2780958e9b1467c9d0153a05738e399811a5nd<img src="/images/build_a_mod_3.png" alt="Module name tags"/><br/>
2aff288113d772cedca6add888eb643afffe9fb1ndEvery module starts with the same declaration, or name tag if you will,
42af92a661a06b3cebc88d585aad75064a309d51ndthat defines a module as <em>a separate entity within Apache</em>:</p>
6fe26506780e73be2a412d758af77fafdf03291and<!-- BEGIN EXAMPLE CODE -->
aa0b2780958e9b1467c9d0153a05738e399811a5ndmodule AP_MODULE_DECLARE_DATA example_module =
2aff288113d772cedca6add888eb643afffe9fb1nd STANDARD20_MODULE_STUFF,
2aff288113d772cedca6add888eb643afffe9fb1nd create_dir_conf, /* Per-directory configuration handler */
64c02f1310b7747423957823ee09fb3608430f89nd merge_dir_conf, /* Merge handler for per-directory configurations */
aa0b2780958e9b1467c9d0153a05738e399811a5nd create_svr_conf, /* Per-server configuration handler */
2aff288113d772cedca6add888eb643afffe9fb1nd merge_svr_conf, /* Merge handler for per-server configurations */
2aff288113d772cedca6add888eb643afffe9fb1nd directives, /* Any directives we may have for httpd */
2aff288113d772cedca6add888eb643afffe9fb1nd register_hooks /* Our hook registering function */
2aff288113d772cedca6add888eb643afffe9fb1nd</highlight>
2aff288113d772cedca6add888eb643afffe9fb1nd<!-- END EXAMPLE CODE -->
2aff288113d772cedca6add888eb643afffe9fb1ndThis bit of code lets the server know that we have now registered a new module
80d3dc69b0e6ad772135f6a78af3d16bd6cccc42ndin the system, and that its name is <code>example_module</code>. The name
2aff288113d772cedca6add888eb643afffe9fb1ndof the module is used primarily for two things:<br/>
e8b603fa9ccf7b17b11b42df6d8916fd97c2331dnd<li>Letting the server know how to load the module using the LoadModule</li>
bf94bedcb62d7f0b926f4286069def5ee6b07b60nd<li>Setting up a namespace for the module to use in configurations</li>
2aff288113d772cedca6add888eb643afffe9fb1ndFor now, we're only concerned with the first purpose of the module name,
bbcbf978a3074512c627c797fedcb30eeab7b39dslivewhich comes into play when we need to load the module:
80d3dc69b0e6ad772135f6a78af3d16bd6cccc42nd<example><pre><a href="/mod/mod_so.html#LoadModule">LoadModule</a> example_module modules/mod_example.so</pre></example>
e55e60efce8a3e2139132c1d6ad9f6f0d2976614ndIn essence, this tells the server to open up <code>mod_example.so</code> and look for a module
7f3fdc63be07f2ad39e01a44e68e9324998a5c03sliveWithin this name tag of ours is also a bunch of references to how we would
7f3fdc63be07f2ad39e01a44e68e9324998a5c03slivelike to handle things: Which directives do we respond to in a configuration
75585bd48fe0f30483dba4762e61edf39ea3e0f6ndfile or .htaccess, how do we operate within specific contexts, and what
75585bd48fe0f30483dba4762e61edf39ea3e0f6ndhandlers are we interested in registering with the Apache HTTP service. We'll
80d3dc69b0e6ad772135f6a78af3d16bd6cccc42ndreturn to all these elements later in this document.
3b58542e01ec69422f3086db5825a12fc77b726end<section id="hooking"><title>Getting started: Hooking into the server</title>
a0d937b340692a3578f1d2f2535890c520c4bf0cnd<section id="hook_intro"><title>An introduction to hooks</title>
2aff288113d772cedca6add888eb643afffe9fb1ndWhen handling requests in Apache HTTP Server 2.4, the first thing you will need to do is
2aff288113d772cedca6add888eb643afffe9fb1ndcreate a hook into the request handling process. A hook is essentially a
2aff288113d772cedca6add888eb643afffe9fb1ndmessage telling the server that you are willing to either serve or at least
2aff288113d772cedca6add888eb643afffe9fb1ndtake a glance at certain requests given by clients. All handlers, whether
80d3dc69b0e6ad772135f6a78af3d16bd6cccc42ndit's mod_rewrite, mod_authn_*, mod_proxy and so on, are hooked into
08842292d2f1550b40ae73e0dafc7641c5955c82ndspecific parts of the request process. As you are probably aware, modules
2aff288113d772cedca6add888eb643afffe9fb1ndserve different purposes; Some are authentication/authorization handlers,
d2b809e5d72658bff23819d8b77f20e4939af541ndothers are file or script handlers while some third modules rewrite URIs or
2aff288113d772cedca6add888eb643afffe9fb1ndproxies content. Furthermore, in the end, it is up to the user of the server
80d3dc69b0e6ad772135f6a78af3d16bd6cccc42ndhow and when each module will come into place. Thus, the server itself does not
2aff288113d772cedca6add888eb643afffe9fb1ndpresume to know which module is responsible for handling a specific
2aff288113d772cedca6add888eb643afffe9fb1ndrequest, and will ask each module whether they have an interest in a given
2aff288113d772cedca6add888eb643afffe9fb1ndrequest or not. It is then up to each module to either gently decline
2aff288113d772cedca6add888eb643afffe9fb1ndserving a request, accept serving it or flat out deny the request from
2aff288113d772cedca6add888eb643afffe9fb1ndbeing served, as authentication/authorization modules do: <br/>
2aff288113d772cedca6add888eb643afffe9fb1nd<img src="/images/build_a_mod_2.png" alt="Hook handling in httpd"/><br/>
80d3dc69b0e6ad772135f6a78af3d16bd6cccc42ndTo make it a bit easier for handlers such as our mod_example to know
c023f60e35022146373e40249f0c8c8d623b6fcfndwhether the client is requesting content we should handle or not, the server
80d3dc69b0e6ad772135f6a78af3d16bd6cccc42ndhas directives for hinting to modules whether their assistance is needed or
a43bfa789f4e52dde53ae8e53fa0427b5c1cf977ndnot. Two of these are <directive module="mod_mime">AddHandler</directive>
a43bfa789f4e52dde53ae8e53fa0427b5c1cf977ndand <directive module="core">SetHandler</directive>. Let's take a look at
101bf3584c853027d9e51df6edfff5ff70c80238jiman example using <directive module="mod_mime">AddHandler</directive>. In
73ba54c33b4fcad0e13005e10ea8648c9fe4265bndour example case, we want every request ending with .sum to be served by
73ba54c33b4fcad0e13005e10ea8648c9fe4265bnd<code>mod_example</code>, so we'll add a configuration directive that tells
73ba54c33b4fcad0e13005e10ea8648c9fe4265bndthe server to do just that:
73ba54c33b4fcad0e13005e10ea8648c9fe4265bndAddHandler example-handler .sum
80d3dc69b0e6ad772135f6a78af3d16bd6cccc42ndWhat this tells the server is the following: <em>Whenever we receive a request
2aff288113d772cedca6add888eb643afffe9fb1ndfor a URI ending in .sum, we are to let all modules know that we are
2aff288113d772cedca6add888eb643afffe9fb1ndlooking for whoever goes by the name of "example-handler" </em>.
2aff288113d772cedca6add888eb643afffe9fb1ndThus, when a request is being served that ends in .sum, the server will let all
2aff288113d772cedca6add888eb643afffe9fb1ndmodules know, that this request should be served by "example-handler
2aff288113d772cedca6add888eb643afffe9fb1nd". As you will see later, when we start building mod_example, we will
2aff288113d772cedca6add888eb643afffe9fb1ndcheck for this handler tag relayed by <code>AddHandler</code> and reply to
2aff288113d772cedca6add888eb643afffe9fb1ndthe server based on the value of this tag.
2aff288113d772cedca6add888eb643afffe9fb1nd<section id="hook_declaration"><title>Hooking into httpd</title>
2aff288113d772cedca6add888eb643afffe9fb1ndTo begin with, we only want to create a simple handler, that replies to the
2aff288113d772cedca6add888eb643afffe9fb1ndclient browser when a specific URL is requested, so we won't bother setting
80d3dc69b0e6ad772135f6a78af3d16bd6cccc42ndup configuration handlers and directives just yet. Our initial module
2aff288113d772cedca6add888eb643afffe9fb1nddefinition will look like this:</p>
2aff288113d772cedca6add888eb643afffe9fb1nd<!-- BEGIN EXAMPLE CODE -->
03c25fb6f628ac81f2ecb637d1e7502dcee783f3ndmodule AP_MODULE_DECLARE_DATA example_module =
2aff288113d772cedca6add888eb643afffe9fb1nd STANDARD20_MODULE_STUFF,
7f5b59ccc63c0c0e3e678a168f09ee6a2f51f9d0nd register_hooks /* Our hook registering function */
63f06dce77bb2d9b1c5aa5deeb47a1069987fd1end</highlight>
3b3b7fc78d1f5bfc2769903375050048ff41ff26nd<!-- END EXAMPLE CODE -->
80d3dc69b0e6ad772135f6a78af3d16bd6cccc42nd<p>This lets the server know that we are not interesting in anything fancy, we
<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>
<li><code>ap_hook_pre_config</code>: Place a hook that executes before any configuration data has been read (very early hook)</li>
<li><code>ap_hook_post_config</code>: Place a hook that executes after configuration has been parsed, but before the server has forked</li>
<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>
<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>
<li><code>r->filename (char*):</code> Contains the translated filename the client is requesting</li>
<li><code>r->connection (conn_rec*):</code> A record containing information about the current connection</li>
<li><code>r->pool (apr_pool_t*)</code>: The memory pool of this request. We'll discuss this in the "
A complete list of all the values contained with in the <code>request_req</code> structure can be found in
the <a href="http://svn.apache.org/repos/asf/httpd/httpd/trunk/include/httpd.h"><code>httpd.h</code></a> header
file 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>.
<li><code>DONE</code>: We handled this request and the server should just close this thread without further processing</li>
href="http://ci.apache.org/projects/httpd/trunk/doxygen/group__APACHE__CORE__PROTO.html#gac827cd0537d2b6213a7c06d7c26cc36e">
<a href="http://ci.apache.org/projects/httpd/trunk/doxygen/group__APACHE__CORE__PROTO.html#ga5e91eb6ca777c9a427b2e82bf1eeb81d">ap_rprintf</a></code>: <br/>
<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/>
<highlight language="c">ap_set_content_type(r, "text/plain"); /* force a raw text output */</highlight>
memory pool that gets cleaned up when its scope ends, e.g. when a request
<li><code>void* <a href="http://apr.apache.org/docs/apr/1.4/group__apr__pools.html#ga85f1e193c31d109affda72f9a92c6915">apr_palloc</a>(
apr_pool_t *p, apr_size_t size)</code>: Allocates <code>size</code> number of bytes in the pool for you</li>
<li><code>void* <a href="http://apr.apache.org/docs/apr/1.4/group__apr__pools.html#gaf61c098ad258069d64cdf8c0a9369f9e">apr_pcalloc</a>(
apr_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>
<li><code>char* <a href="http://apr.apache.org/docs/apr/1.4/group__apr__strings.html#gabc79e99ff19abbd7cfd18308c5f85d47">apr_pstrdup</a>(
apr_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>
<li><code>char* <a href="http://apr.apache.org/docs/apr/1.4/group__apr__strings.html#ga3eca76b8d293c5c3f8021e45eda813d8">apr_psprintf</a>(
apr_pool_t *p, const char *fmt, ...)</code>: Similar to <code>sprintf</code>, except the server supplies you with an appropriately allocated target variable</li>
<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);
/*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
=======================================================================================================================
=======================================================================================================================
=======================================================================================================================
=======================================================================================================================
=======================================================================================================================
=======================================================================================================================
=======================================================================================================================
=======================================================================================================================
=======================================================================================================================