modguide.xml revision 57e8d28eb19a247139c0bd494a3be57dbac7ceed
97a9a944b5887e91042b019776c41d5dd74557aferikabele<!DOCTYPE manualpage SYSTEM "/style/manualpage.dtd">
97a9a944b5887e91042b019776c41d5dd74557aferikabele<?xml-stylesheet type="text/xsl" href="/style/manual.en.xsl"?>
b1ced323143ade589985456a78f3f64d6a6580c5yoshiki<!-- $LastChangedRevision$ -->
0c4abc32c00611fe1d52c9661f5cc79a3f74c6d4nd Licensed to the Apache Software Foundation (ASF) under one or more
0c4abc32c00611fe1d52c9661f5cc79a3f74c6d4nd contributor license agreements. See the NOTICE file distributed with
0c4abc32c00611fe1d52c9661f5cc79a3f74c6d4nd this work for additional information regarding copyright ownership.
0c4abc32c00611fe1d52c9661f5cc79a3f74c6d4nd The ASF licenses this file to You under the Apache License, Version 2.0
0c4abc32c00611fe1d52c9661f5cc79a3f74c6d4nd (the "License"); you may not use this file except in compliance with
0c4abc32c00611fe1d52c9661f5cc79a3f74c6d4nd the License. You may obtain a copy of the License at
0c4abc32c00611fe1d52c9661f5cc79a3f74c6d4nd Unless required by applicable law or agreed to in writing, software
0c4abc32c00611fe1d52c9661f5cc79a3f74c6d4nd distributed under the License is distributed on an "AS IS" BASIS,
0c4abc32c00611fe1d52c9661f5cc79a3f74c6d4nd WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
4b5981e276e93df97c34e4da05ca5cf8bbd937dand See the License for the specific language governing permissions and
0c4abc32c00611fe1d52c9661f5cc79a3f74c6d4nd limitations under the License.
0c4abc32c00611fe1d52c9661f5cc79a3f74c6d4nd <title>Developing modules for the Apache HTTP Server 2.4</title>
0c4abc32c00611fe1d52c9661f5cc79a3f74c6d4nd<p>This document explains how you can develop modules for the Apache HTTP
cea021a7fc2657b091df4d3b031c4254ec371dd7rbowenServer 2.4</p>
f6445f3ad1c82f9398dc8edd77093cd3e20b806cnoirin<seealso><a href="request.html">Request Processing in Apache 2.4</a></seealso>
f6445f3ad1c82f9398dc8edd77093cd3e20b806cnoirin<seealso><a href="hooks.html">Apache 2.x Hook Functions</a></seealso>
f6445f3ad1c82f9398dc8edd77093cd3e20b806cnoirin<section id="introduction"><title>Introduction</title>
f6445f3ad1c82f9398dc8edd77093cd3e20b806cnoirin<section id="what"><title>What we will be discussing in this document</title>
f6445f3ad1c82f9398dc8edd77093cd3e20b806cnoirinThis document will discuss how you can create modules for the Apache
f6445f3ad1c82f9398dc8edd77093cd3e20b806cnoirinHTTP Server 2.4, by exploring an example module called
f6445f3ad1c82f9398dc8edd77093cd3e20b806cnoirin<code>mod_example</code>. In the first part of this document, the purpose
f6445f3ad1c82f9398dc8edd77093cd3e20b806cnoirinof this module will be to calculate and print out various digest values for
f6445f3ad1c82f9398dc8edd77093cd3e20b806cnoirinexisting files on your web server, whenever we access the URL <code>
f6445f3ad1c82f9398dc8edd77093cd3e20b806cnoirinhttp://hostname/filename.sum</code>. For instance, if we want to know the
f6445f3ad1c82f9398dc8edd77093cd3e20b806cnoirinMD5 digest value of the file located at <code>
f6445f3ad1c82f9398dc8edd77093cd3e20b806cnoirinhttp://www.example.com/index.html</code>, we would visit <code>
f0a393c5c2d7de58f447855369ad2fbfa254e544rbowenIn the second part of this document, which deals with configuration
0c4abc32c00611fe1d52c9661f5cc79a3f74c6d4nddirective and context awareness, we will be looking at a module that simply
0c4abc32c00611fe1d52c9661f5cc79a3f74c6d4ndwrites out its own configuration to the client.
117c1f888a14e73cdd821dc6c23eb0411144a41cndFirst and foremost, you are expected to have a basic knowledge of how the C
117c1f888a14e73cdd821dc6c23eb0411144a41cndprogramming language works. In most cases, we will try to be as pedagogical
0c4abc32c00611fe1d52c9661f5cc79a3f74c6d4ndas possible and link to documents describing the functions used in the
b41a0dbe6310c576e96b7ea6910051fd84fb06f5sfexamples, but there are also many cases where it is necessary to either
b41a0dbe6310c576e96b7ea6910051fd84fb06f5sfjust assume that "it works" or do some digging yourself into what the hows
7571ea383299910bead3e93e66246cb212a28d0figalicand whys of various function calls.
b41a0dbe6310c576e96b7ea6910051fd84fb06f5sfLastly, you will need to have a basic understanding of how modules are
7571ea383299910bead3e93e66246cb212a28d0figalicloaded and configured in the Apache HTTP Server, as well as how to get the headers for
b41a0dbe6310c576e96b7ea6910051fd84fb06f5sfApache if you do not have them already, as these are needed for compiling
b41a0dbe6310c576e96b7ea6910051fd84fb06f5sfnew modules.
b41a0dbe6310c576e96b7ea6910051fd84fb06f5sf<section id="compiling"><title>Compiling your module</title>
b41a0dbe6310c576e96b7ea6910051fd84fb06f5sfTo compile the source code we are building in this document, we will be
b41a0dbe6310c576e96b7ea6910051fd84fb06f5sfusing <a href="/programs/apxs.html">APXS</a>. Assuming your source file
b41a0dbe6310c576e96b7ea6910051fd84fb06f5sfis called mod_example.c, compiling, installing and activating the module is
b41a0dbe6310c576e96b7ea6910051fd84fb06f5sfas simple as:
b41a0dbe6310c576e96b7ea6910051fd84fb06f5sfapxs -i -a -c mod_example.c
9b3696c7ad70387ecd46e0f061b99d381dc392f9rbowen<img src="/images/build_a_mod_3.png" alt="Module name tags"/><br/>
9b3696c7ad70387ecd46e0f061b99d381dc392f9rbowenEvery module starts with the same declaration, or name tag if you will,
9b3696c7ad70387ecd46e0f061b99d381dc392f9rbowenthat defines a module as <em>a separate entity within Apache</em>:</p>
9b3696c7ad70387ecd46e0f061b99d381dc392f9rbowen<!-- BEGIN EXAMPLE CODE -->
9b3696c7ad70387ecd46e0f061b99d381dc392f9rbowenmodule AP_MODULE_DECLARE_DATA example_module =
9b3696c7ad70387ecd46e0f061b99d381dc392f9rbowen STANDARD20_MODULE_STUFF,
9b3696c7ad70387ecd46e0f061b99d381dc392f9rbowen create_dir_conf, /* Per-directory configuration handler */
9b3696c7ad70387ecd46e0f061b99d381dc392f9rbowen merge_dir_conf, /* Merge handler for per-directory configurations */
9b3696c7ad70387ecd46e0f061b99d381dc392f9rbowen create_svr_conf, /* Per-server configuration handler */
b41a0dbe6310c576e96b7ea6910051fd84fb06f5sf merge_svr_conf, /* Merge handler for per-server configurations */
0c4abc32c00611fe1d52c9661f5cc79a3f74c6d4nd directives, /* Any directives we may have for httpd */
0c4abc32c00611fe1d52c9661f5cc79a3f74c6d4nd register_hooks /* Our hook registering function */
0c4abc32c00611fe1d52c9661f5cc79a3f74c6d4nd</highlight>
0c4abc32c00611fe1d52c9661f5cc79a3f74c6d4nd<!-- END EXAMPLE CODE -->
0c4abc32c00611fe1d52c9661f5cc79a3f74c6d4ndThis bit of code lets the server know that we have now registered a new module
0c4abc32c00611fe1d52c9661f5cc79a3f74c6d4ndin the system, and that its name is <code>example_module</code>. The name
0c4abc32c00611fe1d52c9661f5cc79a3f74c6d4ndof the module is used primarily for two things:<br/>
9dd0b961340554104e5b6e837ddb3101f843cc3fcovener<li>Letting the server know how to load the module using the LoadModule</li>
9dd0b961340554104e5b6e837ddb3101f843cc3fcovener<li>Setting up a namespace for the module to use in configurations</li>
635de20c16ef862bfc5b0d5f9ceb40ebeaddfdf3noirinFor now, we're only concerned with the first purpose of the module name,
635de20c16ef862bfc5b0d5f9ceb40ebeaddfdf3noirinwhich comes into play when we need to load the module:
9dd0b961340554104e5b6e837ddb3101f843cc3fcovener</highlight>
25d988d92af8cf0d997aa1ebbc7cb11daa14d0becovenerIn essence, this tells the server to open up <code>mod_example.so</code> and look for a module
25d988d92af8cf0d997aa1ebbc7cb11daa14d0becovenerWithin this name tag of ours is also a bunch of references to how we would
25d988d92af8cf0d997aa1ebbc7cb11daa14d0becovenerlike to handle things: Which directives do we respond to in a configuration
635de20c16ef862bfc5b0d5f9ceb40ebeaddfdf3noirinfile or .htaccess, how do we operate within specific contexts, and what
25d988d92af8cf0d997aa1ebbc7cb11daa14d0becovenerhandlers are we interested in registering with the Apache HTTP service. We'll
635de20c16ef862bfc5b0d5f9ceb40ebeaddfdf3noirinreturn to all these elements later in this document.
fa0f379e3845907d7c1087d885169e302239bdbbnd<section id="hooking"><title>Getting started: Hooking into the server</title>
fa0f379e3845907d7c1087d885169e302239bdbbnd<section id="hook_intro"><title>An introduction to hooks</title>
97a9a944b5887e91042b019776c41d5dd74557aferikabeleWhen handling requests in Apache HTTP Server 2.4, the first thing you will need to do is
06ba4a61654b3763ad65f52283832ebf058fdf1cslivecreate a hook into the request handling process. A hook is essentially a
25d988d92af8cf0d997aa1ebbc7cb11daa14d0becovenermessage telling the server that you are willing to either serve or at least
25d988d92af8cf0d997aa1ebbc7cb11daa14d0becovenertake a glance at certain requests given by clients. All handlers, whether
635de20c16ef862bfc5b0d5f9ceb40ebeaddfdf3noirinit's mod_rewrite, mod_authn_*, mod_proxy and so on, are hooked into
97a9a944b5887e91042b019776c41d5dd74557aferikabelespecific parts of the request process. As you are probably aware, modules
06ba4a61654b3763ad65f52283832ebf058fdf1csliveserve different purposes; Some are authentication/authorization handlers,
0c4abc32c00611fe1d52c9661f5cc79a3f74c6d4ndothers are file or script handlers while some third modules rewrite URIs or
0c4abc32c00611fe1d52c9661f5cc79a3f74c6d4ndproxies content. Furthermore, in the end, it is up to the user of the server
0c4abc32c00611fe1d52c9661f5cc79a3f74c6d4ndhow and when each module will come into place. Thus, the server itself does not
0c4abc32c00611fe1d52c9661f5cc79a3f74c6d4ndpresume to know which module is responsible for handling a specific
0c4abc32c00611fe1d52c9661f5cc79a3f74c6d4ndrequest, and will ask each module whether they have an interest in a given
0c4abc32c00611fe1d52c9661f5cc79a3f74c6d4ndrequest or not. It is then up to each module to either gently decline
0c4abc32c00611fe1d52c9661f5cc79a3f74c6d4ndserving a request, accept serving it or flat out deny the request from
0c4abc32c00611fe1d52c9661f5cc79a3f74c6d4ndbeing served, as authentication/authorization modules do: <br/>
0c4abc32c00611fe1d52c9661f5cc79a3f74c6d4nd<img src="/images/build_a_mod_2.png" alt="Hook handling in httpd"/><br/>
0c4abc32c00611fe1d52c9661f5cc79a3f74c6d4ndTo make it a bit easier for handlers such as our mod_example to know
0c4abc32c00611fe1d52c9661f5cc79a3f74c6d4ndwhether the client is requesting content we should handle or not, the server
0c4abc32c00611fe1d52c9661f5cc79a3f74c6d4ndhas directives for hinting to modules whether their assistance is needed or
0c4abc32c00611fe1d52c9661f5cc79a3f74c6d4ndnot. Two of these are <directive module="mod_mime">AddHandler</directive>
0c4abc32c00611fe1d52c9661f5cc79a3f74c6d4ndand <directive module="core">SetHandler</directive>. Let's take a look at
fa0f379e3845907d7c1087d885169e302239bdbbndan example using <directive module="mod_mime">AddHandler</directive>. In
fa0f379e3845907d7c1087d885169e302239bdbbndour example case, we want every request ending with .sum to be served by
fa0f379e3845907d7c1087d885169e302239bdbbnd<code>mod_example</code>, so we'll add a configuration directive that tells
fa0f379e3845907d7c1087d885169e302239bdbbndthe server to do just that:
fa0f379e3845907d7c1087d885169e302239bdbbndAddHandler example-handler .sum
fa0f379e3845907d7c1087d885169e302239bdbbnd</highlight>
06ba4a61654b3763ad65f52283832ebf058fdf1csliveWhat this tells the server is the following: <em>Whenever we receive a request
06ba4a61654b3763ad65f52283832ebf058fdf1cslivefor a URI ending in .sum, we are to let all modules know that we are
06ba4a61654b3763ad65f52283832ebf058fdf1cslivelooking for whoever goes by the name of "example-handler" </em>.
bf380c59be3f235bde21f1c00098e09e3cf7e7aerpluemThus, when a request is being served that ends in .sum, the server will let all
b115299831a7b4bbec58a88d708d8536e1ecd50csfmodules know, that this request should be served by "example-handler
fa0f379e3845907d7c1087d885169e302239bdbbnd". As you will see later, when we start building mod_example, we will
fa0f379e3845907d7c1087d885169e302239bdbbndcheck for this handler tag relayed by <code>AddHandler</code> and reply to
b115299831a7b4bbec58a88d708d8536e1ecd50csfthe server based on the value of this tag.
06ba4a61654b3763ad65f52283832ebf058fdf1cslive<section id="hook_declaration"><title>Hooking into httpd</title>
bf380c59be3f235bde21f1c00098e09e3cf7e7aerpluemTo begin with, we only want to create a simple handler, that replies to the
b115299831a7b4bbec58a88d708d8536e1ecd50csfclient browser when a specific URL is requested, so we won't bother setting
fa0f379e3845907d7c1087d885169e302239bdbbndup configuration handlers and directives just yet. Our initial module
fa0f379e3845907d7c1087d885169e302239bdbbnddefinition will look like this:</p>
fa0f379e3845907d7c1087d885169e302239bdbbnd<!-- BEGIN EXAMPLE CODE -->
06ba4a61654b3763ad65f52283832ebf058fdf1cslivemodule AP_MODULE_DECLARE_DATA example_module =
fa0f379e3845907d7c1087d885169e302239bdbbnd STANDARD20_MODULE_STUFF,
fa0f379e3845907d7c1087d885169e302239bdbbnd register_hooks /* Our hook registering function */
fa0f379e3845907d7c1087d885169e302239bdbbnd</highlight>
fa0f379e3845907d7c1087d885169e302239bdbbnd<!-- END EXAMPLE CODE -->
c6a2d6fa44f8698851dec5051ee3782c2913605fnd<p>This lets the server know that we are not interesting in anything fancy, we
06ba4a61654b3763ad65f52283832ebf058fdf1cslivejust want to hook onto the requests and possibly handle some of them. </p>
5ae30adbe59946de742ab0cd6be3b7457471a698takashi<p> The reference in our example declaration, <code>register_hooks</code>
97a9a944b5887e91042b019776c41d5dd74557aferikabeleis the name of a function we will create to manage how we hook onto the
97a9a944b5887e91042b019776c41d5dd74557aferikabelerequest process. In this example module, the function has just one purpose;
5ae30adbe59946de742ab0cd6be3b7457471a698takashiTo create a simple hook that gets called after all the rewrites, access
5ae30adbe59946de742ab0cd6be3b7457471a698takashicontrol etc has been handled. Thus, we will let the server know, that we want
97a9a944b5887e91042b019776c41d5dd74557aferikabeleto hook into its process as one of the last modules:
97a9a944b5887e91042b019776c41d5dd74557aferikabele<!-- BEGIN EXAMPLE CODE -->
97a9a944b5887e91042b019776c41d5dd74557aferikabelestatic void register_hooks(apr_pool_t *pool)
06ba4a61654b3763ad65f52283832ebf058fdf1cslive /* Create a hook in the request handler, so we get called when a request arrives */
06ba4a61654b3763ad65f52283832ebf058fdf1cslive ap_hook_handler(example_handler, NULL, NULL, APR_HOOK_LAST);
74a6de79356cd15d2e47065087785e36dd65aa41nd<!-- END EXAMPLE CODE -->
97a9a944b5887e91042b019776c41d5dd74557aferikabeleThe <code>example_handler</code> reference is the function that will handle
97a9a944b5887e91042b019776c41d5dd74557aferikabelethe request. We will discuss how to create a handler in the next chapter.
97a9a944b5887e91042b019776c41d5dd74557aferikabele<section id="hook_others"><title>Other useful hooks</title>
5ae30adbe59946de742ab0cd6be3b7457471a698takashiHooking into the request handling phase is but one of many hooks that you
5ae30adbe59946de742ab0cd6be3b7457471a698takashican create. Some other ways of hooking are:
06ba4a61654b3763ad65f52283832ebf058fdf1cslive<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>
53d2fd50ff45e7c568f0588c742a5ef9edf8e275rbowen<li><code>ap_hook_pre_config</code>: Place a hook that executes before any configuration data has been read (very early hook)</li>
5ae30adbe59946de742ab0cd6be3b7457471a698takashi<li><code>ap_hook_post_config</code>: Place a hook that executes after configuration has been parsed, but before the server has forked</li>
97a9a944b5887e91042b019776c41d5dd74557aferikabele<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>
97a9a944b5887e91042b019776c41d5dd74557aferikabele<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>
5ae30adbe59946de742ab0cd6be3b7457471a698takashi<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>
97a9a944b5887e91042b019776c41d5dd74557aferikabele<section id="handling"><title>Building a handler</title>
06ba4a61654b3763ad65f52283832ebf058fdf1csliveA handler is essentially a function that receives a callback when a request
06ba4a61654b3763ad65f52283832ebf058fdf1csliveto the server is made. It is passed a record of the current request (how it was
06ba4a61654b3763ad65f52283832ebf058fdf1cslivemade, which headers and requests were passed along, who's giving the
97a9a944b5887e91042b019776c41d5dd74557aferikabelerequest and so on), and is put in charge of either telling the server that it's
97a9a944b5887e91042b019776c41d5dd74557aferikabelenot interested in the request or handle the request with the tools provided.
97a9a944b5887e91042b019776c41d5dd74557aferikabele<section id="simple_handler"><title>A simple "Hello, world!"
97a9a944b5887e91042b019776c41d5dd74557aferikabelehandler</title>
97a9a944b5887e91042b019776c41d5dd74557aferikabele<p>Let's start off by making a very simple request handler
97a9a944b5887e91042b019776c41d5dd74557aferikabelethat does the following:
06ba4a61654b3763ad65f52283832ebf058fdf1cslive<li>Check that this is a request that should be served by "example-handler"</li>
06ba4a61654b3763ad65f52283832ebf058fdf1cslive<li>Set the content type of our output to <code>text/html</code></li>
97a9a944b5887e91042b019776c41d5dd74557aferikabele<li>Write "Hello, world!" back to the client browser</li>
97a9a944b5887e91042b019776c41d5dd74557aferikabele<li>Let the server know that we took care of this request and everything went fine</li>
97a9a944b5887e91042b019776c41d5dd74557aferikabeleIn C code, our example handler will now look like this:
06ba4a61654b3763ad65f52283832ebf058fdf1cslive<!-- BEGIN EXAMPLE CODE -->
06ba4a61654b3763ad65f52283832ebf058fdf1cslivestatic int example_handler(request_rec *r)
fa0f379e3845907d7c1087d885169e302239bdbbnd /* First off, we need to check if this is a call for the "example-handler" handler.
fa0f379e3845907d7c1087d885169e302239bdbbnd * If it is, we accept it and do our things, if not, we simply return DECLINED,
cea021a7fc2657b091df4d3b031c4254ec371dd7rbowen * and the server will try somewhere else.
fa0f379e3845907d7c1087d885169e302239bdbbnd if (!r->handler || strcmp(r->handler, "example-handler")) return (DECLINED);
37ef4b86270a8e58f87aa5fe558e3e65af97991ccovener /* Now that we are handling this request, we'll write out "Hello, world!" to the client.
37ef4b86270a8e58f87aa5fe558e3e65af97991ccovener * To do so, we must first set the appropriate content type, followed by our output.
37ef4b86270a8e58f87aa5fe558e3e65af97991ccovener ap_rprintf(r, "Hello, world!");
37ef4b86270a8e58f87aa5fe558e3e65af97991ccovener /* Lastly, we must tell the server that we took care of this request and everything went fine.
fa0f379e3845907d7c1087d885169e302239bdbbnd * We do so by simply returning the value OK to the server.
fa0f379e3845907d7c1087d885169e302239bdbbnd</highlight>
fa0f379e3845907d7c1087d885169e302239bdbbnd<!-- END EXAMPLE CODE -->
06ba4a61654b3763ad65f52283832ebf058fdf1csliveNow, we put all we have learned together and end up with a program that
06ba4a61654b3763ad65f52283832ebf058fdf1cslive<a href="http://people.apache.org/~humbedooh/mods/examples/mod_example_1.c">mod_example_1.c</a>
06ba4a61654b3763ad65f52283832ebf058fdf1cslive. The functions used in this example will be explained later in the section
cea021a7fc2657b091df4d3b031c4254ec371dd7rbowen<a href= "#functions">"Some useful functions you should know"</a>.
fa0f379e3845907d7c1087d885169e302239bdbbnd<section id="request_rec"><title>The request_rec structure</title>
cea021a7fc2657b091df4d3b031c4254ec371dd7rbowen<p>The most essential part of any request is the <em>request record
cea021a7fc2657b091df4d3b031c4254ec371dd7rbowen</em>. In a call to a handler function, this is represented by the <code>
fa0f379e3845907d7c1087d885169e302239bdbbndrequest_rec* </code> structure passed along with every call that is made.
fa0f379e3845907d7c1087d885169e302239bdbbndThis struct, typically just referred to as <code>r</code> in modules,
06ba4a61654b3763ad65f52283832ebf058fdf1cslivecontains all the information you need for your module to fully process any
06ba4a61654b3763ad65f52283832ebf058fdf1csliveHTTP request and respond accordingly.</p> <p>Some key elements of the <code>
06ba4a61654b3763ad65f52283832ebf058fdf1csliverequest_rec </code> structure are:
06ba4a61654b3763ad65f52283832ebf058fdf1cslive<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>
06ba4a61654b3763ad65f52283832ebf058fdf1cslive<li><code>r->method (char*):</code> Contains the HTTP method being used, f.x. GET or POST</li>
777c17c11c2b1638f191241364e034779851d186covener<li><code>r->filename (char*):</code> Contains the translated filename the client is requesting</li>
777c17c11c2b1638f191241364e034779851d186covener<li><code>r->args (char*):</code> Contains the query string of the request, if any</li>
06ba4a61654b3763ad65f52283832ebf058fdf1cslive<li><code>r->headers_in (apr_table_t*):</code> Contains all the headers sent by the client</li>
06ba4a61654b3763ad65f52283832ebf058fdf1cslive<li><code>r->connection (conn_rec*):</code> A record containing information about the current connection</li>
06ba4a61654b3763ad65f52283832ebf058fdf1cslive<li><code>r->user (char*):</code> If the URI requires authentication, this is set to the username provided</li>
06ba4a61654b3763ad65f52283832ebf058fdf1cslive<li><code>r->useragent_ip (char*):</code> The IP address of the client connecting to us</li>
fa0f379e3845907d7c1087d885169e302239bdbbnd<li><code>r->pool (apr_pool_t*)</code>: The memory pool of this request. We'll discuss this in the
fa0f379e3845907d7c1087d885169e302239bdbbnd"<a href="#memory">Memory management</a>" chapter.</li>
06ba4a61654b3763ad65f52283832ebf058fdf1csliveA complete list of all the values contained within the <code>request_rec</code> structure can be found in
fa0f379e3845907d7c1087d885169e302239bdbbndthe <a href="http://svn.apache.org/repos/asf/httpd/httpd/trunk/include/httpd.h"><code>httpd.h</code></a> header
c0a201f9f0cda37f4e5829462c7e489f85bf327ccovenerfile 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>.
eaaa852423e42d6d86bcada80ed781a205fc3e5fndLet's try out some of these variables in another example handler:<br/>
fa0f379e3845907d7c1087d885169e302239bdbbnd<!-- BEGIN EXAMPLE CODE -->
fa0f379e3845907d7c1087d885169e302239bdbbndstatic int example_handler(request_rec *r)
eaaa852423e42d6d86bcada80ed781a205fc3e5fnd /* Set the appropriate content type */
4203a35c28d7c60adb7e9ef3be87aad34951c79asf /* Print out the IP address of the client connecting to us: */
4203a35c28d7c60adb7e9ef3be87aad34951c79asf ap_rprintf(r, "<h2>Hello, %s!</h2>", r->useragent_ip);
4203a35c28d7c60adb7e9ef3be87aad34951c79asf /* If we were reached through a GET or a POST request, be happy, else sad. */
06ba4a61654b3763ad65f52283832ebf058fdf1cslive if ( !strcmp(r->method, "POST") || !strcmp(r->method, "GET") ) {
97a9a944b5887e91042b019776c41d5dd74557aferikabele ap_rputs("You used a GET or a POST method, that makes us happy!<br/>", r);
fa0f379e3845907d7c1087d885169e302239bdbbnd ap_rputs("You did not use POST or GET, that makes us sad :(<br/>", r);
4cb65c31bc681540ea623e1cb2bdd09749fb8d7esf /* Lastly, if there was a query string, let's print that too! */
4cb65c31bc681540ea623e1cb2bdd09749fb8d7esf if (r->args) {
fa0f379e3845907d7c1087d885169e302239bdbbnd ap_rprintf(r, "Your query string was: %s", r->args);
fa0f379e3845907d7c1087d885169e302239bdbbnd return OK;
fa0f379e3845907d7c1087d885169e302239bdbbnd</highlight>
fa0f379e3845907d7c1087d885169e302239bdbbnd<!-- END EXAMPLE CODE -->
fa0f379e3845907d7c1087d885169e302239bdbbndApache relies on return values from handlers to signify whether a request
fa0f379e3845907d7c1087d885169e302239bdbbndwas handled or not, and if so, whether the request went well or not. If a
fa0f379e3845907d7c1087d885169e302239bdbbndmodule is not interested in handling a specific request, it should always
fa0f379e3845907d7c1087d885169e302239bdbbndreturn the value <code>DECLINED</code>. If it is handling a request, it
fa0f379e3845907d7c1087d885169e302239bdbbndshould either return the generic value <code>OK</code>, or a specific HTTP
fa0f379e3845907d7c1087d885169e302239bdbbndstatus code, for example:
fa0f379e3845907d7c1087d885169e302239bdbbnd<!-- BEGIN EXAMPLE CODE -->
a4d04b8c74044c58bd4182028a1408d936c95951covenerstatic int example_handler(request_rec *r)
06ba4a61654b3763ad65f52283832ebf058fdf1cslive /* Return 404: Not found */
fa0f379e3845907d7c1087d885169e302239bdbbnd return HTTP_NOT_FOUND;
fa0f379e3845907d7c1087d885169e302239bdbbnd</highlight>
fa0f379e3845907d7c1087d885169e302239bdbbnd<!-- END EXAMPLE CODE -->
06ba4a61654b3763ad65f52283832ebf058fdf1csliveReturning <code>OK</code> or a HTTP status code does not necessarily mean
bf380c59be3f235bde21f1c00098e09e3cf7e7aerpluemthat the request will end. The server may still have other handlers that are
fa0f379e3845907d7c1087d885169e302239bdbbndinterested in this request, for instance the logging modules which, upon a
eaaa852423e42d6d86bcada80ed781a205fc3e5fndsuccessful request, will write down a summary of what was requested and how
fa0f379e3845907d7c1087d885169e302239bdbbndit went. To do a full stop and prevent any further processing after your
fa0f379e3845907d7c1087d885169e302239bdbbndmodule is done, you can return the value <code>DONE</code> to let the server
fa0f379e3845907d7c1087d885169e302239bdbbndknow that it should cease all activity on this request and carry on with
fa0f379e3845907d7c1087d885169e302239bdbbndthe next, without informing other handlers.
fa0f379e3845907d7c1087d885169e302239bdbbnd<li><code>DECLINED</code>: We are not handling this request</li>
fa0f379e3845907d7c1087d885169e302239bdbbnd<li><code>OK</code>: We handled this request and it went well</li>
fa0f379e3845907d7c1087d885169e302239bdbbnd<li><code>DONE</code>: We handled this request and the server should just close this thread without further processing</li>
fa0f379e3845907d7c1087d885169e302239bdbbnd<li><code>HTTP_MOVED_PERMANENTLY (301)</code>: The resource has moved to a new URL</li>
fa0f379e3845907d7c1087d885169e302239bdbbnd<li><code>HTTP_UNAUTHORIZED (401)</code>: Client is not authorized to visit this page</li>
fa0f379e3845907d7c1087d885169e302239bdbbnd<li><code>HTTP_FORBIDDEN (403)</code>: Permission denied</li>
fa0f379e3845907d7c1087d885169e302239bdbbnd<li><code>HTTP_NOT_FOUND (404)</code>: File not found</li>
fa0f379e3845907d7c1087d885169e302239bdbbnd<li><code>HTTP_INTERNAL_SERVER_ERROR (500)</code>: Internal server error (self explanatory)</li>
fa0f379e3845907d7c1087d885169e302239bdbbnd<section id="functions"><title>Some useful functions you should know</title>
fa0f379e3845907d7c1087d885169e302239bdbbnd <code>ap_rputs(const char *string, request_rec *r)</code>: <br/>
fa0f379e3845907d7c1087d885169e302239bdbbnd Sends a string of text to the client. This is a shorthand version of <a
fa0f379e3845907d7c1087d885169e302239bdbbnd href="http://ci.apache.org/projects/httpd/trunk/doxygen/group__APACHE__CORE__PROTO.html#gac827cd0537d2b6213a7c06d7c26cc36e">
fa0f379e3845907d7c1087d885169e302239bdbbnd ap_rwrite</a>.
fa0f379e3845907d7c1087d885169e302239bdbbnd<!-- BEGIN EXAMPLE CODE -->
fa0f379e3845907d7c1087d885169e302239bdbbnd<highlight language="c">ap_rputs("Hello, world!", r);</highlight>
fa0f379e3845907d7c1087d885169e302239bdbbnd<!-- END EXAMPLE CODE -->
fa0f379e3845907d7c1087d885169e302239bdbbnd <a href="http://ci.apache.org/projects/httpd/trunk/doxygen/group__APACHE__CORE__PROTO.html#ga5e91eb6ca777c9a427b2e82bf1eeb81d">ap_rprintf</a></code>: <br/>
fa0f379e3845907d7c1087d885169e302239bdbbnd This function works just like <code>printf</code>, except it sends the result to the client.
06ba4a61654b3763ad65f52283832ebf058fdf1cslive<!-- BEGIN EXAMPLE CODE -->
06ba4a61654b3763ad65f52283832ebf058fdf1cslive<highlight language="c">ap_rprintf(r, "Hello, %s!", r->useragent_ip);</highlight>
bf380c59be3f235bde21f1c00098e09e3cf7e7aerpluem<!-- END EXAMPLE CODE -->
88f586e767b7b224bdb1a178455668a2475cfc75rbowen <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/>
88f586e767b7b224bdb1a178455668a2475cfc75rbowen Sets the content type of the output you are sending.
06ba4a61654b3763ad65f52283832ebf058fdf1cslive<!-- BEGIN EXAMPLE CODE -->
06ba4a61654b3763ad65f52283832ebf058fdf1cslive<highlight language="c">ap_set_content_type(r, "text/plain"); /* force a raw text output */</highlight>
06ba4a61654b3763ad65f52283832ebf058fdf1cslive<!-- END EXAMPLE CODE -->
81785f72c9d133aef57ad6b02f248345d90239aapoirier<section id="memory"><title>Memory management</title>
bf380c59be3f235bde21f1c00098e09e3cf7e7aerpluemManaging your resources in Apache HTTP Server 2.4 is quite easy, thanks to the memory pool
bf380c59be3f235bde21f1c00098e09e3cf7e7aerpluemsystem. In essence, each server, connection and request have their own
bf380c59be3f235bde21f1c00098e09e3cf7e7aerpluemmemory pool that gets cleaned up when its scope ends, e.g. when a request
06ba4a61654b3763ad65f52283832ebf058fdf1csliveis done or when a server process shuts down. All your module needs to do is
06ba4a61654b3763ad65f52283832ebf058fdf1cslivelatch onto this memory pool, and you won't have to worry about having to
bf380c59be3f235bde21f1c00098e09e3cf7e7aerpluemclean up after yourself - pretty neat, huh?
bf380c59be3f235bde21f1c00098e09e3cf7e7aerpluemIn our module, we will primarily be allocating memory for each request, so
06ba4a61654b3763ad65f52283832ebf058fdf1cslivereference when creating new objects. A few of the functions for allocating
bf380c59be3f235bde21f1c00098e09e3cf7e7aerpluemmemory within a pool are:
bf380c59be3f235bde21f1c00098e09e3cf7e7aerpluem<li><code>void* <a href="http://apr.apache.org/docs/apr/1.4/group__apr__pools.html#ga85f1e193c31d109affda72f9a92c6915">apr_palloc</a>(
bf380c59be3f235bde21f1c00098e09e3cf7e7aerpluemapr_pool_t *p, apr_size_t size)</code>: Allocates <code>size</code> number of bytes in the pool for you</li>
bf380c59be3f235bde21f1c00098e09e3cf7e7aerpluem<li><code>void* <a href="http://apr.apache.org/docs/apr/1.4/group__apr__pools.html#gaf61c098ad258069d64cdf8c0a9369f9e">apr_pcalloc</a>(
bf380c59be3f235bde21f1c00098e09e3cf7e7aerpluemapr_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>
bf380c59be3f235bde21f1c00098e09e3cf7e7aerpluem<li><code>char* <a href="http://apr.apache.org/docs/apr/1.4/group__apr__strings.html#gabc79e99ff19abbd7cfd18308c5f85d47">apr_pstrdup</a>(
06ba4a61654b3763ad65f52283832ebf058fdf1csliveapr_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>
06ba4a61654b3763ad65f52283832ebf058fdf1cslive<li><code>char* <a href="http://apr.apache.org/docs/apr/1.4/group__apr__strings.html#ga3eca76b8d293c5c3f8021e45eda813d8">apr_psprintf</a>(
3b1807171c3f06d8951da1bf23c5f51961c274bbrbowenapr_pool_t *p, const char *fmt, ...)</code>: Similar to <code>sprintf</code>, except the server supplies you with an appropriately allocated target variable</li>
3b1807171c3f06d8951da1bf23c5f51961c274bbrbowen<p>Let's put these functions into an example handler:</p>
3b1807171c3f06d8951da1bf23c5f51961c274bbrbowen<!-- BEGIN EXAMPLE CODE -->
3b1807171c3f06d8951da1bf23c5f51961c274bbrbowenstatic int example_handler(request_rec *r)
3b1807171c3f06d8951da1bf23c5f51961c274bbrbowen const char* original = "You can't edit this!";
3b1807171c3f06d8951da1bf23c5f51961c274bbrbowen char* copy;
3b1807171c3f06d8951da1bf23c5f51961c274bbrbowen int* integers;
3b1807171c3f06d8951da1bf23c5f51961c274bbrbowen /* Allocate space for 10 integer values and set them all to zero. */
88f586e767b7b224bdb1a178455668a2475cfc75rbowen integers = apr_pcalloc(r->pool, sizeof(int)*10);
88f586e767b7b224bdb1a178455668a2475cfc75rbowen /* Create a copy of the 'original' variable that we can edit. */
88f586e767b7b224bdb1a178455668a2475cfc75rbowen copy = apr_pstrdup(r->pool, original);
88f586e767b7b224bdb1a178455668a2475cfc75rbowen</highlight>
88f586e767b7b224bdb1a178455668a2475cfc75rbowen<!-- END EXAMPLE CODE -->
88f586e767b7b224bdb1a178455668a2475cfc75rbowenThis is all well and good for our module, which won't need any
88f586e767b7b224bdb1a178455668a2475cfc75rbowenpre-initialized variables or structures. However, if we wanted to
88f586e767b7b224bdb1a178455668a2475cfc75rboweninitialize something early on, before the requests come rolling in, we
88f586e767b7b224bdb1a178455668a2475cfc75rbowencould simply add a call to a function in our <code>register_hooks</code>
88f586e767b7b224bdb1a178455668a2475cfc75rbowenfunction to sort it out:
88f586e767b7b224bdb1a178455668a2475cfc75rbowen<!-- BEGIN EXAMPLE CODE -->
88f586e767b7b224bdb1a178455668a2475cfc75rbowenstatic void register_hooks(apr_pool_t *pool)
88f586e767b7b224bdb1a178455668a2475cfc75rbowen /* Call a function that initializes some stuff */
88f586e767b7b224bdb1a178455668a2475cfc75rbowen example_init_function(pool);
88f586e767b7b224bdb1a178455668a2475cfc75rbowen /* Create a hook in the request handler, so we get called when a request arrives */
88f586e767b7b224bdb1a178455668a2475cfc75rbowen ap_hook_handler(example_handler, NULL, NULL, APR_HOOK_LAST);
88f586e767b7b224bdb1a178455668a2475cfc75rbowen</highlight>
88f586e767b7b224bdb1a178455668a2475cfc75rbowen<!-- END EXAMPLE CODE -->
88f586e767b7b224bdb1a178455668a2475cfc75rbowenIn this pre-request initialization function we would not be using the
88f586e767b7b224bdb1a178455668a2475cfc75rbowensame pool as we did when allocating resources for request-based functions.
88f586e767b7b224bdb1a178455668a2475cfc75rbowenInstead, we would use the pool given to us by the server for allocating memory
88f586e767b7b224bdb1a178455668a2475cfc75rbowenon a per-process based level.
88f586e767b7b224bdb1a178455668a2475cfc75rbowen<section id="parsing"><title>Parsing request data</title>
88f586e767b7b224bdb1a178455668a2475cfc75rbowenIn our example module, we would like to add a feature, that checks which
88f586e767b7b224bdb1a178455668a2475cfc75rbowentype of digest, MD5 or SHA1 the client would like to see. This could be
88f586e767b7b224bdb1a178455668a2475cfc75rbowensolved by adding a query string to the request. A query string is typically
88f586e767b7b224bdb1a178455668a2475cfc75rbowencomprised of several keys and values put together in a string, for instance
88f586e767b7b224bdb1a178455668a2475cfc75rbowen<code>valueA=yes&valueB=no&valueC=maybe</code>. It is up to the
88f586e767b7b224bdb1a178455668a2475cfc75rbowenmodule itself to parse these and get the data it requires. In our example,
88f586e767b7b224bdb1a178455668a2475cfc75rbowenwe'll be looking for a key called <code>digest</code>, and if set to <code>
88f586e767b7b224bdb1a178455668a2475cfc75rbowenmd5</code>, we'll produce an MD5 digest, otherwise we'll produce a SHA1
97a9a944b5887e91042b019776c41d5dd74557aferikabeleSince the introduction of Apache HTTP Server 2.4, parsing request data from GET and
06ba4a61654b3763ad65f52283832ebf058fdf1cslivePOST requests have never been easier. All we require to parse both GET and
bf380c59be3f235bde21f1c00098e09e3cf7e7aerpluemPOST data is four simple lines:
06ba4a61654b3763ad65f52283832ebf058fdf1cslive<!-- BEGIN EXAMPLE CODE -->
06ba4a61654b3763ad65f52283832ebf058fdf1cslive<a href="http://ci.apache.org/projects/httpd/trunk/doxygen/group__apr__tables.html#gad7ea82d6608a4a633fc3775694ab71e4">apr_table_t</a> *GET; <em>
bf380c59be3f235bde21f1c00098e09e3cf7e7aerpluem</em><a href="http://ci.apache.org/projects/httpd/trunk/doxygen/structapr__array__header__t.html">apr_array_header_t</a>*POST;
06ba4a61654b3763ad65f52283832ebf058fdf1cslive<a href="http://ci.apache.org/projects/httpd/trunk/doxygen/group__APACHE__CORE__SCRIPT.html#gaed25877b529623a4d8f99f819ba1b7bd">
bf380c59be3f235bde21f1c00098e09e3cf7e7aerpluem</em><a href="http://ci.apache.org/projects/httpd/trunk/doxygen/group__APACHE__CORE__DAEMON.html#ga9d426b6382b49754d4f87c55f65af202">
bf380c59be3f235bde21f1c00098e09e3cf7e7aerpluemap_parse_form_data</a>(r, NULL, &POST, -1, 8192);
06ba4a61654b3763ad65f52283832ebf058fdf1cslive</highlight>
3b1807171c3f06d8951da1bf23c5f51961c274bbrbowen<!-- END EXAMPLE CODE -->
3b1807171c3f06d8951da1bf23c5f51961c274bbrbowenIn our specific example module, we're looking for the <code>digest</code>
3b1807171c3f06d8951da1bf23c5f51961c274bbrbowenvalue from the query string, which now resides inside a table called <code>
3b1807171c3f06d8951da1bf23c5f51961c274bbrbowenGET</code>. To extract this value, we need only perform a simple operation:
88f586e767b7b224bdb1a178455668a2475cfc75rbowen<!-- BEGIN EXAMPLE CODE -->
3b1807171c3f06d8951da1bf23c5f51961c274bbrbowen/* Get the "digest" key from the query string, if any. */
3b1807171c3f06d8951da1bf23c5f51961c274bbrbowenconst char *digestType = apr_table_get(GET, "digest");
3b1807171c3f06d8951da1bf23c5f51961c274bbrbowen/* If no key was returned, we will set a default value instead. */
3b1807171c3f06d8951da1bf23c5f51961c274bbrbowenif (!digestType) digestType = "sha1";
3b1807171c3f06d8951da1bf23c5f51961c274bbrbowen</highlight>
3b1807171c3f06d8951da1bf23c5f51961c274bbrbowen<!-- END EXAMPLE CODE -->
3b1807171c3f06d8951da1bf23c5f51961c274bbrbowenThe structures used for the POST and GET data are not exactly the same, so
bf380c59be3f235bde21f1c00098e09e3cf7e7aerpluemif we were to fetch a value from POST data instead of the query string, we
97a9a944b5887e91042b019776c41d5dd74557aferikabelewould have to resort to a few more lines, as outlined in <a href="#get_post"
bf380c59be3f235bde21f1c00098e09e3cf7e7aerpluem>this example</a> in the last chapter of this document.
bf380c59be3f235bde21f1c00098e09e3cf7e7aerpluem<section id="advanced_handler"><title>Making an advanced handler</title>
3b1807171c3f06d8951da1bf23c5f51961c274bbrbowenNow that we have learned how to parse form data and manage our resources,
3b1807171c3f06d8951da1bf23c5f51961c274bbrbowenwe can move on to creating an advanced version of our module, that spits
3b1807171c3f06d8951da1bf23c5f51961c274bbrbowenout the MD5 or SHA1 digest of files:
3b1807171c3f06d8951da1bf23c5f51961c274bbrbowen<!-- BEGIN EXAMPLE CODE -->
06ba4a61654b3763ad65f52283832ebf058fdf1cslivestatic int example_handler(request_rec *r)
06ba4a61654b3763ad65f52283832ebf058fdf1cslive int rc, exists;
06ba4a61654b3763ad65f52283832ebf058fdf1cslive apr_finfo_t finfo;
06ba4a61654b3763ad65f52283832ebf058fdf1cslive apr_file_t *file;
97a9a944b5887e91042b019776c41d5dd74557aferikabele char *filename;
06ba4a61654b3763ad65f52283832ebf058fdf1cslive char buffer[256];
06ba4a61654b3763ad65f52283832ebf058fdf1cslive apr_size_t readBytes;
4cb65c31bc681540ea623e1cb2bdd09749fb8d7esf apr_table_t *GET;
4cb65c31bc681540ea623e1cb2bdd09749fb8d7esf apr_array_header_t *POST;
4cb65c31bc681540ea623e1cb2bdd09749fb8d7esf const char *digestType;
fa1092e17f0b85a610379ac564334ad879ed7dbarbowen /* Check that the "example-handler" handler is being called. */
fa1092e17f0b85a610379ac564334ad879ed7dbarbowen if (!r->handler || strcmp(r->handler, "example-handler")) return (DECLINED);
fa1092e17f0b85a610379ac564334ad879ed7dbarbowen /* Figure out which file is being requested by removing the .sum from it */
fa1092e17f0b85a610379ac564334ad879ed7dbarbowen filename = apr_pstrdup(r->pool, r->filename);
fa1092e17f0b85a610379ac564334ad879ed7dbarbowen filename[strlen(filename)-4] = 0; /* Cut off the last 4 characters. */
fa1092e17f0b85a610379ac564334ad879ed7dbarbowen /* Figure out if the file we request a sum on exists and isn't a directory */
fa1092e17f0b85a610379ac564334ad879ed7dbarbowen rc = apr_stat(&finfo, filename, APR_FINFO_MIN, r->pool);
4cb65c31bc681540ea623e1cb2bdd09749fb8d7esf if (rc == APR_SUCCESS) {
bf380c59be3f235bde21f1c00098e09e3cf7e7aerpluem (finfo.filetype != APR_NOFILE)
06ba4a61654b3763ad65f52283832ebf058fdf1cslive && !(finfo.filetype & APR_DIR)
bf380c59be3f235bde21f1c00098e09e3cf7e7aerpluem if (!exists) return HTTP_NOT_FOUND; /* Return a 404 if not found. */
06ba4a61654b3763ad65f52283832ebf058fdf1cslive /* If apr_stat failed, we're probably not allowed to check this file. */
06ba4a61654b3763ad65f52283832ebf058fdf1cslive else return HTTP_FORBIDDEN;
97a9a944b5887e91042b019776c41d5dd74557aferikabele /* Parse the GET and, optionally, the POST data sent to us */
5ae30adbe59946de742ab0cd6be3b7457471a698takashi ap_args_to_table(r, &GET);
06ba4a61654b3763ad65f52283832ebf058fdf1cslive ap_parse_form_data(r, NULL, &POST, -1, 8192);
06ba4a61654b3763ad65f52283832ebf058fdf1cslive /* Set the appropriate content type */
06ba4a61654b3763ad65f52283832ebf058fdf1cslive /* Print a title and some general information */
06ba4a61654b3763ad65f52283832ebf058fdf1cslive ap_rprintf(r, "<h2>Information on %s:</h2>", filename);
97a9a944b5887e91042b019776c41d5dd74557aferikabele ap_rprintf(r, "<b>Size:</b> %u bytes<br/>", finfo.size);
81785f72c9d133aef57ad6b02f248345d90239aapoirier /* Get the digest type the client wants to see */
06ba4a61654b3763ad65f52283832ebf058fdf1cslive digestType = apr_table_get(GET, "digest");
97a9a944b5887e91042b019776c41d5dd74557aferikabele if (!digestType) digestType = "MD5";
025069f3f8c6b59e730a72c229329dfad5a28424rbowen rc = apr_file_open(&file, filename, APR_READ, APR_OS_DEFAULT, r->pool);
06ba4a61654b3763ad65f52283832ebf058fdf1cslive if (rc == APR_SUCCESS) {
06ba4a61654b3763ad65f52283832ebf058fdf1cslive /* Are we trying to calculate the MD5 or the SHA1 digest? */
bf380c59be3f235bde21f1c00098e09e3cf7e7aerpluem if (!strcasecmp(digestType, "md5")) {
bf380c59be3f235bde21f1c00098e09e3cf7e7aerpluem /* Calculate the MD5 sum of the file */
9335f6d807d76d60e54af4ededdebebddb3e3d13noodl char chr[16];
9335f6d807d76d60e54af4ededdebebddb3e3d13noodl uint32_t num[4];
9335f6d807d76d60e54af4ededdebebddb3e3d13noodl apr_md5_ctx_t md5;
9335f6d807d76d60e54af4ededdebebddb3e3d13noodl apr_md5_init(&md5);
9335f6d807d76d60e54af4ededdebebddb3e3d13noodl readBytes = 256;
9335f6d807d76d60e54af4ededdebebddb3e3d13noodl while ( apr_file_read(file, buffer, &readBytes) == APR_SUCCESS ) {
9335f6d807d76d60e54af4ededdebebddb3e3d13noodl apr_md5_update(&md5, buffer, readBytes);
9335f6d807d76d60e54af4ededdebebddb3e3d13noodl apr_md5_final(digest.chr, &md5);
22d5d84393d960a2027f472036f3fee15d7dbce9nd /* Print out the MD5 digest */
bf380c59be3f235bde21f1c00098e09e3cf7e7aerpluem ap_rputs("<b>MD5: </b><code>", r);
06ba4a61654b3763ad65f52283832ebf058fdf1cslive for (n = 0; n < APR_MD5_DIGESTSIZE/4; n++) {
06ba4a61654b3763ad65f52283832ebf058fdf1cslive ap_rprintf(r, "%08x", digest.num[n]);
06ba4a61654b3763ad65f52283832ebf058fdf1cslive ap_rputs("</code>", r);
06ba4a61654b3763ad65f52283832ebf058fdf1cslive /* Print a link to the SHA1 version */
06ba4a61654b3763ad65f52283832ebf058fdf1cslive ap_rputs("<br/><a href='?digest=sha1'>View the SHA1 hash instead</a>", r);
7171511e7e2c17e9b54cc34dc247266b70138d6crbowen /* Calculate the SHA1 sum of the file */
06ba4a61654b3763ad65f52283832ebf058fdf1cslive char chr[20];
7171511e7e2c17e9b54cc34dc247266b70138d6crbowen uint32_t num[5];
06ba4a61654b3763ad65f52283832ebf058fdf1cslive apr_sha1_ctx_t sha1;
06ba4a61654b3763ad65f52283832ebf058fdf1cslive apr_sha1_init(&sha1);
97a9a944b5887e91042b019776c41d5dd74557aferikabele readBytes = 256;
06ba4a61654b3763ad65f52283832ebf058fdf1cslive while ( apr_file_read(file, buffer, &readBytes) == APR_SUCCESS ) {
81785f72c9d133aef57ad6b02f248345d90239aapoirier apr_sha1_update(&sha1, buffer, readBytes);
bf380c59be3f235bde21f1c00098e09e3cf7e7aerpluem apr_sha1_final(digest.chr, &sha1);
bf380c59be3f235bde21f1c00098e09e3cf7e7aerpluem /* Print out the SHA1 digest */
81785f72c9d133aef57ad6b02f248345d90239aapoirier ap_rputs("<b>SHA1: </b><code>", r);
5ae30adbe59946de742ab0cd6be3b7457471a698takashi for (n = 0; n < APR_SHA1_DIGESTSIZE/4; n++) {
5ae30adbe59946de742ab0cd6be3b7457471a698takashi ap_rprintf(r, "%08x", digest.num[n]);
bf380c59be3f235bde21f1c00098e09e3cf7e7aerpluem ap_rputs("</code>", r);
0c4abc32c00611fe1d52c9661f5cc79a3f74c6d4nd /* Print a link to the MD5 version */
0c4abc32c00611fe1d52c9661f5cc79a3f74c6d4nd ap_rputs("<br/><a href='?digest=md5'>View the MD5 hash instead</a>", r);
0c4abc32c00611fe1d52c9661f5cc79a3f74c6d4nd apr_file_close(file);
0c4abc32c00611fe1d52c9661f5cc79a3f74c6d4nd /* Let the server know that we responded to this request. */
0c4abc32c00611fe1d52c9661f5cc79a3f74c6d4nd return OK;
0c4abc32c00611fe1d52c9661f5cc79a3f74c6d4nd</highlight>
0c4abc32c00611fe1d52c9661f5cc79a3f74c6d4nd<!-- END EXAMPLE CODE -->
06ba4a61654b3763ad65f52283832ebf058fdf1csliveThis version in its entirety can be found here:
06ba4a61654b3763ad65f52283832ebf058fdf1cslive<a href="http://people.apache.org/~humbedooh/mods/examples/mod_example_2.c">mod_example_2.c</a>.
06ba4a61654b3763ad65f52283832ebf058fdf1cslive<section id="configuration"><title>Adding configuration options</title>
06ba4a61654b3763ad65f52283832ebf058fdf1csliveIn this next segment of this document, we will turn our eyes away from the
4c36c711036219c80d5517d35be68a4769c15291slivedigest module and create a new example module, whose only function is to
4c36c711036219c80d5517d35be68a4769c15291slivewrite out its own configuration. The purpose of this is to examine how
06ba4a61654b3763ad65f52283832ebf058fdf1cslivethe server works with configuration, and what happens when you start writing
4c36c711036219c80d5517d35be68a4769c15291sliveadvanced configurations
0c4abc32c00611fe1d52c9661f5cc79a3f74c6d4ndfor your modules.
fc9f416faa11879811f17d6efadedbf81cfd52a1covener<section id="config_intro"><title>An introduction to configuration
fc9f416faa11879811f17d6efadedbf81cfd52a1covenerdirectives</title>
fc9f416faa11879811f17d6efadedbf81cfd52a1covenerIf you are reading this, then you probably already know
0c4abc32c00611fe1d52c9661f5cc79a3f74c6d4ndwhat a configuration directive is. Simply put, a directive is a way of
0c4abc32c00611fe1d52c9661f5cc79a3f74c6d4ndtelling an individual module (or a set of modules) how to behave, such as
0c4abc32c00611fe1d52c9661f5cc79a3f74c6d4ndthese directives control how <code>mod_rewrite</code> works:
0c4abc32c00611fe1d52c9661f5cc79a3f74c6d4ndRewriteEngine On
0c4abc32c00611fe1d52c9661f5cc79a3f74c6d4nd</highlight>
0c4abc32c00611fe1d52c9661f5cc79a3f74c6d4ndEach of these configuration directives are handled by a separate function,
cea021a7fc2657b091df4d3b031c4254ec371dd7rbowenthat parses the parameters given and sets up a configuration accordingly.
06ba4a61654b3763ad65f52283832ebf058fdf1cslive<section id="config_simple"><title>Making an example configuration</title>
06ba4a61654b3763ad65f52283832ebf058fdf1cslive<p>To begin with, we'll create a basic configuration in C-space:</p>
06ba4a61654b3763ad65f52283832ebf058fdf1cslive<!-- BEGIN EXAMPLE CODE -->
06ba4a61654b3763ad65f52283832ebf058fdf1cslivetypedef struct {
06ba4a61654b3763ad65f52283832ebf058fdf1cslive int enabled; /* Enable or disable our module */
06ba4a61654b3763ad65f52283832ebf058fdf1cslive const char *path; /* Some path to...something */
06ba4a61654b3763ad65f52283832ebf058fdf1cslive int typeOfAction; /* 1 means action A, 2 means action B and so on */
97a9a944b5887e91042b019776c41d5dd74557aferikabele} example_config;
06ba4a61654b3763ad65f52283832ebf058fdf1cslive</highlight>
97a9a944b5887e91042b019776c41d5dd74557aferikabele<!-- END EXAMPLE CODE -->
06ba4a61654b3763ad65f52283832ebf058fdf1csliveNow, let's put this into perspective by creating a very small module that
97a9a944b5887e91042b019776c41d5dd74557aferikabelejust prints out a hard-coded configuration. You'll notice that we use the
06ba4a61654b3763ad65f52283832ebf058fdf1cslive<code>register_hooks</code> function for initializing the configuration
bf380c59be3f235bde21f1c00098e09e3cf7e7aerpluemvalues to their defaults:
06ba4a61654b3763ad65f52283832ebf058fdf1cslive<!-- BEGIN EXAMPLE CODE -->
7992de7f9e82ab86effe3dcc5279fb959f6c398dcovenertypedef struct {
7992de7f9e82ab86effe3dcc5279fb959f6c398dcovener int enabled; /* Enable or disable our module */
7992de7f9e82ab86effe3dcc5279fb959f6c398dcovener const char *path; /* Some path to...something */
06ba4a61654b3763ad65f52283832ebf058fdf1cslive int typeOfAction; /* 1 means action A, 2 means action B and so on */
0ccb6ee166750359937ae35d59c0beb54f8fd228rbowen} example_config;
0ccb6ee166750359937ae35d59c0beb54f8fd228rbowenstatic example_config config;
0ccb6ee166750359937ae35d59c0beb54f8fd228rbowenstatic int example_handler(request_rec *r)
0ccb6ee166750359937ae35d59c0beb54f8fd228rbowen if (!r->handler || strcmp(r->handler, "example-handler")) return(DECLINED);
0ccb6ee166750359937ae35d59c0beb54f8fd228rbowen ap_rprintf(r, "Enabled: %u\n", config.enabled);
0ccb6ee166750359937ae35d59c0beb54f8fd228rbowen ap_rprintf(r, "Path: %s\n", config.path);
0ccb6ee166750359937ae35d59c0beb54f8fd228rbowen ap_rprintf(r, "TypeOfAction: %x\n", config.typeOfAction);
8ac3ff7008df949c096f9cd8f769c7893594f61fnd return OK;
06ba4a61654b3763ad65f52283832ebf058fdf1cslivestatic void register_hooks(apr_pool_t *pool)
790a477f6ce41161c4173c1e5080a1f569976a1erbowen ap_hook_handler(example_handler, NULL, NULL, APR_HOOK_LAST);
790a477f6ce41161c4173c1e5080a1f569976a1erbowen/* Define our module as an entity and assign a function for registering hooks */
790a477f6ce41161c4173c1e5080a1f569976a1erbowenmodule AP_MODULE_DECLARE_DATA example_module =
790a477f6ce41161c4173c1e5080a1f569976a1erbowen STANDARD20_MODULE_STUFF,
790a477f6ce41161c4173c1e5080a1f569976a1erbowen NULL, /* Per-directory configuration handler */
0a3142725875ea286597e083547d34d98f8c1f2drbowen NULL, /* Merge handler for per-directory configurations */
0a3142725875ea286597e083547d34d98f8c1f2drbowen NULL, /* Per-server configuration handler */
790a477f6ce41161c4173c1e5080a1f569976a1erbowen NULL, /* Merge handler for per-server configurations */
0a3142725875ea286597e083547d34d98f8c1f2drbowen NULL, /* Any directives we may have for httpd */
790a477f6ce41161c4173c1e5080a1f569976a1erbowen register_hooks /* Our hook registering function */
0a3142725875ea286597e083547d34d98f8c1f2drbowen</highlight>
790a477f6ce41161c4173c1e5080a1f569976a1erbowen<!-- END EXAMPLE CODE -->
790a477f6ce41161c4173c1e5080a1f569976a1erbowenSo far so good. To access our new handler, we could add the following to
790a477f6ce41161c4173c1e5080a1f569976a1erbowenour configuration:
790a477f6ce41161c4173c1e5080a1f569976a1erbowen<Location /example>
790a477f6ce41161c4173c1e5080a1f569976a1erbowen SetHandler example-handler
790a477f6ce41161c4173c1e5080a1f569976a1erbowen</Location>
0a3142725875ea286597e083547d34d98f8c1f2drbowen</highlight>
06ba4a61654b3763ad65f52283832ebf058fdf1csliveWhen we visit, we'll see our current configuration being spit out by our
0c4abc32c00611fe1d52c9661f5cc79a3f74c6d4nd<section id="register_directive"><title>Registering directives with the server</title>
0203b896e484dfb877111aceffb812401d0f216andWhat if we want to change our configuration, not by hard-coding new values
0c4abc32c00611fe1d52c9661f5cc79a3f74c6d4ndinto the module, but by using either the httpd.conf file or possibly a
0c4abc32c00611fe1d52c9661f5cc79a3f74c6d4nd.htaccess file? It's time to let the server know that we want this to be
0c4abc32c00611fe1d52c9661f5cc79a3f74c6d4ndpossible. To do so, we must first change our <em>name tag</em> to include a
0c4abc32c00611fe1d52c9661f5cc79a3f74c6d4ndreference to the configuration directives we want to register with the server:
0c4abc32c00611fe1d52c9661f5cc79a3f74c6d4nd<!-- BEGIN EXAMPLE CODE -->
06ba4a61654b3763ad65f52283832ebf058fdf1cslivemodule AP_MODULE_DECLARE_DATA example_module =
81785f72c9d133aef57ad6b02f248345d90239aapoirier STANDARD20_MODULE_STUFF,
bf380c59be3f235bde21f1c00098e09e3cf7e7aerpluem NULL, /* Per-directory configuration handler */
06ba4a61654b3763ad65f52283832ebf058fdf1cslive NULL, /* Merge handler for per-directory configurations */
0203b896e484dfb877111aceffb812401d0f216and NULL, /* Per-server configuration handler */
8681ae721fdee17238ebfb7edaeb5c3edc9f1a33nd NULL, /* Merge handler for per-server configurations */
1437d609a6e92c3f32dfdb0d63fce4fd2243fa0frbowen example_directives, /* Any directives we may have for httpd */
1437d609a6e92c3f32dfdb0d63fce4fd2243fa0frbowen register_hooks /* Our hook registering function */
bf380c59be3f235bde21f1c00098e09e3cf7e7aerpluem</highlight>
0203b896e484dfb877111aceffb812401d0f216and<!-- END EXAMPLE CODE -->
a4d04b8c74044c58bd4182028a1408d936c95951covenerThis will tell the server that we are now accepting directives from the
a4d04b8c74044c58bd4182028a1408d936c95951covenerconfiguration files, and that the structure called <code>example_directives
a4d04b8c74044c58bd4182028a1408d936c95951covener</code> holds information on what our directives are and how they work.
a4d04b8c74044c58bd4182028a1408d936c95951covenerSince we have three different variables in our module configuration, we
a4d04b8c74044c58bd4182028a1408d936c95951covenerwill add a structure with three directives and a NULL at the end:
a4d04b8c74044c58bd4182028a1408d936c95951covener<!-- BEGIN EXAMPLE CODE -->
1437d609a6e92c3f32dfdb0d63fce4fd2243fa0frbowenstatic const command_rec example_directives[] =
1437d609a6e92c3f32dfdb0d63fce4fd2243fa0frbowen AP_INIT_TAKE1("exampleEnabled", example_set_enabled, NULL, RSRC_CONF, "Enable or disable mod_example"),
1437d609a6e92c3f32dfdb0d63fce4fd2243fa0frbowen AP_INIT_TAKE1("examplePath", example_set_path, NULL, RSRC_CONF, "The path to whatever"),
1437d609a6e92c3f32dfdb0d63fce4fd2243fa0frbowen AP_INIT_TAKE2("exampleAction", example_set_action, NULL, RSRC_CONF, "Special action value!"),
8681ae721fdee17238ebfb7edaeb5c3edc9f1a33nd</highlight>
8681ae721fdee17238ebfb7edaeb5c3edc9f1a33nd<!-- END EXAMPLE CODE -->
8681ae721fdee17238ebfb7edaeb5c3edc9f1a33nd<img src="/images/build_a_mod_4.png" alt="Directives structure"/><br />
8681ae721fdee17238ebfb7edaeb5c3edc9f1a33ndAs you can see, each directive needs at least 5 parameters set:
0c4abc32c00611fe1d52c9661f5cc79a3f74c6d4nd<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.
8681ae721fdee17238ebfb7edaeb5c3edc9f1a33ndIf 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
0c4abc32c00611fe1d52c9661f5cc79a3f74c6d4ndfor more macros).</li>
0c4abc32c00611fe1d52c9661f5cc79a3f74c6d4nd<li><code>exampleEnabled</code>: This is the name of our directive. More precisely, it is what the user must put in his/her
0c4abc32c00611fe1d52c9661f5cc79a3f74c6d4ndconfiguration in order to invoke a configuration change in our module.</li>
0c4abc32c00611fe1d52c9661f5cc79a3f74c6d4nd<li><code>example_set_enabled</code>: This is a reference to a C function that parses the directive and sets the configuration
0c4abc32c00611fe1d52c9661f5cc79a3f74c6d4ndaccordingly. We will discuss how to make this in the following paragraph.</li>
0c4abc32c00611fe1d52c9661f5cc79a3f74c6d4nd<li><code>RSRC_CONF</code>: This tells the server where the directive is permitted. We'll go into details on this value in the
96147932f199be4ad038778e702c13a2f79051c0slivelater chapters, but for now, <code>RSRC_CONF</code> means that the server will only accept these directives in a server context.</li>
0c4abc32c00611fe1d52c9661f5cc79a3f74c6d4nd<li><code>"Enable or disable...."</code>: This is simply a brief description of what the directive does.</li>
0c4abc32c00611fe1d52c9661f5cc79a3f74c6d4nd(<em>The "missing" parameter in our definition, which is usually set to
0c4abc32c00611fe1d52c9661f5cc79a3f74c6d4nd<code>NULL</code>, is an optional function that can be run after the
06ba4a61654b3763ad65f52283832ebf058fdf1csliveinitial function to parse the arguments have been run. This is usually
81785f72c9d133aef57ad6b02f248345d90239aapoirieromitted, as the function for verifying arguments might as well be used to
bf380c59be3f235bde21f1c00098e09e3cf7e7aerpluemset them.</em>)
06ba4a61654b3763ad65f52283832ebf058fdf1cslive<section id="directive_handler"><title>The directive handler function</title>
630c456b6461158be6cc5c5483735e27b13b4ad5ndNow that we have told the server to expect some directives for our module, it's
37ef4b86270a8e58f87aa5fe558e3e65af97991ccovenertime to make a few functions for handling these. What the server reads in the
8c8c2e71c84babf0e8c4b35819c7c5b3be014cfenoodlconfiguration file(s) is text, and so naturally, what it passes along to
8c8c2e71c84babf0e8c4b35819c7c5b3be014cfenoodlour directive handler is one or more strings, that we ourselves need to
8c8c2e71c84babf0e8c4b35819c7c5b3be014cfenoodlrecognize and act upon. You'll notice, that since we set our <code>
06ba4a61654b3763ad65f52283832ebf058fdf1csliveexampleAction</code> directive to accept two arguments, its C function also
96147932f199be4ad038778e702c13a2f79051c0slivehas an additional parameter defined:</p>
9560125bd44b9d138cb67884b1884401edb1eb85covener<!-- BEGIN EXAMPLE CODE -->
9560125bd44b9d138cb67884b1884401edb1eb85covener/* Handler for the "exampleEnabled" directive */
9560125bd44b9d138cb67884b1884401edb1eb85covenerconst char *example_set_enabled(cmd_parms *cmd, void *cfg, const char *arg)
9560125bd44b9d138cb67884b1884401edb1eb85covener if(!strcasecmp(arg, "on")) config.enabled = 1;
9560125bd44b9d138cb67884b1884401edb1eb85covener return NULL;
96147932f199be4ad038778e702c13a2f79051c0slive/* Handler for the "examplePath" directive */
96147932f199be4ad038778e702c13a2f79051c0sliveconst char *example_set_path(cmd_parms *cmd, void *cfg, const char *arg)
9560125bd44b9d138cb67884b1884401edb1eb85covener return NULL;
9560125bd44b9d138cb67884b1884401edb1eb85covener/* Handler for the "exampleAction" directive */
9dd0b961340554104e5b6e837ddb3101f843cc3fcovener/* Let's pretend this one takes one argument (file or db), and a second (deny or allow), */
9560125bd44b9d138cb67884b1884401edb1eb85covener/* and we store it in a bit-wise manner. */
9560125bd44b9d138cb67884b1884401edb1eb85covenerconst char *example_set_action(cmd_parms *cmd, void *cfg, const char *arg1, const char* arg2)
9560125bd44b9d138cb67884b1884401edb1eb85covener if(!strcasecmp(arg1, "file")) config.typeOfAction = 0x01;
9560125bd44b9d138cb67884b1884401edb1eb85covener if(!strcasecmp(arg2, "deny")) config.typeOfAction += 0x10;
9560125bd44b9d138cb67884b1884401edb1eb85covener return NULL;
9560125bd44b9d138cb67884b1884401edb1eb85covener</highlight>
9560125bd44b9d138cb67884b1884401edb1eb85covener<!-- END EXAMPLE CODE -->
9560125bd44b9d138cb67884b1884401edb1eb85covener<section id="directive_complete"><title>Putting it all together</title>
9560125bd44b9d138cb67884b1884401edb1eb85covenerNow that we have our directives set up, and handlers configured for them,
9560125bd44b9d138cb67884b1884401edb1eb85covenerwe can assemble our module into one big file:
9560125bd44b9d138cb67884b1884401edb1eb85covener<!-- BEGIN EXAMPLE CODE -->
9560125bd44b9d138cb67884b1884401edb1eb85covener#include <stdio.h>
5ae30adbe59946de742ab0cd6be3b7457471a698takashi ==============================================================================
81785f72c9d133aef57ad6b02f248345d90239aapoirier Our configuration prototype and declaration:
bf380c59be3f235bde21f1c00098e09e3cf7e7aerpluem ==============================================================================
06ba4a61654b3763ad65f52283832ebf058fdf1cslivetypedef struct {
06ba4a61654b3763ad65f52283832ebf058fdf1cslive int enabled; /* Enable or disable our module */
06ba4a61654b3763ad65f52283832ebf058fdf1cslive const char *path; /* Some path to...something */
06ba4a61654b3763ad65f52283832ebf058fdf1cslive int typeOfAction; /* 1 means action A, 2 means action B and so on */
bf380c59be3f235bde21f1c00098e09e3cf7e7aerpluem} example_config;
81785f72c9d133aef57ad6b02f248345d90239aapoirierstatic example_config config;
bf380c59be3f235bde21f1c00098e09e3cf7e7aerpluem ==============================================================================
97a9a944b5887e91042b019776c41d5dd74557aferikabele Our directive handlers:
06ba4a61654b3763ad65f52283832ebf058fdf1cslive ==============================================================================
96147932f199be4ad038778e702c13a2f79051c0slive/* Handler for the "exampleEnabled" directive */
96147932f199be4ad038778e702c13a2f79051c0sliveconst char *example_set_enabled(cmd_parms *cmd, void *cfg, const char *arg)
96147932f199be4ad038778e702c13a2f79051c0slive if(!strcasecmp(arg, "on")) config.enabled = 1;
96147932f199be4ad038778e702c13a2f79051c0slive return NULL;
96147932f199be4ad038778e702c13a2f79051c0slive/* Handler for the "examplePath" directive */
96147932f199be4ad038778e702c13a2f79051c0sliveconst char *example_set_path(cmd_parms *cmd, void *cfg, const char *arg)
96147932f199be4ad038778e702c13a2f79051c0slive return NULL;
96147932f199be4ad038778e702c13a2f79051c0slive/* Handler for the "exampleAction" directive */
e00def5e805da9a73b72ad25dac664f0c8c36c2end/* Let's pretend this one takes one argument (file or db), and a second (deny or allow), */
96147932f199be4ad038778e702c13a2f79051c0slive/* and we store it in a bit-wise manner. */
96147932f199be4ad038778e702c13a2f79051c0sliveconst char *example_set_action(cmd_parms *cmd, void *cfg, const char *arg1, const char* arg2)
96147932f199be4ad038778e702c13a2f79051c0slive if(!strcasecmp(arg1, "file")) config.typeOfAction = 0x01;
96147932f199be4ad038778e702c13a2f79051c0slive if(!strcasecmp(arg2, "deny")) config.typeOfAction += 0x10;
96147932f199be4ad038778e702c13a2f79051c0slive return NULL;
96147932f199be4ad038778e702c13a2f79051c0slive ==============================================================================
96147932f199be4ad038778e702c13a2f79051c0slive The directive structure for our name tag:
96147932f199be4ad038778e702c13a2f79051c0slive ==============================================================================
96147932f199be4ad038778e702c13a2f79051c0slivestatic const command_rec example_directives[] =
96147932f199be4ad038778e702c13a2f79051c0slive AP_INIT_TAKE1("exampleEnabled", example_set_enabled, NULL, RSRC_CONF, "Enable or disable mod_example"),
96147932f199be4ad038778e702c13a2f79051c0slive AP_INIT_TAKE1("examplePath", example_set_path, NULL, RSRC_CONF, "The path to whatever"),
96147932f199be4ad038778e702c13a2f79051c0slive AP_INIT_TAKE2("exampleAction", example_set_action, NULL, RSRC_CONF, "Special action value!"),
96147932f199be4ad038778e702c13a2f79051c0slive ==============================================================================
96147932f199be4ad038778e702c13a2f79051c0slive Our module handler:
96147932f199be4ad038778e702c13a2f79051c0slive ==============================================================================
96147932f199be4ad038778e702c13a2f79051c0slivestatic int example_handler(request_rec *r)
06ba4a61654b3763ad65f52283832ebf058fdf1cslive if(!r->handler || strcmp(r->handler, "example-handler")) return(DECLINED);
bf380c59be3f235bde21f1c00098e09e3cf7e7aerpluem ap_rprintf(r, "Enabled: %u\n", config.enabled);
06ba4a61654b3763ad65f52283832ebf058fdf1cslive ap_rprintf(r, "Path: %s\n", config.path);
06ba4a61654b3763ad65f52283832ebf058fdf1cslive ap_rprintf(r, "TypeOfAction: %x\n", config.typeOfAction);
06ba4a61654b3763ad65f52283832ebf058fdf1cslive ==============================================================================
06ba4a61654b3763ad65f52283832ebf058fdf1cslive The hook registration function (also initializes the default config values):
06ba4a61654b3763ad65f52283832ebf058fdf1cslive ==============================================================================
06ba4a61654b3763ad65f52283832ebf058fdf1cslivestatic void register_hooks(apr_pool_t *pool)
06ba4a61654b3763ad65f52283832ebf058fdf1cslive ap_hook_handler(example_handler, NULL, NULL, APR_HOOK_LAST);
06ba4a61654b3763ad65f52283832ebf058fdf1cslive ==============================================================================
06ba4a61654b3763ad65f52283832ebf058fdf1cslive Our module name tag:
bf380c59be3f235bde21f1c00098e09e3cf7e7aerpluem ==============================================================================
bf380c59be3f235bde21f1c00098e09e3cf7e7aerpluemmodule AP_MODULE_DECLARE_DATA example_module =
bf380c59be3f235bde21f1c00098e09e3cf7e7aerpluem STANDARD20_MODULE_STUFF,
bf380c59be3f235bde21f1c00098e09e3cf7e7aerpluem NULL, /* Per-directory configuration handler */
06ba4a61654b3763ad65f52283832ebf058fdf1cslive NULL, /* Merge handler for per-directory configurations */
bf380c59be3f235bde21f1c00098e09e3cf7e7aerpluem NULL, /* Per-server configuration handler */
bf380c59be3f235bde21f1c00098e09e3cf7e7aerpluem NULL, /* Merge handler for per-server configurations */
bf380c59be3f235bde21f1c00098e09e3cf7e7aerpluem example_directives, /* Any directives we may have for httpd */
06ba4a61654b3763ad65f52283832ebf058fdf1cslive register_hooks /* Our hook registering function */
96147932f199be4ad038778e702c13a2f79051c0slive</highlight>
96147932f199be4ad038778e702c13a2f79051c0slive<!-- END EXAMPLE CODE -->
96147932f199be4ad038778e702c13a2f79051c0sliveIn our httpd.conf file, we can now change the hard-coded configuration by
96147932f199be4ad038778e702c13a2f79051c0sliveadding a few lines:
70373b9ee042e7b3be82eee14b17f510fffdacc9sliveExampleEnabled On
bf380c59be3f235bde21f1c00098e09e3cf7e7aerpluemExampleAction file allow
06ba4a61654b3763ad65f52283832ebf058fdf1cslive</highlight>
ee9cda8f648f99a0b889cb0831ba5b1efe6b3eb5rbowenAnd thus we apply the configuration, visit <code>/example</code> on our
545fa9d9188f1ae00e785e784f23e1f0a62b7c25sfweb site, and we see the configuration has adapted to what we wrote in our
ee9cda8f648f99a0b889cb0831ba5b1efe6b3eb5rbowenconfiguration file.
ee9cda8f648f99a0b889cb0831ba5b1efe6b3eb5rbowen<section id="context"><title>Context aware configurations</title>
ee9cda8f648f99a0b889cb0831ba5b1efe6b3eb5rbowen<section id="context_intro"><title>Introduction to context aware configurations</title>
ee9cda8f648f99a0b889cb0831ba5b1efe6b3eb5rbowenIn Apache HTTP Server 2.4, different URLs, virtual hosts, directories etc can have very
ee9cda8f648f99a0b889cb0831ba5b1efe6b3eb5rbowendifferent meanings to the user of the server, and thus different contexts
ee9cda8f648f99a0b889cb0831ba5b1efe6b3eb5rbowenwithin which modules must operate. For example, let's assume you have this
ee9cda8f648f99a0b889cb0831ba5b1efe6b3eb5rbowenconfiguration set up for mod_rewrite:
ee9cda8f648f99a0b889cb0831ba5b1efe6b3eb5rbowen RewriteCond %{HTTP_HOST} ^example.com$
ee9cda8f648f99a0b889cb0831ba5b1efe6b3eb5rbowen RewriteRule (.*) http://www.example.com/$1
ee9cda8f648f99a0b889cb0831ba5b1efe6b3eb5rbowen</Directory>
ee9cda8f648f99a0b889cb0831ba5b1efe6b3eb5rbowen RewriteRule ^foobar$ index.php?foobar=true
590742c95db6e12a810030a36b295271f3228e31rbowen</Directory>
ee9cda8f648f99a0b889cb0831ba5b1efe6b3eb5rbowen</highlight>
ee9cda8f648f99a0b889cb0831ba5b1efe6b3eb5rbowenIn this example, you will have set up two different contexts for
ee9cda8f648f99a0b889cb0831ba5b1efe6b3eb5rbowenmod_rewrite:</p>
4cb65c31bc681540ea623e1cb2bdd09749fb8d7esf<li>Inside <code>/var/www</code>, all requests for <code>http://example.com</code> must go to <code>http://www.example.com</code></li>
39d67f66729a7008c1e73d65a81e778ce819a227rjung<li>Inside <code>/var/www/sub</code>, all requests for <code>foobar</code> must go to <code>index.php?foobar=true</code></li>
ee9cda8f648f99a0b889cb0831ba5b1efe6b3eb5rbowenIf mod_rewrite (or the entire server for that matter) wasn't context aware, then
ee9cda8f648f99a0b889cb0831ba5b1efe6b3eb5rbowenthese rewrite rules would just apply to every and any request made,
ee9cda8f648f99a0b889cb0831ba5b1efe6b3eb5rbowenregardless of where and how they were made, but since the module can pull
ee9cda8f648f99a0b889cb0831ba5b1efe6b3eb5rbowenthe context specific configuration straight from the server, it does not need
ee9cda8f648f99a0b889cb0831ba5b1efe6b3eb5rbowento know itself, which of the directives are valid in this context, since
ee9cda8f648f99a0b889cb0831ba5b1efe6b3eb5rbowenthe server takes care of this.</p>
ee9cda8f648f99a0b889cb0831ba5b1efe6b3eb5rbowenSo how does a module get the specific configuration for the server,
ee9cda8f648f99a0b889cb0831ba5b1efe6b3eb5rbowendirectory or location in question? It does so by making one simple call:
ee9cda8f648f99a0b889cb0831ba5b1efe6b3eb5rbowen<!-- BEGIN EXAMPLE CODE -->
ee9cda8f648f99a0b889cb0831ba5b1efe6b3eb5rbowenexample_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);
ee9cda8f648f99a0b889cb0831ba5b1efe6b3eb5rbowen</highlight>
ee9cda8f648f99a0b889cb0831ba5b1efe6b3eb5rbowen<!-- END EXAMPLE CODE -->
1e6708ac9aebbbd0ff63c2b93e6b97d50263a8bbrbowenThat's it! Of course, a whole lot goes on behind the scenes, which we will
ee9cda8f648f99a0b889cb0831ba5b1efe6b3eb5rbowendiscuss in this chapter, starting with how the server came to know what our
ee9cda8f648f99a0b889cb0831ba5b1efe6b3eb5rbowenconfiguration looks like, and how it came to be set up as it is in the
ee9cda8f648f99a0b889cb0831ba5b1efe6b3eb5rbowenspecific context.
ee9cda8f648f99a0b889cb0831ba5b1efe6b3eb5rbowen<section id="context_base"><title>Our basic configuration setup</title>
ee9cda8f648f99a0b889cb0831ba5b1efe6b3eb5rbowen<p>In this chapter, we will be working with a slightly modified version of
ee9cda8f648f99a0b889cb0831ba5b1efe6b3eb5rbowenour previous context structure. We will set a <code>context</code>
ee9cda8f648f99a0b889cb0831ba5b1efe6b3eb5rbowenvariable that we can use to track which context configuration is being
ee9cda8f648f99a0b889cb0831ba5b1efe6b3eb5rbowenused by the server in various places:
ee9cda8f648f99a0b889cb0831ba5b1efe6b3eb5rbowen<!-- BEGIN EXAMPLE CODE -->
ee9cda8f648f99a0b889cb0831ba5b1efe6b3eb5rbowentypedef struct {
ee9cda8f648f99a0b889cb0831ba5b1efe6b3eb5rbowen char context[256];
ee9cda8f648f99a0b889cb0831ba5b1efe6b3eb5rbowen char path[256];
ee9cda8f648f99a0b889cb0831ba5b1efe6b3eb5rbowen int typeOfAction;
ee9cda8f648f99a0b889cb0831ba5b1efe6b3eb5rbowen int enabled;
ee9cda8f648f99a0b889cb0831ba5b1efe6b3eb5rbowen} example_config;
ee9cda8f648f99a0b889cb0831ba5b1efe6b3eb5rbowen</highlight>
ee9cda8f648f99a0b889cb0831ba5b1efe6b3eb5rbowen<!-- END EXAMPLE CODE -->
ee9cda8f648f99a0b889cb0831ba5b1efe6b3eb5rbowen<p>Our handler for requests will also be modified, yet still very simple:</p>
ee9cda8f648f99a0b889cb0831ba5b1efe6b3eb5rbowen<!-- BEGIN EXAMPLE CODE -->
ee9cda8f648f99a0b889cb0831ba5b1efe6b3eb5rbowenstatic int example_handler(request_rec *r)
ee9cda8f648f99a0b889cb0831ba5b1efe6b3eb5rbowen if(!r->handler || strcmp(r->handler, "example-handler")) return(DECLINED);
ee9cda8f648f99a0b889cb0831ba5b1efe6b3eb5rbowen example_config *config = (example_config*) ap_get_module_config(r->per_dir_config, &example_module);
ee9cda8f648f99a0b889cb0831ba5b1efe6b3eb5rbowen ap_rprintf("Enabled: %u\n", config->enabled);
ee9cda8f648f99a0b889cb0831ba5b1efe6b3eb5rbowen ap_rprintf("Path: %s\n", config->path);
ee9cda8f648f99a0b889cb0831ba5b1efe6b3eb5rbowen ap_rprintf("TypeOfAction: %x\n", config->typeOfAction);
ee9cda8f648f99a0b889cb0831ba5b1efe6b3eb5rbowen ap_rprintf("Context: %s\n", config->context);
ee9cda8f648f99a0b889cb0831ba5b1efe6b3eb5rbowen</highlight>
ee9cda8f648f99a0b889cb0831ba5b1efe6b3eb5rbowen<!-- END EXAMPLE CODE -->
ee9cda8f648f99a0b889cb0831ba5b1efe6b3eb5rbowen<section id="context_which"><title>Choosing a context</title>
ee9cda8f648f99a0b889cb0831ba5b1efe6b3eb5rbowenBefore we can start making our module context aware, we must first define,
ee9cda8f648f99a0b889cb0831ba5b1efe6b3eb5rbowenwhich contexts we will accept. As we saw in the previous chapter, defining
ee9cda8f648f99a0b889cb0831ba5b1efe6b3eb5rbowena directive required five elements be set:</p>
ee9cda8f648f99a0b889cb0831ba5b1efe6b3eb5rbowen<!-- BEGIN EXAMPLE CODE -->
1e6708ac9aebbbd0ff63c2b93e6b97d50263a8bbrbowenAP_INIT_TAKE1("exampleEnabled", example_set_enabled, NULL, RSRC_CONF, "Enable or disable mod_example"),
1e6708ac9aebbbd0ff63c2b93e6b97d50263a8bbrbowen</highlight>
1e6708ac9aebbbd0ff63c2b93e6b97d50263a8bbrbowen<!-- END EXAMPLE CODE -->
1e6708ac9aebbbd0ff63c2b93e6b97d50263a8bbrbowen<p>The <code>RSRC_CONF</code> definition told the server that we would only allow
1e6708ac9aebbbd0ff63c2b93e6b97d50263a8bbrbowenthis directive in a global server context, but since we are now trying out
ee9cda8f648f99a0b889cb0831ba5b1efe6b3eb5rbowena context aware version of our module, we should set this to something
ee9cda8f648f99a0b889cb0831ba5b1efe6b3eb5rbowenmore lenient, namely the value <code>ACCESS_CONF</code>, which lets us use
ee9cda8f648f99a0b889cb0831ba5b1efe6b3eb5rbowenthe directive inside <Directory> and <Location> blocks. For more
ee9cda8f648f99a0b889cb0831ba5b1efe6b3eb5rbowencontrol over the placement of your directives, you can combine the following
ee9cda8f648f99a0b889cb0831ba5b1efe6b3eb5rbowenrestrictions together to form a specific rule:
ee9cda8f648f99a0b889cb0831ba5b1efe6b3eb5rbowen<li><code>RSRC_CONF</code>: Allow in .conf files (not .htaccess) outside <Directory> or <Location></li>
ee9cda8f648f99a0b889cb0831ba5b1efe6b3eb5rbowen<li><code>ACCESS_CONF</code>: Allow in .conf files (not .htaccess) inside <Directory> or <Location></li>
ee9cda8f648f99a0b889cb0831ba5b1efe6b3eb5rbowen<li><code>OR_OPTIONS</code>: Allow in .conf files and .htaccess when <code>AllowOverride Options</code> is set</li>
ee9cda8f648f99a0b889cb0831ba5b1efe6b3eb5rbowen<li><code>OR_FILEINFO</code>: Allow in .conf files and .htaccess when <code>AllowOverride FileInfo</code> is set</li>
ff21ab9f1cc3037fe58a2029432834581594b6c4pctony<li><code>OR_AUTHCFG</code>: Allow in .conf files and .htaccess when <code>AllowOverride AuthConfig</code> is set</li>
de68ca33425122cf4a880859013e08e84f8143a5covener<li><code>OR_INDEXES</code>: Allow in .conf files and .htaccess when <code>AllowOverride Indexes</code> is set</li>
de68ca33425122cf4a880859013e08e84f8143a5covener<li><code>OR_ALL</code>: Allow anywhere in .conf files and .htaccess</li>
de68ca33425122cf4a880859013e08e84f8143a5covener<section id="context_pool"><title>Using the server to allocate configuration slots</title>
de68ca33425122cf4a880859013e08e84f8143a5covener<p> A much smarter way to manage your configurations is by letting the server
de68ca33425122cf4a880859013e08e84f8143a5covenerhelp you create them. To do so, we must first start off by changing our
de68ca33425122cf4a880859013e08e84f8143a5covener<em>name tag</em> to let the server know, that it should assist us in creating
de68ca33425122cf4a880859013e08e84f8143a5covenerand managing our configurations. Since we have chosen the per-directory
de68ca33425122cf4a880859013e08e84f8143a5covener(or per-location) context for our module configurations, we'll add a
06ba4a61654b3763ad65f52283832ebf058fdf1csliveper-directory creator and merger function reference in our tag:</p>
06ba4a61654b3763ad65f52283832ebf058fdf1cslive<!-- BEGIN EXAMPLE CODE -->
06ba4a61654b3763ad65f52283832ebf058fdf1cslivemodule AP_MODULE_DECLARE_DATA example_module =
06ba4a61654b3763ad65f52283832ebf058fdf1cslive STANDARD20_MODULE_STUFF,
97a9a944b5887e91042b019776c41d5dd74557aferikabele create_dir_conf, /* Per-directory configuration handler */
06ba4a61654b3763ad65f52283832ebf058fdf1cslive merge_dir_conf, /* Merge handler for per-directory configurations */
06ba4a61654b3763ad65f52283832ebf058fdf1cslive NULL, /* Per-server configuration handler */
34212fdb21f03f4e180a3226f83e39af0371d7dbrbowen NULL, /* Merge handler for per-server configurations */
34212fdb21f03f4e180a3226f83e39af0371d7dbrbowen directives, /* Any directives we may have for httpd */
34212fdb21f03f4e180a3226f83e39af0371d7dbrbowen register_hooks /* Our hook registering function */
34212fdb21f03f4e180a3226f83e39af0371d7dbrbowen</highlight>
34212fdb21f03f4e180a3226f83e39af0371d7dbrbowen<!-- END EXAMPLE CODE -->
34212fdb21f03f4e180a3226f83e39af0371d7dbrbowen<section id="context_new"><title>Creating new context configurations</title>
34212fdb21f03f4e180a3226f83e39af0371d7dbrbowenNow that we have told the server to help us create and manage configurations,
34212fdb21f03f4e180a3226f83e39af0371d7dbrbowenour first step is to make a function for creating new, blank
34212fdb21f03f4e180a3226f83e39af0371d7dbrbowenconfigurations. We do so by creating the function we just referenced in
34212fdb21f03f4e180a3226f83e39af0371d7dbrbowenour name tag as the Per-directory configuration handler:</p>
34212fdb21f03f4e180a3226f83e39af0371d7dbrbowen<!-- BEGIN EXAMPLE CODE -->
34212fdb21f03f4e180a3226f83e39af0371d7dbrbowenvoid* example_create_dir_conf(apr_pool_t* pool, char* context) {
34212fdb21f03f4e180a3226f83e39af0371d7dbrbowen context = context ? context : "(undefined context)";
34212fdb21f03f4e180a3226f83e39af0371d7dbrbowen example_config *cfg = apr_pcalloc(pool, sizeof(example_config));
34212fdb21f03f4e180a3226f83e39af0371d7dbrbowen /* Set some default values */
34212fdb21f03f4e180a3226f83e39af0371d7dbrbowen strcpy(cfg->context, x);
34212fdb21f03f4e180a3226f83e39af0371d7dbrbowen cfg->enabled = 0;
34212fdb21f03f4e180a3226f83e39af0371d7dbrbowen cfg->typeOfAction = 0x11;
34212fdb21f03f4e180a3226f83e39af0371d7dbrbowen return cfg;
34212fdb21f03f4e180a3226f83e39af0371d7dbrbowen</highlight>
34212fdb21f03f4e180a3226f83e39af0371d7dbrbowen<!-- END EXAMPLE CODE -->
34212fdb21f03f4e180a3226f83e39af0371d7dbrbowen<section id="context_merge"><title>Merging configurations</title>
34212fdb21f03f4e180a3226f83e39af0371d7dbrbowenOur next step in creating a context aware configuration is merging
34212fdb21f03f4e180a3226f83e39af0371d7dbrbowenconfigurations. This part of the process particularly applies to scenarios
34212fdb21f03f4e180a3226f83e39af0371d7dbrbowenwhere you have a parent configuration and a child, such as the following:
34212fdb21f03f4e180a3226f83e39af0371d7dbrbowen ExampleEnabled On
34212fdb21f03f4e180a3226f83e39af0371d7dbrbowen ExampleAction file allow
34212fdb21f03f4e180a3226f83e39af0371d7dbrbowen</Directory>
34212fdb21f03f4e180a3226f83e39af0371d7dbrbowen ExampleAction file deny
34212fdb21f03f4e180a3226f83e39af0371d7dbrbowen</Directory>
34212fdb21f03f4e180a3226f83e39af0371d7dbrbowen</highlight>
34212fdb21f03f4e180a3226f83e39af0371d7dbrbowenIn this example, it is natural to assume that the directory <code>
34212fdb21f03f4e180a3226f83e39af0371d7dbrbowen/var/www/subdir</code> should inherit the values set for the <code>/var/www
34212fdb21f03f4e180a3226f83e39af0371d7dbrbowen</code> directory, as we did not specify an <code>ExampleEnabled</code> nor
34212fdb21f03f4e180a3226f83e39af0371d7dbrbowenan <code>ExamplePath</code> for this directory. The server does not presume to
34212fdb21f03f4e180a3226f83e39af0371d7dbrbowenknow if this is true, but cleverly does the following:
34212fdb21f03f4e180a3226f83e39af0371d7dbrbowen<li>Creates a new configuration for <code>/var/www</code></li>
34212fdb21f03f4e180a3226f83e39af0371d7dbrbowen<li>Sets the configuration values according to the directives given for <code>/var/www</code></li>
34212fdb21f03f4e180a3226f83e39af0371d7dbrbowen<li>Creates a new configuration for <code>/var/www/subdir</code></li>
34212fdb21f03f4e180a3226f83e39af0371d7dbrbowen<li>Sets the configuration values according to the directives given for <code>/var/www/subdir</code></li>
34212fdb21f03f4e180a3226f83e39af0371d7dbrbowen<li><strong>Proposes a merge</strong> of the two configurations into a new configuration for <code>/var/www/subdir</code></li>
97a9a944b5887e91042b019776c41d5dd74557aferikabeleThis proposal is handled by the <code>merge_dir_conf</code> function we
bf380c59be3f235bde21f1c00098e09e3cf7e7aerpluemreferenced in our name tag. The purpose of this function is to assess the
97a9a944b5887e91042b019776c41d5dd74557aferikabeletwo configurations and decide how they are to be merged:</p>
06ba4a61654b3763ad65f52283832ebf058fdf1cslive<!-- BEGIN EXAMPLE CODE -->
34212fdb21f03f4e180a3226f83e39af0371d7dbrbowenvoid* merge_dir_conf(apr_pool_t* pool, void* BASE, void* ADD) {
34212fdb21f03f4e180a3226f83e39af0371d7dbrbowen example_config* base = (example_config *) BASE ; /* This is what was set in the parent context */
34212fdb21f03f4e180a3226f83e39af0371d7dbrbowen example_config* add = (example_config *) ADD ; /* This is what is set in the new context */
34212fdb21f03f4e180a3226f83e39af0371d7dbrbowen example_config* conf = (example_config *) create_dir_conf(pool, "Merged configuration"); /* This will be the merged configuration */
34212fdb21f03f4e180a3226f83e39af0371d7dbrbowen /* Merge configurations */
34212fdb21f03f4e180a3226f83e39af0371d7dbrbowen conf->enabled = ( add->enabled == 0 ) ? base->enabled : add->enabled ;
34212fdb21f03f4e180a3226f83e39af0371d7dbrbowen conf->typeOfAction = add->typeOfAction ? add->typeOfAction : base->typeOfAction;
34212fdb21f03f4e180a3226f83e39af0371d7dbrbowen strcpy(conf->path, strlen(add->path) ? add->path : base->path);
34212fdb21f03f4e180a3226f83e39af0371d7dbrbowen return conf ;
34212fdb21f03f4e180a3226f83e39af0371d7dbrbowen</highlight>
34212fdb21f03f4e180a3226f83e39af0371d7dbrbowen<!-- END EXAMPLE CODE -->
34212fdb21f03f4e180a3226f83e39af0371d7dbrbowen<section id="context_example"><title>Trying out our new context aware configurations</title>
34212fdb21f03f4e180a3226f83e39af0371d7dbrbowenNow, let's try putting it all together to create a new module that is
34212fdb21f03f4e180a3226f83e39af0371d7dbrbowencontext aware. First off, we'll create a configuration that lets us test
34212fdb21f03f4e180a3226f83e39af0371d7dbrbowenhow the module works:
34212fdb21f03f4e180a3226f83e39af0371d7dbrbowen<Location "/a">
34212fdb21f03f4e180a3226f83e39af0371d7dbrbowen SetHandler example-handler
34212fdb21f03f4e180a3226f83e39af0371d7dbrbowen ExampleEnabled on
34212fdb21f03f4e180a3226f83e39af0371d7dbrbowen ExampleAction file allow
34212fdb21f03f4e180a3226f83e39af0371d7dbrbowen</Location>
34212fdb21f03f4e180a3226f83e39af0371d7dbrbowen<Location "/a/b">
34212fdb21f03f4e180a3226f83e39af0371d7dbrbowen ExampleAction file deny
34212fdb21f03f4e180a3226f83e39af0371d7dbrbowen ExampleEnabled off
34212fdb21f03f4e180a3226f83e39af0371d7dbrbowen</Location>
34212fdb21f03f4e180a3226f83e39af0371d7dbrbowen<Location "/a/b/c">
34212fdb21f03f4e180a3226f83e39af0371d7dbrbowen ExampleAction db deny
34212fdb21f03f4e180a3226f83e39af0371d7dbrbowen ExampleEnabled on
34212fdb21f03f4e180a3226f83e39af0371d7dbrbowen</Location>
34212fdb21f03f4e180a3226f83e39af0371d7dbrbowen</highlight>
34212fdb21f03f4e180a3226f83e39af0371d7dbrbowenThen we'll assemble our module code. Note, that since we are now using our
34212fdb21f03f4e180a3226f83e39af0371d7dbrbowenname tag as reference when fetching configurations in our handler, I have
34212fdb21f03f4e180a3226f83e39af0371d7dbrbowenadded some prototypes to keep the compiler happy:
34212fdb21f03f4e180a3226f83e39af0371d7dbrbowen<!-- BEGIN EXAMPLE CODE -->
34212fdb21f03f4e180a3226f83e39af0371d7dbrbowen +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
34212fdb21f03f4e180a3226f83e39af0371d7dbrbowen +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
34212fdb21f03f4e180a3226f83e39af0371d7dbrbowen#include <stdio.h>
0c4abc32c00611fe1d52c9661f5cc79a3f74c6d4nd ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
0c4abc32c00611fe1d52c9661f5cc79a3f74c6d4nd Configuration structure
0c4abc32c00611fe1d52c9661f5cc79a3f74c6d4nd ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
7dc5a2d4a0c77f5bf5a95de92d68e43de7d8117anilguntypedef struct
9c1260efa52c82c2a58e5b5f20cd6902563d95f5rbowen char context[256];
0c4abc32c00611fe1d52c9661f5cc79a3f74c6d4nd char path[256];
0c0b2cdbccd4ddc8f07574c36444bf9a795a3e1cjim int typeOfAction;
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
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);
/*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
=======================================================================================================================
=======================================================================================================================
=======================================================================================================================
=======================================================================================================================
=======================================================================================================================
=======================================================================================================================
=======================================================================================================================
=======================================================================================================================
=======================================================================================================================
=======================================================================================================================