
humbedooh at apache
Apr 13, 2012, 11:58 PM
Post #1 of 1
(24 views)
Permalink
|
|
svn commit: r1326061 [2/3] - in /httpd/httpd/branches/2.4.x/docs/manual/developer: documenting.xml.zh-cn modguide.html modguide.html.en modguide.xml.meta
|
|
Added: httpd/httpd/branches/2.4.x/docs/manual/developer/modguide.html.en URL: http://svn.apache.org/viewvc/httpd/httpd/branches/2.4.x/docs/manual/developer/modguide.html.en?rev=1326061&view=auto ============================================================================== --- httpd/httpd/branches/2.4.x/docs/manual/developer/modguide.html.en (added) +++ httpd/httpd/branches/2.4.x/docs/manual/developer/modguide.html.en Sat Apr 14 06:58:16 2012 @@ -0,0 +1,1664 @@ +<?xml version="1.0" encoding="ISO-8859-1"?> +<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd"> +<html xmlns="http://www.w3.org/1999/xhtml" lang="en" xml:lang="en"><head><!-- + XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX + This file is generated from xml source: DO NOT EDIT + XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX + --> +<title>Developing modules for the Apache HTTP Server 2.4 - Apache HTTP Server</title> +<link href="../style/css/manual.css" rel="stylesheet" media="all" type="text/css" title="Main stylesheet" /> +<link href="../style/css/manual-loose-100pc.css" rel="alternate stylesheet" media="all" type="text/css" title="No Sidebar - Default font size" /> +<link href="../style/css/manual-print.css" rel="stylesheet" media="print" type="text/css" /> +<link href="../images/favicon.ico" rel="shortcut icon" /></head> +<body id="manual-page"><div id="page-header"> +<p class="menu"><a href="../mod/">Modules</a> | <a href="../mod/directives.html">Directives</a> | <a href="../faq/">FAQ</a> | <a href="../glossary.html">Glossary</a> | <a href="../sitemap.html">Sitemap</a></p> +<p class="apache">Apache HTTP Server Version 2.4</p> +<img alt="" src="../images/feather.gif" /></div> +<div class="up"><a href="./"><img title="<-" alt="<-" src="../images/left.gif" /></a></div> +<div id="path"> +<a href="http://www.apache.org/">Apache</a> > <a href="http://httpd.apache.org/">HTTP Server</a> > <a href="http://httpd.apache.org/docs/">Documentation</a> > <a href="../">Version 2.4</a> > <a href="./">Developer</a></div><div id="page-content"><div id="preamble"><h1>Developing modules for the Apache HTTP Server 2.4</h1> +<div class="toplang"> +<p><span>Available Languages: </span><a href="../en/developer/modguide.html" title="English"> en </a></p> +</div> + +<p>This document explains how you can develop modules for the Apache HTTP +Server 2.4</p> +</div> +<div id="quickview"><ul id="toc"><li><img alt="" src="../images/down.gif" /> <a href="#introduction">Introduction</a></li> +<li><img alt="" src="../images/down.gif" /> <a href="#basics">Defining a module</a></li> +<li><img alt="" src="../images/down.gif" /> <a href="#hooking">Getting started: Hooking into Apache</a></li> +<li><img alt="" src="../images/down.gif" /> <a href="#handling">Building a handler</a></li> +<li><img alt="" src="../images/down.gif" /> <a href="#configuration">Adding configuration options</a></li> +<li><img alt="" src="../images/down.gif" /> <a href="#context">Context aware configurations</a></li> +<li><img alt="" src="../images/down.gif" /> <a href="#summary">Summing up</a></li> +<li><img alt="" src="../images/down.gif" /> <a href="#snippets">Some useful snippets of code</a></li> +</ul><h3>See also</h3><ul class="seealso"><li><a href="request.html">Request Processing in Apache 2.4</a></li><li><a href="hooks.html">Apache 2.x Hook Functions</a></li></ul></div> +<div class="top"><a href="#page-header"><img alt="top" src="../images/up.gif" /></a></div> +<div class="section"> +<h2><a name="introduction" id="introduction">Introduction</a></h2> +<h3><a name="what" id="what">What we will be discussing in this document</a></h3> +<p> +This document will discuss how you can easily create modules for the Apache +HTTP Server 2.4 ("Apache"), by exploring an example module called +<code>mod_example</code>. In the first part of this document, the purpose +of this module will be to calculate and print out various digest values for +existing files on your web server, whenever we access the URL <code> +http://hostname/filename.sum</code>. For instance, if we want to know the +MD5 digest value of the file located at <code> +http://www.example.com/index.html</code>, we would visit <code> +http://www.example.com/index.html.sum</code>. +</p> +<p> +In the second part of this document, which deals with configuration +directive and context awareness, we will be looking at a module that simply +write out its own configuration to the client. +</p> + +<h3><a name="prerequisites" id="prerequisites">Prerequisites</a></h3> +<p> +First and foremost, you are expected to have a basic knowledge of how the C +programming language works. In most cases, we will try to be as pedagogical +as possible and link to documents describing the functions used in the +examples, but there are also many cases where it is necessary to either +just assume that "it works" or do some digging youself into what the hows +and whys of various function calls. +</p> +<p> +Lastly, you will need to have a basic understanding of how modules are +loaded and configured in Apache, as well as how to get the headers for +Apache if you do not have them already, as these are needed for compiling +new modules. +</p> + +<h3><a name="compiling" id="compiling">Compiling your module</a></h3> +<p> +To compile the source code we are building in this document, we will be +using <a href="../programs/apxs.html">APXS</a>. Assuming your source file +is called mod_example.c, compiling, installing and activating the module is +as simple as: +<div class="example"><pre> +apxs -i -a -c mod_example.c +</pre></div> +</p> + +</div><div class="top"><a href="#page-header"><img alt="top" src="../images/up.gif" /></a></div> +<div class="section"> +<h2><a name="basics" id="basics">Defining a module</a></h2> +<img src="../images/build_a_mod_3.png" /><br /> +<p>Every module starts with the same declaration, or name tag if you will, +that defines a module as <em>a separate entity within Apache</em>: + + + +<pre style="color:#000000;background:#ffffef;border: 1px dashed #333; padding: 0.5em; margin: 1em 2em 1em 1em;"> +module AP_MODULE_DECLARE_DATA example_module <code style="color:#806030; ">=</code> +<code style="color:#806030; ">{</code> + STANDARD20_MODULE_STUFF<code style="color:#806030; ">,</code> + create_dir_conf<code style="color:#806030; ">,</code> <code style="color:#c34e00; ">/* Per-directory configuration handler */</code> + merge_dir_conf<code style="color:#806030; ">,</code> <code style="color:#c34e00; ">/* Merge handler for per-directory configurations */</code> + create_svr_conf<code style="color:#806030; ">,</code> <code style="color:#c34e00; ">/* Per-server configuration handler */</code> + merge_svr_conf<code style="color:#806030; ">,</code> <code style="color:#c34e00; ">/* Merge handler for per-server configurations */</code> + directives<code style="color:#806030; ">,</code> <code style="color:#c34e00; ">/* Any directives we may have for httpd */</code> + register_hooks <code style="color:#c34e00; ">/* Our hook registering function */</code> +<code style="color:#806030; ">}</code><code style="color:#806030; ">;</code> +</pre> + + + +This bit of code lets Apache know that we have now registered a new module +in the system, and that its name is <code>example_module</code>. The name +of the module is used primarilly for two things:<br /> +<ul> +<li>Letting Apache know how to load the module using the LoadModule</li> +<li>Setting up a namespace for the module to use in configurations</li> +</ul> +For now, we're only concerned with the first purpose of the module name, +which comes into play when we need to load the module:<br /> +<div class="example"><pre><a href="../mod/mod_so.html#LoadModule">LoadModule</a> example_module modules/mod_example.so</pre></div> +In essence, this tells Apache to open up <code>mod_example.so</code> and look for a module +called <code>example_module</code>. +</p> +<p> +Within this name tag of ours is also a bunch of references to how we would +like to handle things: Which directives do we respond to in a configuration +file or .htaccess, how do we operate within specific contexts, and what +handlers are we interested in registering with the Apache service. We'll +return to all these elements later in this document. +</p> +</div><div class="top"><a href="#page-header"><img alt="top" src="../images/up.gif" /></a></div> +<div class="section"> +<h2><a name="hooking" id="hooking">Getting started: Hooking into Apache</a></h2> +<h3><a name="hook_intro" id="hook_intro">An introduction to hooks</a></h3> +<p> +When handling requests in Apache, the first thing you will need to do is +create a hook into the request handling process. A hook is essentially a +message telling Apache that you are willing to either serve or at least +take a glance at certain requests given by clients. All handlers, whether +it's mod_rewrite, mod_authn_*, mod_proxy and so on, are hooked into +specific parts of the request process. As you are probably aware, modules +serve different purposes; Some are authentication/authorization handlers, +others are file or script handlers while some third modules rewrite URIs or +proxies content. Furthermore, in the end, it is up to the user of Apache +how and when each module will come into place. Thus, Apache itself does not +presume to know which module is responsible for handling a specific +request, and will ask each module whether they have an interest in a given +request or not. It is then up to each module to either gently decline +serving a request, accept serving it or flat out deny the request from +being served, as authentication/authorization modules do: <br /> +<img src="../images/build_a_mod_2.png" /><br /> +To make it a bit easier for handlers such as our mod_example to know +whether the client is requesting content we should handle or not, Apache +has directives for hinting to modules whether their assistance is needed or +not. Two of these are <code class="directive"><a href="../mod/mod_mime.html#addhandler">AddHandler</a></code> +and <code class="directive"><a href="../mod/core.html#sethandler">SetHandler</a></code>. Let's take a look at +an example using <code class="directive"><a href="../mod/mod_mime.html#addhandler">AddHandler</a></code>. In +our example case, we want every request ending with .sum to be served by +<code>mod_example</code>, so we'll add a configuration directive that tells +Apache to do just that: +<div class="example"><pre> +AddHandler example-handler .sum +</pre></div> +What this tells Apache is the following: <em>Whenever we receive a request +for a URI ending in .sum, we are to let all modules know that we are +looking for whoever goes by the name of "example-handler" </em>. +Thus, when a request is being served that ends in .sum, Apache will let all +modules know, that this request should be served by "example-handler +". As you will see later, when we start building mod_example, we will +check for this handler tag relayed by <code>AddHandler</code> and reply to +Apache based on the value of this tag. +</p> + +<h3><a name="hook_declaration" id="hook_declaration">Hooking into httpd</a></h3> +<p> +To begin with, we only want to create a simple handler, that replies to the +client browser when a specific URL is requested, so we won't bother setting +up configuration handlers and directives just yet. Our initial module +definition will look like this:<br /> + + + +<pre style="color:#000000;background:#ffffef;border: 1px dashed #333; padding: 0.5em; margin: 1em 2em 1em 1em;"> +module AP_MODULE_DECLARE_DATA example_module = +{ + STANDARD20_MODULE_STUFF, + <code style="color:#7f0055; font-weight:bold; ">NULL</code>, + <code style="color:#7f0055; font-weight:bold; ">NULL</code>, + <code style="color:#7f0055; font-weight:bold; ">NULL</code>, + <code style="color:#7f0055; font-weight:bold; ">NULL</code>, + <code style="color:#7f0055; font-weight:bold; ">NULL</code>, + <code style="color:#800040; ">register_hooks</code> <code style="color:#c34e00; "><code style="color:#c34e00; ">/* Our hook registering function */</code></code> +}; +</pre> + + + +This lets Apache know that we are not interesting in anything fancy, we +just want to hook onto the requests and possibly handle some of them. </p> +<p> The reference in our example declaration, <code>register_hooks</code> +is the name of a function we will create to manage how we hook onto the +request process. In this example module, the function has just one purpose; +To create a simple hook that gets called after all the rewrites, access +control etc has been handled. Thus, we will let Apache know, that we want +to hook into its process as one of the last modules: + + + +<pre style="color:#000000;background:#ffffef;border: 1px dashed #333; padding: 0.5em; margin: 1em 2em 1em 1em;"> +<code style="color:#400000; font-weight:bold; ">static</code> <code style="color:#400000; font-weight:bold; ">void</code> register_hooks<code style="color:#806030; ">(</code>apr_pool_t <code style="color:#806030; ">*</code>pool<code style="color:#806030; ">)</code> +<code style="color:#806030; ">{</code> + <code style="color:#c34e00; ">/* Create a hook in the request handler, so we get called when a request arrives */</code> + <code style="color:#800040; ">ap_hook_handler</code><code style="color:#806030; ">(</code>example_handler<code style="color:#806030; ">,</code> <code style="color:#7f0055; font-weight:bold; ">NULL</code><code style="color:#806030; ">,</code> <code style="color:#7f0055; font-weight:bold; ">NULL</code><code style="color:#806030; ">,</code> APR_HOOK_LAST<code style="color:#806030; ">)</code><code style="color:#806030; ">;</code> +<code style="color:#806030; ">}</code> +</pre> + + + +The <code>example_handler</code> reference is the function that will handle +the request. We will discuss how to create a handler in the next chapter. +</p> + +<h3><a name="hook_others" id="hook_others">Other useful hooks</a></h3> +<p> +Hooking into the request handling phase is but one of many hooks that you +can create. Some other ways of hooking are: +<ul> +<li><code>ap_hook_child_init</code>: Place a hook that executes when a child process is spawned (commonly used for initializing modules after Apache 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 Apache 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> +</ul> +</p> + +</div><div class="top"><a href="#page-header"><img alt="top" src="../images/up.gif" /></a></div> +<div class="section"> +<h2><a name="handling" id="handling">Building a handler</a></h2> +<p> +A handler is essentially a function that receives a callback when a request +to Apache is made. It is passed a record of the current request (how it was +made, which headers and requests were passed along, who's giving the +request and so on), and is put in charge of either telling Apache that it's +not interested in the request or handle the request with the tools provided. +</p> +<h3><a name="simple_handler" id="simple_handler">A simple "Hello, world!" +handler</a></h3> Let's start off by making a very simple request handler +that does the following: <br /> +<ol> +<li>Check that this is a request that should be served by "example-handler"</li> +<li>Set the content type of our output to <code>text/html</code></li> +<li>Write "Hello, world!" back to the client browser</li> +<li>Let Apache know that we took care of this request and everything went fine</li> +</ol> +In C code, our example handler will now look like this:<br /> + + + +<pre style="color:#000000;background:#ffffef;border: 1px dashed #333; padding: 0.5em; margin: 1em 2em 1em 1em;"> +<code style="color:#400000; font-weight:bold; ">static</code> <code style="color:#400000; font-weight:bold; ">int</code> example_handler<code style="color:#806030; ">(</code>request_rec <code style="color:#806030; ">*</code>r<code style="color:#806030; ">)</code> +<code style="color:#806030; ">{</code> + <code style="color:#c34e00; ">/* First off, we need to check if this is a call for the "example-handler" handler.</code> +<code style="color:#c34e00; "> * If it is, we accept it and do our things, if not, we simply return DECLINED,</code> +<code style="color:#c34e00; "> * and Apache will try somewhere else.</code> +<code style="color:#c34e00; "> */</code> + <code style="color:#400000; font-weight:bold; ">if</code> <code style="color:#806030; ">(</code><code style="color:#806030; ">!</code>r<code style="color:#806030; ">-</code><code style="color:#806030; ">></code><code style="color:#008833">handler</code> <code style="color:#806030; ">|</code><code style="color:#806030; ">|</code> <code style="color:#800040; ">strcmp</code><code style="color:#806030; ">(</code>r<code style="color:#806030; ">-</code><code style="color:#806030; ">></code><code style="color:#008833">handler</code><code style="color:#806030; ">,</code> <code style="color:#800000; ">"</code><code style="color:#e60000; ">example-handler</code><code style="color:#800000; ">"</code><code style="color:#806030; ">)</code><code style="color:#806030; ">)</code> <code style="color:#400000; font-weight:bold; ">return</code> <code style="color:#806030; ">(</code>DECLINED<code style="color:#806030; ">)</code><code style="color:#806030; ">;</code> + + <code style="color:#c34e00; ">/* Now that we are handling this request, we'll write out "Hello, world!" to the client.</code> +<code style="color:#c34e00; "> * To do so, we must first set the appropriate content type, followed by our output.</code> +<code style="color:#c34e00; "> */</code> + <a href="http://ci.apache.org/projects/httpd/trunk/doxygen/group__APACHE__CORE__PROTO.html#gaa2f8412c400197338ec509f4a45e4579">ap_set_content_type</a><code style="color:#806030; ">(</code>r<code style="color:#806030; ">,</code> <code style="color:#800000; ">"</code><code style="color:#e60000; ">text/html</code><code style="color:#800000; ">"</code><code style="color:#806030; ">)</code><code style="color:#806030; ">;</code> + <a href="http://ci.apache.org/projects/httpd/trunk/doxygen/group__APACHE__CORE__PROTO.html#ga5e91eb6ca777c9a427b2e82bf1eeb81d">ap_rprintf</a><code style="color:#806030; ">(</code>r<code style="color:#806030; ">,</code> <code style="color:#800000; ">"</code><code style="color:#e60000; ">Hello, world!</code><code style="color:#800000; ">"</code><code style="color:#806030; ">)</code><code style="color:#806030; ">;</code> + + <code style="color:#c34e00; ">/* Lastly, we must tell Apache that we took care of this request and everything went fine.</code> +<code style="color:#c34e00; "> * We do so by simply returning the value OK to Apache.</code> +<code style="color:#c34e00; "> */</code> + <code style="color:#400000; font-weight:bold; ">return</code> OK<code style="color:#806030; ">;</code> +<code style="color:#806030; ">}</code> +</pre> + + + +Now, we put all we have learned together and end up with a program that +looks like +<a href="http://people.apache.org/~humbedooh/mods/examples/mod_example_1.c">mod_example_1.c</a> +. The functions used in this example will be explained later in the section +<a href="#functions">"Some useful functions you should know"</a> +. <h3><a name="request_rec" id="request_rec">The request_rec structure +</a></h3> <p>The most essential part of any request is the <em>request record +</em>. In a call to a handler function, this is represented by the <code> +request_req* </code> structure passed along with every call that is made. +This struct, typically just refered to as <code>r</code> in modules, +contains all the information you need for your module to fully process any +HTTP request and respond accordingly.</p> <p>Some key elements of the <code> +request_req </code> structure are: +<ul> +<li><code><code style="color:#008833">r->handler</code> (char*)</code>: Contains the name of the handler Apache is currently asking to do the handling of this request</li> +<li><code><code style="color:#008833">r->method</code> (char*)</code>: Contains the HTTP method being used, f.x. GET or POST</li> +<li><code><code style="color:#008833">r->filename</code> (char*)</code>: Contains the translated filename the client is requesting</li> +<li><code><code style="color:#008833">r->args</code> (char*)</code>: Contains the query string of the request, if any</li> +<li><code><code style="color:#008833">r->headers_in</code> (apr_table_t*)</code>: Contains all the headers sent by the client</li> +<li><code><code style="color:#008833">r->connection</code> (conn_rec*)</code>: A record containing information about the current connection</li> +<li><code><code style="color:#008833">r->useragent_ip</code> (char*)</code>: The IP address of the client connecting to us</li> +<li><code><code style="color:#008833">r->pool</code> (apr_pool_t*)</code>: The memory pool of this request. We'll discuss this in the " +<a href="#memory">Memory management</a>" chapter.</li> +</ul> +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>. +</p> +<p> +Let's try out some of these variables in another example handler:<br /> + + + +<pre style="color:#000000;background:#ffffef;border: 1px dashed #333; padding: 0.5em; margin: 1em 2em 1em 1em;"> +<code style="color:#400000; font-weight:bold; ">static</code> <code style="color:#400000; font-weight:bold; ">int</code> example_handler<code style="color:#806030; ">(</code>request_rec <code style="color:#806030; ">*</code>r<code style="color:#806030; ">)</code> +<code style="color:#806030; ">{</code> + <code style="color:#c34e00; ">/* Set the appropriate content type */</code> + <a href="http://ci.apache.org/projects/httpd/trunk/doxygen/group__APACHE__CORE__PROTO.html#gaa2f8412c400197338ec509f4a45e4579">ap_set_content_type</a><code style="color:#806030; ">(</code>r<code style="color:#806030; ">,</code> <code style="color:#800000; ">"</code><code style="color:#e60000; ">text/html</code><code style="color:#800000; ">"</code><code style="color:#806030; ">)</code><code style="color:#806030; ">;</code> + + <code style="color:#c34e00; ">/* Print out the IP address of the client connecting to us: */</code> + <a href="http://ci.apache.org/projects/httpd/trunk/doxygen/group__APACHE__CORE__PROTO.html#ga5e91eb6ca777c9a427b2e82bf1eeb81d">ap_rprintf</a><code style="color:#806030; ">(</code>r<code style="color:#806030; ">,</code> <code style="color:#800000; ">"</code><code style="color:#e60000; "><h2>Hello, </code><code style="color:#0f6900; ">%s</code><code style="color:#e60000; ">!</h2></code><code style="color:#800000; ">"</code><code style="color:#806030; ">,</code> r<code style="color:#806030; ">-</code><code style="color:#806030; ">></code><code style="color:#008833">useragent_ip</code><code style="color:#806030; ">)</code><code style="color:#806030; ">;</code> + + <code style="color:#c34e00; ">/* If we were reached through a GET or a POST request, be happy, else sad. */</code> + <code style="color:#400000; font-weight:bold; ">if</code> <code style="color:#806030; ">(</code> <code style="color:#806030; ">!</code><code style="color:#800040; ">strcmp</code><code style="color:#806030; ">(</code>r<code style="color:#806030; ">-</code><code style="color:#806030; ">></code><code style="color:#008833">method</code><code style="color:#806030; ">,</code> <code style="color:#800000; ">"</code><code style="color:#e60000; ">POST</code><code style="color:#800000; ">"</code><code style="color:#806030; ">)</code> <code style="color:#806030; ">|</code><code style="color:#806030; ">|</code> <code style="color:#806030; ">!</code><code style="color:#800040; ">strcmp</code><code style="color:#806030; ">(</code>r<code style="color:#806030; ">-</code><code style="color:#806030; ">></code><code style="color:#008833">method</code><code style="color:#806030; ">,</code> <code style="color:#800000; ">"</code><code style="color:#e60000; ">GET</code><code style="color: #800000; ">"</code><code style="color:#806030; ">)</code> <code style="color:#806030; ">)</code> <code style="color:#806030; ">{</code> + ap_rputs<code style="color:#806030; ">(</code><code style="color:#800000; ">"</code><code style="color:#e60000; ">You used a GET or a POST method, that makes us happy!<br></code><code style="color:#800000; ">"</code><code style="color:#806030; ">,</code> r<code style="color:#806030; ">)</code><code style="color:#806030; ">;</code> + <code style="color:#806030; ">}</code> + <code style="color:#400000; font-weight:bold; ">else</code> <code style="color:#806030; ">{</code> + ap_rputs<code style="color:#806030; ">(</code><code style="color:#800000; ">"</code><code style="color:#e60000; ">You did not use POST or GET, that makes us sad :(<br></code><code style="color:#800000; ">"</code><code style="color:#806030; ">,</code> r<code style="color:#806030; ">)</code><code style="color:#806030; ">;</code> + <code style="color:#806030; ">}</code> + + <code style="color:#c34e00; ">/* Lastly, if there was a query string, let's print that too! */</code> + <code style="color:#400000; font-weight:bold; ">if</code> <code style="color:#806030; ">(</code>r<code style="color:#806030; ">-</code><code style="color:#806030; ">></code><code style="color:#008833">args</code><code style="color:#806030; ">)</code> <code style="color:#806030; ">{</code> + <a href="http://ci.apache.org/projects/httpd/trunk/doxygen/group__APACHE__CORE__PROTO.html#ga5e91eb6ca777c9a427b2e82bf1eeb81d">ap_rprintf</a><code style="color:#806030; ">(</code>r<code style="color:#806030; ">,</code> <code style="color:#800000; ">"</code><code style="color:#e60000; ">Your query string was: </code><code style="color:#0f6900; ">%s</code><code style="color:#800000; ">"</code><code style="color:#806030; ">,</code> r<code style="color:#806030; ">-</code><code style="color:#806030; ">></code><code style="color:#008833">args</code><code style="color:#806030; ">)</code><code style="color:#806030; ">;</code> + <code style="color:#806030; ">}</code> + <code style="color:#400000; font-weight:bold; ">return</code> OK<code style="color:#806030; ">;</code> +<code style="color:#806030; ">}</code> +</pre> + + + +</p> + + +<h3><a name="return_value" id="return_value">Return values</a></h3> +<p> +Apache relies on return values from handlers to signify whether a request +was handled or not, and if so, whether the request went well or not. If a +module is not interested in handling a specific request, it should always +return the value <code>DECLINED</code>. If it is handling a request, it +should either return the generic value <code>OK</code>, or a specific HTTP +status code, for example: + + + +<pre style="color:#000000;background:#ffffef;border: 1px dashed #333; padding: 0.5em; margin: 1em 2em 1em 1em;"> +<code style="color:#400000; font-weight:bold; ">static</code> <code style="color:#400000; font-weight:bold; ">int</code> example_handler<code style="color:#806030; ">(</code>request_rec <code style="color:#806030; ">*</code>r<code style="color:#806030; ">)</code> +<code style="color:#806030; ">{</code> + <code style="color:#c34e00; ">/* Return 404: Not found */</code> + <code style="color:#400000; font-weight:bold; ">return</code> HTTP_NOT_FOUND<code style="color:#806030; ">;</code> +<code style="color:#806030; ">}</code> +</pre> + + + +Returning <code>OK</code> or a HTTP status code does not necessarilly mean +that the request will end. Apache may still have other handlers that are +interested in this request, for instance the logging modules which, upon a +successful request, will write down a summary of what was requested and how +it went. To do a full stop and prevent any further processing after your +module is done, you can return the value <code>DONE</code> to let Apache +know that it should cease all activity on this request and carry on with +the next, without informing other handlers. +<br /> +<strong>General response codes:</strong> +<ul> +<li><code>DECLINED</code>: We are not handling this request</li> +<li><code>OK</code>: We handled this request and it went well</li> +<li><code>DONE</code>: We handled this request and Apache should just close this thread without further processing</li> +</ul><br /> +<strong>HTTP specific return codes (excerpt):</strong> +<ul> +<li><code>HTTP_OK (200)</code>: Request was okay</li> +<li><code>HTTP_MOVED_PERMANENTLY (301)</code>: The resource has moved to a new URL</li> +<li><code>HTTP_UNAUTHORIZED (401)</code>: Client is not authorized to visit this page</li> +<li><code>HTTP_FORBIDDEN (403)</code>: Permission denied</li> +<li><code>HTTP_NOT_FOUND (404)</code>: File not found</li> +<li><code>HTTP_INTERNAL_SERVER_ERROR (500)</code>: Internal server error (self explanatory)</li> +</ul> +</p> + + +<h3><a name="functions" id="functions">Some useful functions you should know</a></h3> + +<ul> +<li> + <code>ap_rputs(const char *string, request_req *r)</code>: <br /> + Sends a string of text to the client. This is a shorthand version of <a href="http://ci.apache.org/projects/httpd/trunk/doxygen/group__APACHE__CORE__PROTO.html#gac827cd0537d2b6213a7c06d7c26cc36e"> + ap_rwrite</a>. + + + +<pre style="color:#000000;background:#ffffef;border: 1px dashed #333; padding: 0.5em; margin: 1em 2em 1em 1em;">ap_rputs<code style="color:#806030; ">(</code><code style="color:#800000; ">"</code><code style="color:#e60000; ">Hello, world!</code><code style="color:#800000; ">"</code><code style="color:#806030; ">,</code> r<code style="color:#806030; ">)</code><code style="color:#806030; ">;</code></pre> + + + +</li> +<li> + <code> + <a href="http://ci.apache.org/projects/httpd/trunk/doxygen/group__APACHE__CORE__PROTO.html#ga5e91eb6ca777c9a427b2e82bf1eeb81d">ap_rprintf</a></code>: <br /> + This function works just like <code>printf</code>, except it sends the result to the client. + + + +<pre style="color:#000000;background:#ffffef;border: 1px dashed #333; padding: 0.5em; margin: 1em 2em 1em 1em;"><code style="color:#2e8800; "><a href="http://ci.apache.org/projects/httpd/trunk/doxygen/group__APACHE__CORE__PROTO.html#ga5e91eb6ca777c9a427b2e82bf1eeb81d">ap_rprintf</a></code><code style="color:#806030; ">(</code>r<code style="color:#806030; ">,</code> <code style="color:#800000; ">"</code><code style="color:#e60000; ">Hello, </code><code style="color:#0f6900; ">%s</code><code style="color:#e60000; ">!</code><code style="color:#800000; ">"</code><code style="color:#806030; ">,</code> r<code style="color:#806030; ">-</code><code style="color:#806030; ">></code><code style="color:#008833">useragent_ip</code><code style="color:#806030; ">)</code><code style="color:#806030; ">;</code></pre> + + +</li> +<li> + <code> + <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 /> + Sets the content type of the output you are sending. + + + +<pre style="color:#000000;background:#ffffef;border: 1px dashed #333; padding: 0.5em; margin: 1em 2em 1em 1em;"><code style="color:#2e8800; "><a href="http://ci.apache.org/projects/httpd/trunk/doxygen/group__APACHE__CORE__PROTO.html#gaa2f8412c400197338ec509f4a45e4579">ap_set_content_type</a></code><code style="color:#806030; ">(</code>r<code style="color:#806030; ">,</code> <code style="color:#800000; ">"</code><code style="color:#e60000; ">text/plain</code><code style="color:#800000; ">"</code><code style="color:#806030; ">)</code><code style="color:#806030; ">;</code> <code style="color:#c34e00; ">/* force a raw text output */</code></pre> + + +</li> + + +</ul> + + +<h3><a name="memory" id="memory">Memory management</a></h3> +<p> +Managing your resources in Apache is quite easy, thanks to the memory pool +system. In essence, each server, connection and request have their own +memory pool that gets cleaned up when its scope ends, e.g. when a request +is done or when a server process shuts down. All your module needs to do is +latch onto this memory pool, and you won't have to worry about having to +clean up after yourself - pretty neat, huh? +</p> + +<p> +In our module, we will primarilly be allocating memory for each request, so +it's appropriate to use the <code style="color:#008833">r->pool</code> +reference when creating new objects. A few of the functions for allocating +memory within a pool are: +<ul> +<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 Apache supplies you with an appropriately allocated target variable</li> + +</ul> +Let's put these functions into an example handler:<br /> + + + +<pre style="color:#000000;background:#ffffef;border: 1px dashed #333; padding: 0.5em; margin: 1em 2em 1em 1em;"> +<code style="color:#400000; font-weight:bold; ">static</code> <code style="color:#400000; font-weight:bold; ">int</code> example_handler<code style="color:#806030; ">(</code>request_rec <code style="color:#806030; ">*</code>r<code style="color:#806030; ">)</code> +<code style="color:#806030; ">{</code> + <code style="color:#400000; font-weight:bold; ">const</code> <code style="color:#400000; font-weight:bold; ">char</code><code style="color:#806030; ">*</code> original <code style="color:#806030; ">=</code> <code style="color:#800000; ">"</code><code style="color:#e60000; ">You can't edit this!</code><code style="color:#800000; ">"</code><code style="color:#806030; ">;</code> + <code style="color:#400000; font-weight:bold; ">char</code><code style="color:#806030; ">*</code> copy<code style="color:#806030; ">;</code> + <code style="color:#400000; font-weight:bold; ">int</code><code style="color:#806030; ">*</code> integers<code style="color:#806030; ">;</code> + + <code style="color:#c34e00; ">/* Allocate space for 10 integer values and set them all to zero. */</code> + integers <code style="color:#806030; ">=</code> apr_pcalloc<code style="color:#806030; ">(</code>r<code style="color:#806030; ">-</code><code style="color:#806030; ">></code>pool<code style="color:#806030; ">,</code> <code style="color:#400000; font-weight:bold; ">sizeof</code><code style="color:#806030; ">(</code><code style="color:#400000; font-weight:bold; ">int</code><code style="color:#806030; ">)</code><code style="color:#806030; ">*</code><code style="color:#c00000; ">10</code><code style="color:#806030; ">)</code><code style="color:#806030; ">;</code> + + <code style="color:#c34e00; ">/* Create a copy of the 'original' variable that we can edit. */</code> + copy <code style="color:#806030; ">=</code> apr_pstrdup<code style="color:#806030; ">(</code>r<code style="color:#806030; ">-</code><code style="color:#806030; ">></code>pool<code style="color:#806030; ">,</code> original<code style="color:#806030; ">)</code><code style="color:#806030; ">;</code> + <code style="color:#400000; font-weight:bold; ">return</code> OK<code style="color:#806030; ">;</code> +<code style="color:#806030; ">}</code> +</pre> + + +This is all well and good for our module, which won't need any +pre-initialized variables or structures. However, if we wanted to +initialize something early on, before the requests come rolling in, we +could simply add a call to a function in our <code>register_hooks</code> +function to sort it out: + + +<pre style="color:#000000;background:#ffffef;border: 1px dashed #333; padding: 0.5em; margin: 1em 2em 1em 1em;"> +<code style="color:#400000; font-weight:bold; ">static</code> <code style="color:#400000; font-weight:bold; ">void</code> register_hooks<code style="color:#806030; ">(</code>apr_pool_t <code style="color:#806030; ">*</code>pool<code style="color:#806030; ">)</code> +<code style="color:#806030; ">{</code> + <code style="color:#c34e00; ">/* Call a function that initializes some stuff */</code> + <code style="color:#800040; ">example_init_function</code><code style="color:#806030; ">(</code>pool<code style="color:#806030; ">)</code><code style="color:#806030; ">;</code> + <code style="color:#c34e00; ">/* Create a hook in the request handler, so we get called when a request arrives */</code> + <code style="color:#800040; ">ap_hook_handler</code><code style="color:#806030; ">(</code>example_handler<code style="color:#806030; ">,</code> <code style="color:#7f0055; font-weight:bold; ">NULL</code><code style="color:#806030; ">,</code> <code style="color:#7f0055; font-weight:bold; ">NULL</code><code style="color:#806030; ">,</code> APR_HOOK_LAST<code style="color:#806030; ">)</code><code style="color:#806030; ">;</code> +<code style="color:#806030; ">}</code> +</pre> + + +In this pre-request initialization function we would not be using the +same pool as we did when allocating resources for request-based functions. +Instead, we would use the pool given to us by Apache for allocating memory +on a per-process based level. + +</p> + + +<h3><a name="parsing" id="parsing">Parsing request data</a></h3> +<p> +In our example module, we would like to add a feature, that checks which +type of digest, MD5 or SHA1 the client would like to see. This could be +solved by adding a query string to the request. A query string is typically +comprised of several keys and values put together in a string, for instance +<code>valueA=yes&valueB=no&valueC=maybe</code>. It is up to the +module itself to parse these and get the data it requires. In our example, +we'll be looking for a key called <code>digest</code>, and if set to <code> +md5</code>, we'll produce an MD5 digest, otherwise we'll produce a SHA1 +digest. +</p> +<p> +Since the introduction of Apache 2.4, parsing request data from GET and +POST requests have never been easier. All we require to parse both GET and +POST data is four simple lines: + + + +<pre style="color:#000000;background:#ffffef;border: 1px dashed #333; padding: 0.5em; margin: 1em 2em 1em 1em;"> +<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, <code style="color:#7f0055; font-weight:bold; ">NULL</code>, &POST, -1, 8192); +</pre> + + + +In our specific example module, we're looking for the <code>digest</code> +value from the query string, which now resides inside a table called <code> +GET</code>. To extract this value, we need only perform a simple operation: +<br /> + + + +<pre style="color:#000000;background:#ffffef;border: 1px dashed #333; padding: 0.5em; margin: 1em 2em 1em 1em;"> +<code style="color:#c34e00; ">/* Get the "digest" key from the query string, if any. */</code> +<code style="color:#400000; font-weight:bold; ">const</code> <code style="color:#400000; font-weight:bold; ">char</code><code style="color:#806030; "> *</code>digestType <code style="color:#806030; ">=</code> <a href="http://ci.apache.org/projects/httpd/trunk/doxygen/group__apr__tables.html#ga4db13e3915c6b9a3142b175d4c15d915">apr_table_get</a><code style="color:#806030; ">(</code>GET<code style="color:#806030; ">,</code> <code style="color:#800000; ">"</code><code style="color:#e60000; ">digest</code><code style="color:#800000; ">"</code><code style="color:#806030; ">)</code><code style="color:#806030; ">;</code> + +<code style="color:#c34e00; ">/* If no key was returned, we will set a default value instead. */</code> +<code style="color:#400000; font-weight:bold; ">if</code> <code style="color:#806030; ">(</code><code style="color:#806030; ">!</code>digestType<code style="color:#806030; ">)</code> digestType <code style="color:#806030; ">=</code> <code style="color:#800000; ">"</code><code style="color:#e60000; ">sha1</code><code style="color:#800000; ">"</code><code style="color:#806030; ">;</code> + +</pre> + + + +The structures used for the POST and GET data are not exactly the same, so +if we were to fetch a value from POST data instead of the query string, we +would have to resort to a few more lines, as outlined in <a href="#get_post">this example</a> in the last chapter of this document. +</p> + + +<h3><a name="advanced_handler" id="advanced_handler">Making an advanced handler</a></h3> +Now that we have learned how to parse form data and manage our resources, +we can move on to creating an advanced version of our module, that spits +out the MD5 or SHA1 digest of files:<br /> + + + +<pre style="color:#000000;background:#ffffef;border: 1px dashed #333; padding: 0.5em; margin: 1em 2em 1em 1em;"> +<code style="color:#400000; font-weight:bold; ">static</code> <code style="color:#400000; font-weight:bold; ">int</code> example_handler<code style="color:#806030; ">(</code>request_rec <code style="color:#806030; ">*</code>r<code style="color:#806030; ">)</code> +<code style="color:#806030; ">{</code> + <code style="color:#400000; font-weight:bold; ">int</code> rc<code style="color:#806030; ">,</code> exists<code style="color:#806030; ">;</code> + apr_finfo_t finfo<code style="color:#806030; ">;</code> + apr_file_t<code style="color:#806030; "> *</code>file<code style="color:#806030; ">;</code> + <code style="color:#400000; font-weight:bold; ">char</code> <code style="color:#806030; ">*</code>filename<code style="color:#806030; ">;</code> + <code style="color:#400000; font-weight:bold; ">char</code> buffer<code style="color:#806030; ">[</code><code style="color:#c00000; ">256</code><code style="color:#806030; ">]</code><code style="color:#806030; ">;</code> + apr_size_t readBytes<code style="color:#806030; ">;</code> + <code style="color:#400000; font-weight:bold; ">int</code> n<code style="color:#806030; ">;</code> + apr_table_t<code style="color:#806030; "> *</code>GET<code style="color:#806030; ">;</code> + apr_array_header_t<code style="color:#806030; "> *</code>POST<code style="color:#806030; ">;</code> + <code style="color:#400000; font-weight:bold; ">const</code> <code style="color:#400000; font-weight:bold; ">char</code><code style="color:#806030; "> *</code>digestType<code style="color:#806030; ">;</code> + + + <code style="color:#c34e00; ">/* Check that the "example-handler" handler is being called. */</code> + <code style="color:#400000; font-weight:bold; ">if</code> <code style="color:#806030; ">(</code><code style="color:#806030; ">!</code>r<code style="color:#806030; ">-</code><code style="color:#806030; ">></code><code style="color:#008833">handler</code> <code style="color:#806030; ">|</code><code style="color:#806030; ">|</code> <code style="color:#800040; ">strcmp</code><code style="color:#806030; ">(</code>r<code style="color:#806030; ">-</code><code style="color:#806030; ">></code><code style="color:#008833">handler</code><code style="color:#806030; ">,</code> <code style="color:#800000; ">"</code><code style="color:#e60000; ">example-handler</code><code style="color:#800000; ">"</code><code style="color:#806030; ">)</code><code style="color:#806030; ">)</code> <code style="color:#400000; font-weight:bold; ">return</code> <code style="color:#806030; ">(</code>DECLINED<code style="color:#806030; ">)</code><code style="color:#806030; ">;</code> + + <code style="color:#c34e00; ">/* Figure out which file is being requested by removing the .sum from it */</code> + filename <code style="color:#806030; ">=</code> apr_pstrdup<code style="color:#806030; ">(</code>r<code style="color:#806030; ">-</code><code style="color:#806030; ">></code><code style="color:#008833">pool</code><code style="color:#806030; ">,</code> r<code style="color:#806030; ">-</code><code style="color:#806030; ">></code><code style="color:#008833">filename</code><code style="color:#806030; ">)</code><code style="color:#806030; ">;</code> + filename<code style="color:#806030; ">[.</code><code style="color:#800040; ">strlen</code><code style="color:#806030; ">(</code>filename<code style="color:#806030; ">)</code><code style="color:#806030; ">-</code><code style="color:#c00000; ">4</code><code style="color:#806030; ">]</code> <code style="color:#806030; ">=</code> <code style="color:#c00000; ">0</code><code style="color:#806030; ">;</code> <code style="color:#c34e00; ">/* Cut off the last 4 characters. */</code> + + <code style="color:#c34e00; ">/* Figure out if the file we request a sum on exists and isn't a directory */</code> + rc <code style="color:#806030; ">=</code> apr_stat<code style="color:#806030; ">(</code><code style="color:#806030; ">&</code>finfo<code style="color:#806030; ">,</code> filename<code style="color:#806030; ">,</code> APR_FINFO_MIN<code style="color:#806030; ">,</code> r<code style="color:#806030; ">-</code><code style="color:#806030; ">></code><code style="color:#008833">pool</code><code style="color:#806030; ">)</code><code style="color:#806030; ">;</code> + <code style="color:#400000; font-weight:bold; ">if</code> <code style="color:#806030; ">(</code>rc <code style="color:#806030; ">=</code><code style="color:#806030; ">=</code> APR_SUCCESS<code style="color:#806030; ">)</code> <code style="color:#806030; ">{</code> + exists <code style="color:#806030; ">=</code> + <code style="color:#806030; ">(</code> + <code style="color:#806030; ">(</code>finfo<code style="color:#806030; ">.</code>filetype <code style="color:#806030; ">!</code><code style="color:#806030; ">=</code> APR_NOFILE<code style="color:#806030; ">)</code> + <code style="color:#806030; ">&</code><code style="color:#806030; ">&</code> <code style="color:#806030; ">!</code><code style="color:#806030; ">(</code>finfo<code style="color:#806030; ">.</code>filetype <code style="color:#806030; ">&</code> APR_DIR<code style="color:#806030; ">)</code> + <code style="color:#806030; ">)</code><code style="color:#806030; ">;</code> + <code style="color:#400000; font-weight:bold; ">if</code> <code style="color:#806030; ">(</code><code style="color:#806030; ">!</code>exists<code style="color:#806030; ">)</code> <code style="color:#400000; font-weight:bold; ">return</code> HTTP_NOT_FOUND<code style="color:#806030; ">;</code> <code style="color:#c34e00; ">/* Return a 404 if not found. */</code> + <code style="color:#806030; ">}</code> + <code style="color:#c34e00; ">/* If apr_stat failed, we're probably not allowed to check this file. */</code> + <code style="color:#400000; font-weight:bold; ">else</code> <code style="color:#400000; font-weight:bold; ">return</code> HTTP_FORBIDDEN<code style="color:#806030; ">;</code> + + <code style="color:#c34e00; ">/* Parse the GET and, optionally, the POST data sent to us */</code> + + ap_args_to_table<code style="color:#806030; ">(</code>r<code style="color:#806030; ">,</code> <code style="color:#806030; ">&</code>GET<code style="color:#806030; ">)</code><code style="color:#806030; ">;</code> + ap_parse_form_data<code style="color:#806030; ">(</code>r<code style="color:#806030; ">,</code> <code style="color:#007d45; ">NULL</code><code style="color:#806030; ">,</code> <code style="color:#806030; ">&</code>POST<code style="color:#806030; ">,</code> <code style="color:#806030; ">-</code><code style="color:#c00000; ">1</code><code style="color:#806030; ">,</code> <code style="color:#c00000; ">8192</code><code style="color:#806030; ">)</code><code style="color:#806030; ">;</code> + + <code style="color:#c34e00; ">/* Set the appropriate content type */</code> + ap_set_content_type<code style="color:#806030; ">(</code>r<code style="color:#806030; ">,</code> <code style="color:#800000; ">"</code><code style="color:#e60000; ">text/html</code><code style="color:#800000; ">"</code><code style="color:#806030; ">)</code><code style="color:#806030; ">;</code> + + <code style="color:#c34e00; ">/* Print a title and some general information */</code> + ap_rprintf<code style="color:#806030; ">(</code>r<code style="color:#806030; ">,</code> <code style="color:#800000; ">"</code><code style="color:#e60000; "><h2>Information on </code><code style="color:#0f6900; ">%s</code><code style="color:#e60000; ">:</h2></code><code style="color:#800000; ">"</code><code style="color:#806030; ">,</code> filename<code style="color:#806030; ">)</code><code style="color:#806030; ">;</code> + ap_rprintf<code style="color:#806030; ">(</code>r<code style="color:#806030; ">,</code> <code style="color:#800000; ">"</code><code style="color:#e60000; "><b>Size:</b> </code><code style="color:#0f6900; ">%u</code><code style="color:#e60000; "> bytes<br/></code><code style="color:#800000; ">"</code><code style="color:#806030; ">,</code> finfo<code style="color:#806030; ">.</code>size<code style="color:#806030; ">)</code><code style="color:#806030; ">;</code> + + <code style="color:#c34e00; ">/* Get the digest type the client wants to see */</code> + digestType <code style="color:#806030; ">=</code> apr_table_get<code style="color:#806030; ">(</code>GET<code style="color:#806030; ">,</code> <code style="color:#800000; ">"</code><code style="color:#e60000; ">digest</code><code style="color:#800000; ">"</code><code style="color:#806030; ">)</code><code style="color:#806030; ">;</code> + <code style="color:#400000; font-weight:bold; ">if</code> <code style="color:#806030; ">(</code><code style="color:#806030; ">!</code>digestType<code style="color:#806030; ">)</code> digestType <code style="color:#806030; ">=</code> <code style="color:#800000; ">"</code><code style="color:#e60000; ">MD5</code><code style="color:#800000; ">"</code><code style="color:#806030; ">;</code> + + + rc <code style="color:#806030; ">=</code> apr_file_open<code style="color:#806030; ">(</code><code style="color:#806030; ">&</code>file<code style="color:#806030; ">,</code> filename<code style="color:#806030; ">,</code> APR_READ<code style="color:#806030; ">,</code> APR_OS_DEFAULT<code style="color:#806030; ">,</code> r<code style="color:#806030; ">-</code><code style="color:#806030; ">></code><code style="color:#008833">pool</code><code style="color:#806030; ">)</code><code style="color:#806030; ">;</code> + <code style="color:#400000; font-weight:bold; ">if</code> <code style="color:#806030; ">(</code>rc <code style="color:#806030; ">=</code><code style="color:#806030; ">=</code> APR_SUCCESS<code style="color:#806030; ">)</code> <code style="color:#806030; ">{</code> + + <code style="color:#c34e00; ">/* Are we trying to calculate the MD5 or the SHA1 digest? */</code> + <code style="color:#400000; font-weight:bold; ">if</code> <code style="color:#806030; ">(</code><code style="color:#806030; ">!</code>strcasecmp<code style="color:#806030; ">(</code>digestType<code style="color:#806030; ">,</code> <code style="color:#800000; ">"</code><code style="color:#e60000; ">md5</code><code style="color:#800000; ">"</code><code style="color:#806030; ">)</code><code style="color:#806030; ">)</code> <code style="color:#806030; ">{</code> + <code style="color:#c34e00; ">/* Calculate the MD5 sum of the file */</code> + <code style="color:#400000; font-weight:bold; ">union</code> <code style="color:#806030; ">{</code> + <code style="color:#400000; font-weight:bold; ">char</code> chr<code style="color:#806030; ">[</code><code style="color:#c00000; ">16</code><code style="color:#806030; ">]</code><code style="color:#806030; ">;</code> + uint32_t num<code style="color:#806030; ">[</code><code style="color:#c00000; ">4</code><code style="color:#806030; ">]</code><code style="color:#806030; ">;</code> + <code style="color:#806030; ">}</code> digest<code style="color:#806030; ">;</code> + apr_md5_ctx_t md5<code style="color:#806030; ">;</code> + apr_md5_init<code style="color:#806030; ">(</code><code style="color:#806030; ">&</code>md5<code style="color:#806030; ">)</code><code style="color:#806030; ">;</code> + readBytes <code style="color:#806030; ">=</code> <code style="color:#c00000; ">256</code><code style="color:#806030; ">;</code> + <code style="color:#400000; font-weight:bold; ">while</code> <code style="color:#806030; ">(</code> apr_file_read<code style="color:#806030; ">(</code>file<code style="color:#806030; ">,</code> buffer<code style="color:#806030; ">,</code> <code style="color:#806030; ">&</code>readBytes<code style="color:#806030; ">)</code> <code style="color:#806030; ">=</code><code style="color:#806030; ">=</code> APR_SUCCESS <code style="color:#806030; ">)</code> <code style="color:#806030; ">{</code> + apr_md5_update<code style="color:#806030; ">(</code><code style="color:#806030; ">&</code>md5<code style="color:#806030; ">,</code> buffer<code style="color:#806030; ">,</code> readBytes<code style="color:#806030; ">)</code><code style="color:#806030; ">;</code> + <code style="color:#806030; ">}</code> + apr_md5_final<code style="color:#806030; ">(</code>digest<code style="color:#806030; ">.</code>chr<code style="color:#806030; ">,</code> <code style="color:#806030; ">&</code>md5<code style="color:#806030; ">)</code><code style="color:#806030; ">;</code> + + <code style="color:#c34e00; ">/* Print out the MD5 digest */</code> + ap_rputs<code style="color:#806030; ">(</code><code style="color:#800000; ">"</code><code style="color:#e60000; "><b>MD5: </b><code></code><code style="color:#800000; ">"</code><code style="color:#806030; ">,</code> r<code style="color:#806030; ">)</code><code style="color:#806030; ">;</code> + <code style="color:#400000; font-weight:bold; ">for</code> <code style="color:#806030; ">(</code>n <code style="color:#806030; ">=</code> <code style="color:#c00000; ">0</code><code style="color:#806030; ">;</code> n <code style="color:#806030; "><</code> APR_MD5_DIGESTSIZE<code style="color:#806030; ">/</code><code style="color:#c00000; ">4</code><code style="color:#806030; ">;</code> n<code style="color:#806030; ">+</code><code style="color:#806030; ">+</code><code style="color:#806030; ">)</code> <code style="color:#806030; ">{</code> + ap_rprintf<code style="color:#806030; ">(</code>r<code style="color:#806030; ">,</code> <code style="color:#800000; ">"</code><code style="color:#0f6900; ">%08x</code><code style="color:#800000; ">"</code><code style="color:#806030; ">,</code> digest<code style="color:#806030; ">.</code>num<code style="color:#806030; ">[</code>n<code style="color:#806030; ">]</code><code style="color:#806030; ">)</code><code style="color:#806030; ">;</code> + <code style="color:#806030; ">}</code> + ap_rputs<code style="color:#806030; ">(</code><code style="color:#800000; ">"</code><code style="color:#e60000; "></code></code><code style="color:#800000; ">"</code><code style="color:#806030; ">,</code> r<code style="color:#806030; ">)</code><code style="color:#806030; ">;</code> + <code style="color:#c34e00; ">/* Print a link to the SHA1 version */</code> + ap_rputs<code style="color:#806030; ">(</code><code style="color:#800000; ">"</code><code style="color:#e60000; "><br/><a href='?digest=sha1'>View the SHA1 hash instead</a></code><code style="color:#800000; ">"</code><code style="color:#806030; ">,</code> r<code style="color:#806030; ">)</code><code style="color:#806030; ">;</code> + <code style="color:#806030; ">}</code> + <code style="color:#400000; font-weight:bold; ">else</code> <code style="color:#806030; ">{</code> + <code style="color:#c34e00; ">/* Calculate the SHA1 sum of the file */</code> + <code style="color:#400000; font-weight:bold; ">union</code> <code style="color:#806030; ">{</code> + <code style="color:#400000; font-weight:bold; ">char</code> chr<code style="color:#806030; ">[</code><code style="color:#c00000; ">20</code><code style="color:#806030; ">]</code><code style="color:#806030; ">;</code> + uint32_t num<code style="color:#806030; ">[</code><code style="color:#c00000; ">5</code><code style="color:#806030; ">]</code><code style="color:#806030; ">;</code> + <code style="color:#806030; ">}</code> digest<code style="color:#806030; ">;</code> + apr_sha1_ctx_t sha1<code style="color:#806030; ">;</code> + apr_sha1_init<code style="color:#806030; ">(</code><code style="color:#806030; ">&</code>sha1<code style="color:#806030; ">)</code><code style="color:#806030; ">;</code> + readBytes <code style="color:#806030; ">=</code> <code style="color:#c00000; ">256</code><code style="color:#806030; ">;</code> + <code style="color:#400000; font-weight:bold; ">while</code> <code style="color:#806030; ">(</code> apr_file_read<code style="color:#806030; ">(</code>file<code style="color:#806030; ">,</code> buffer<code style="color:#806030; ">,</code> <code style="color:#806030; ">&</code>readBytes<code style="color:#806030; ">)</code> <code style="color:#806030; ">=</code><code style="color:#806030; ">=</code> APR_SUCCESS <code style="color:#806030; ">)</code> <code style="color:#806030; ">{</code> + apr_sha1_update<code style="color:#806030; ">(</code><code style="color:#806030; ">&</code>sha1<code style="color:#806030; ">,</code> buffer<code style="color:#806030; ">,</code> readBytes<code style="color:#806030; ">)</code><code style="color:#806030; ">;</code> + <code style="color:#806030; ">}</code> + apr_sha1_final<code style="color:#806030; ">(</code>digest<code style="color:#806030; ">.</code>chr<code style="color:#806030; ">,</code> <code style="color:#806030; ">&</code>sha1<code style="color:#806030; ">)</code><code style="color:#806030; ">;</code> + + <code style="color:#c34e00; ">/* Print out the SHA1 digest */</code> + ap_rputs<code style="color:#806030; ">(</code><code style="color:#800000; ">"</code><code style="color:#e60000; "><b>SHA1: </b><code></code><code style="color:#800000; ">"</code><code style="color:#806030; ">,</code> r<code style="color:#806030; ">)</code><code style="color:#806030; ">;</code> + <code style="color:#400000; font-weight:bold; ">for</code> <code style="color:#806030; ">(</code>n <code style="color:#806030; ">=</code> <code style="color:#c00000; ">0</code><code style="color:#806030; ">;</code> n <code style="color:#806030; "><</code> APR_SHA1_DIGESTSIZE<code style="color:#806030; ">/</code><code style="color:#c00000; ">4</code><code style="color:#806030; ">;</code> n<code style="color:#806030; ">+</code><code style="color:#806030; ">+</code><code style="color:#806030; ">)</code> <code style="color:#806030; ">{</code> + ap_rprintf<code style="color:#806030; ">(</code>r<code style="color:#806030; ">,</code> <code style="color:#800000; ">"</code><code style="color:#0f6900; ">%08x</code><code style="color:#800000; ">"</code><code style="color:#806030; ">,</code> digest<code style="color:#806030; ">.</code>num<code style="color:#806030; ">[</code>n<code style="color:#806030; ">]</code><code style="color:#806030; ">)</code><code style="color:#806030; ">;</code> + <code style="color:#806030; ">}</code> + ap_rputs<code style="color:#806030; ">(</code><code style="color:#800000; ">"</code><code style="color:#e60000; "></code></code><code style="color:#800000; ">"</code><code style="color:#806030; ">,</code> r<code style="color:#806030; ">)</code><code style="color:#806030; ">;</code> + + <code style="color:#c34e00; ">/* Print a link to the MD5 version */</code> + ap_rputs<code style="color:#806030; ">(</code><code style="color:#800000; ">"</code><code style="color:#e60000; "><br/><a href='?digest=md5'>View the MD5 hash instead</a></code><code style="color:#800000; ">"</code><code style="color:#806030; ">,</code> r<code style="color:#806030; ">)</code><code style="color:#806030; ">;</code> + <code style="color:#806030; ">}</code> + apr_file_close<code style="color:#806030; ">(</code>file<code style="color:#806030; ">)</code><code style="color:#806030; ">;</code> + + <code style="color:#806030; ">}</code> + + + + <code style="color:#c34e00; ">/* Let Apache know that we responded to this request. */</code> + <code style="color:#400000; font-weight:bold; ">return</code> OK<code style="color:#806030; ">;</code> +<code style="color:#806030; ">}</code> +</pre> + + + +This version in its entirity can be found here: +<a href="http://people.apache.org/~humbedooh/mods/examples/mod_example_2.c">mod_example_2.c</a>. + + +</div><div class="top"><a href="#page-header"><img alt="top" src="../images/up.gif" /></a></div> +<div class="section"> +<h2><a name="configuration" id="configuration">Adding configuration options</a></h2> +<p> +In this next segment of this document, we will turn our eyes away from the +digest module and create a new example module, whose only function is to +write out its own configuration. The purpose of this is to examine how +Apache works with configuration, and what happens when you start writing +advanced configurations +for your modules. +</p> +<h3><a name="config_intro" id="config_intro">An introduction to configuration +directives</a></h3> If you are reading this, then you probably already know +what a configuration directive is. Simply put, a directive is a way of +telling an individual module (or a set of modules) how to behave, such as +these directives control how <code>mod_rewrite</code> works: +<div class="example"><pre> +RewriteEngine On +RewriteCond %{REQUEST_URI} ^/foo/bar +RewriteRule ^/foo/bar/(.*)$ /foobar?page=$1 +</pre></div> +Each of these configuration directives are handled by a separate function, +that parses the parameters given and sets up a configuration accordingly. + +<h3><a name="config_simple" id="config_simple">Making an example configuration</a></h3> +To begin with, we'll create a basic configuration in C-space: + + + +<pre style="color:#000000;background:#ffffef;border: 1px dashed #333; padding: 0.5em; margin: 1em 2em 1em 1em;"> +<code style="color:#400000; font-weight:bold; ">typedef</code> <code style="color:#400000; font-weight:bold; ">struct</code> <code style="color:#806030; ">{</code> + <code style="color:#400000; font-weight:bold; ">int</code> enabled<code style="color:#806030; ">;</code> <code style="color:#c34e00; ">/* Enable or disable our module */</code> + <code style="color:#400000; font-weight:bold; ">const</code> <code style="color:#400000; font-weight:bold; ">char</code> <code style="color:#806030; ">*</code>path<code style="color:#806030; ">;</code> <code style="color:#c34e00; ">/* Some path to...something */</code> + <code style="color:#400000; font-weight:bold; ">int</code> typeOfAction<code style="color:#806030; ">;</code> <code style="color:#c34e00; ">/* 1 means action A, 2 means action B and so on */</code> +<code style="color:#806030; ">}</code> example_config<code style="color:#806030; ">;</code> +</pre> + + + +Now, let's put this into perspective by creating a very small module that +just prints out a hard-coded configuration. You'll notice that we use the +<code>register_hooks</code> function for initializing the configuration +values to their defaults: + + + +<pre style="color:#000000;background:#ffffef;border: 1px dashed #333; padding: 0.5em; margin: 1em 2em 1em 1em;"> +<code style="color:#400000; font-weight:bold; ">typedef</code> <code style="color:#400000; font-weight:bold; ">struct</code> <code style="color:#806030; ">{</code> + <code style="color:#400000; font-weight:bold; ">int</code> enabled<code style="color:#806030; ">;</code> <code style="color:#c34e00; ">/* Enable or disable our module */</code> + <code style="color:#400000; font-weight:bold; ">const</code> <code style="color:#400000; font-weight:bold; ">char</code> <code style="color:#806030; ">*</code>path<code style="color:#806030; ">;</code> <code style="color:#c34e00; ">/* Some path to...something */</code> + <code style="color:#400000; font-weight:bold; ">int</code> typeOfAction<code style="color:#806030; ">;</code> <code style="color:#c34e00; ">/* 1 means action A, 2 means action B and so on */</code> +<code style="color:#806030; ">}</code> example_config<code style="color:#806030; ">;</code> + +<code style="color:#400000; font-weight:bold; ">static</code> example_config config<code style="color:#806030; ">;</code> + +<code style="color:#400000; font-weight:bold; ">static</code> <code style="color:#400000; font-weight:bold; ">int</code> example_handler<code style="color:#806030; ">(</code>request_rec <code style="color:#806030; ">*</code>r<code style="color:#806030; ">)</code> +<code style="color:#806030; ">{</code> + <code style="color:#400000; font-weight:bold; ">if</code> <code style="color:#806030; ">(</code><code style="color:#806030; ">!</code>r<code style="color:#806030; ">-</code><code style="color:#806030; ">></code><code style="color:#008833">handler</code> <code style="color:#806030; ">|</code><code style="color:#806030; ">|</code> <code style="color:#800040; ">strcmp</code><code style="color:#806030; ">(</code>r<code style="color:#806030; ">-</code><code style="color:#806030; ">></code><code style="color:#008833">handler</code><code style="color:#806030; ">,</code> <code style="color:#800000; ">"</code><code style="color:#e60000; ">example-handler</code><code style="color:#800000; ">"</code><code style="color:#806030; ">)</code><code style="color:#806030; ">)</code> <code style="color:#400000; font-weight:bold; ">return</code><code style="color:#806030; ">(</code>DECLINED<code style="color:#806030; ">)</code><code style="color:#806030; ">;</code> + ap_set_content_type<code style="color:#806030; ">(</code>r<code style="color:#806030; ">,</code> <code style="color:#800000; ">"</code><code style="color:#e60000; ">text/plain</code><code style="color:#800000; ">"</code><code style="color:#806030; ">)</code><code style="color:#806030; ">;</code> + ap_rprintf<code style="color:#806030; ">(r, </code><code style="color:#800000; ">"</code><code style="color:#e60000; ">Enabled: </code><code style="color:#0f6900; ">%u</code><code style="color:#0f6900; ">\n</code><code style="color:#800000; ">"</code><code style="color:#806030; ">,</code> config<code style="color:#806030; ">.</code>enabled<code style="color:#806030; ">)</code><code style="color:#806030; ">;</code> + ap_rprintf<code style="color:#806030; ">(r, </code><code style="color:#800000; ">"</code><code style="color:#e60000; ">Path: </code><code style="color:#0f6900; ">%s</code><code style="color:#0f6900; ">\n</code><code style="color:#800000; ">"</code><code style="color:#806030; ">,</code> config<code style="color:#806030; ">.</code>path<code style="color:#806030; ">)</code><code style="color:#806030; ">;</code> + ap_rprintf<code style="color:#806030; ">(r, </code><code style="color:#800000; ">"</code><code style="color:#e60000; ">TypeOfAction: </code><code style="color:#0f6900; ">%x</code><code style="color:#0f6900; ">\n</code><code style="color:#800000; ">"</code><code style="color:#806030; ">,</code> config<code style="color:#806030; ">.</code>typeOfAction<code style="color:#806030; ">)</code><code style="color:#806030; ">;</code> + <code style="color:#400000; font-weight:bold; ">return</code> OK<code style="color:#806030; ">;</code> +<code style="color:#806030; ">}</code> + +<code style="color:#400000; font-weight:bold; ">static</code> <code style="color:#400000; font-weight:bold; ">void</code> register_hooks<code style="color:#806030; ">(</code>apr_pool_t <code style="color:#806030; ">*</code>pool<code style="color:#806030; ">)</code> +<code style="color:#806030; ">{</code> + config<code style="color:#806030; ">.</code>enabled <code style="color:#806030; ">=</code> <code style="color:#c00000; ">1</code><code style="color:#806030; ">;</code> + config<code style="color:#806030; ">.</code>path <code style="color:#806030; ">=</code> <code style="color:#800000; ">"</code><code style="color:#e60000; ">/foo/bar</code><code style="color:#800000; ">"</code><code style="color:#806030; ">;</code> + config<code style="color:#806030; ">.</code>typeOfAction <code style="color:#806030; ">=</code> <code style="color:#c00000; ">0x00</code><code style="color:#806030; ">;</code> + ap_hook_handler<code style="color:#806030; ">(</code>example_handler<code style="color:#806030; ">,</code> <code style="color:#007d45; ">NULL</code><code style="color:#806030; ">,</code> <code style="color:#007d45; ">NULL</code><code style="color:#806030; ">,</code> APR_HOOK_LAST<code style="color:#806030; ">)</code><code style="color:#806030; ">;</code> +<code style="color:#806030; ">}</code> + +<code style="color:#c34e00; ">/* Define our module as an entity and assign a function for registering hooks */</code> + +module AP_MODULE_DECLARE_DATA example_module <code style="color:#806030; ">=</code> +<code style="color:#806030; ">{</code> + STANDARD20_MODULE_STUFF<code style="color:#806030; ">,</code> + <code style="color:#007d45; ">NULL</code><code style="color:#806030; ">,</code> <code style="color:#c34e00; ">/* Per-directory configuration handler */</code> + <code style="color:#007d45; ">NULL</code><code style="color:#806030; ">,</code> <code style="color:#c34e00; ">/* Merge handler for per-directory configurations */</code> + <code style="color:#007d45; ">NULL</code><code style="color:#806030; ">,</code> <code style="color:#c34e00; ">/* Per-server configuration handler */</code> + <code style="color:#007d45; ">NULL</code><code style="color:#806030; ">,</code> <code style="color:#c34e00; ">/* Merge handler for per-server configurations */</code> + <code style="color:#007d45; ">NULL</code><code style="color:#806030; ">,</code> <code style="color:#c34e00; ">/* Any directives we may have for httpd */</code> + register_hooks <code style="color:#c34e00; ">/* Our hook registering function */</code> +<code style="color:#806030; ">}</code><code style="color:#806030; ">;</code> +</pre> + + + +So far so good. To access our new handler, we could add the following to +our configuration: +<div class="example"><pre> +<Location /example> + SetHandler example-handler +</Location> +</pre></div> +When we visit, we'll see our current configuration being spit out by our +module. + + +<h3><a name="register_directive" id="register_directive">Registering directives with Apache</a></h3> +What if we want to change our configuration, not by hard-coding new values +into the module, but by using either the httpd.conf file or possibly a +.htaccess file? It's time to let Apache know that we want this to be +possible. To do so, we must first change our <em>name tag</em> to include a +reference to the configuration directives we want to register with Apache: + + + +<pre style="color:#000000;background:#ffffef;border: 1px dashed #333; padding: 0.5em; margin: 1em 2em 1em 1em;"> +module AP_MODULE_DECLARE_DATA example_module = +{ + STANDARD20_MODULE_STUFF, + <code style="color:#7f0055; font-weight:bold; ">NULL</code>, <code style="color:#c34e00; ">/* Per-directory configuration handler */</code> + <code style="color:#7f0055; font-weight:bold; ">NULL</code>, <code style="color:#c34e00; ">/* Merge handler for per-directory configurations */</code> + <code style="color:#7f0055; font-weight:bold; ">NULL</code>, <code style="color:#c34e00; ">/* Per-server configuration handler */</code> + <code style="color:#7f0055; font-weight:bold; ">NULL</code>, <code style="color:#c34e00; ">/* Merge handler for per-server configurations */</code> + example_directives, <code style="color:#c34e00; ">/* Any directives we may have for httpd */</code> + register_hooks <code style="color:#c34e00; ">/* Our hook registering function */</code> +}; +</pre> + + + +This will tell Apache that we are now accepting directives from the +configuration files, and that the structure called <code>example_directives +</code> holds information on what our directives are and how they work. +Since we have three different variables in our module configuration, we +will add a structure with three directives and a NULL at the end: + + + +<pre style="color:#000000;background:#ffffef;border: 1px dashed #333; padding: 0.5em; margin: 1em 2em 1em 1em;"> +static const command_rec example_directives[] = +{ + <code style="color:#2e8800; "><a href="http://ci.apache.org/projects/httpd/trunk/doxygen/group__APACHE__CORE__CONFIG.html#ga07c7d22ae17805e61204463326cf9c34">AP_INIT_TAKE1</a></code>("exampleEnabled", example_set_enabled, <code style="color:#7f0055; font-weight:bold; ">NULL</code>, RSRC_CONF, "Enable or disable mod_example"), + <code style="color:#2e8800; "><a href="http://ci.apache.org/projects/httpd/trunk/doxygen/group__APACHE__CORE__CONFIG.html#ga07c7d22ae17805e61204463326cf9c34">AP_INIT_TAKE1</a></code>("examplePath", example_set_path, <code style="color:#7f0055; font-weight:bold; ">NULL</code>, RSRC_CONF, "The path to whatever"), + <code style="color:#2e8800; "><a href="http://ci.apache.org/projects/httpd/trunk/doxygen/group__APACHE__CORE__CONFIG.html#gafaec43534fcf200f37d9fecbf9247c21">AP_INIT_TAKE2</a></code>("exampleAction", example_set_action, <code style="color:#7f0055; font-weight:bold; ">NULL</code>, RSRC_CONF, "Special action value!"), + { <code style="color:#7f0055; font-weight:bold; ">NULL</code> } +}; +</pre> + + + +<img src="../images/build_a_mod_4.png" border="1" /><br /> +<p> +As you can see, each directive needs at least 5 parameters set: +<ol> +<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 Apache 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 +for more macros).</li> +<li><code>exampleEnabled</code>: This is the name of our directive. More precisely, it is what the user must put in his/her +configuration in order to invoke a configuration change in our module.</li> +<li><code>example_set_enabled</code>: This is a reference to a C function that parses the directive and sets the configuration +accordingly. We will discuss how to make this in the following paragraph.</li> +<li><code>RSRC_CONF</code>: This tells Apache where the directive is permissable. We'll go into details on this value in the +later chapters, but for now, <code>RSRC_CONF</code> means that Apache 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> +</ol> +(<em>The "missing" parameter in our definition, which is usually set to +<code>NULL</code>, is an optional function that can be run after the +initial function to parse the arguments have been run. This is usually +omitted, as the function for verifying arguments might as well be used to +set them.</em>) +</p> + +<h3><a name="directive_handler" id="directive_handler">The directive handler function</a></h3> +<p> +Now that we've told Apache to expect some directives for our module, it's +time to make a few functions for handling these. What Apache reads in the +configuration file(s) is text, and so naturally, what it passes along to +our directive handler is one or more strings, that we ourselves need to +recognize and act upon. You'll notice, that since we set our <code> +exampleAction</code> directive to accept two arguments, its C function also +has an additional parameter defined:<br /> + + +<pre style="color:#000000;background:#ffffef;border: 1px dashed #333; padding: 0.5em; margin: 1em 2em 1em 1em;"> +<code style="color:#c34e00; ">/* Handler for the "exambleEnabled" directive */</code> +<code style="color:#400000; font-weight:bold; ">const</code> <code style="color:#400000; font-weight:bold; ">char</code><code style="color:#806030; "> *</code>example_set_enabled<code style="color:#806030; ">(</code>cmd_parms <code style="color:#806030; ">*</code>cmd<code style="color:#806030; ">,</code> <code style="color:#400000; font-weight:bold; ">void</code> <code style="color:#806030; ">*</code>cfg<code style="color:#806030; ">,</code> <code style="color:#400000; font-weight:bold; ">const</code> <code style="color:#400000; font-weight:bold; ">char</code> <code style="color:#806030; ">*</code>arg<code style="color:#806030; ">)</code> +<code style="color:#806030; ">{</code> + <code style="color:#400000; font-weight:bold; ">if</code><code style="color:#806030; ">(</code><code style="color:#806030; ">!</code>strcasecmp<code style="color:#806030; ">(</code>arg<code style="color:#806030; ">,</code> <code style="color:#800000; ">"</code><code style="color:#e60000; ">on</code><code style="color:#800000; ">"</code><code style="color:#806030; ">)</code><code style="color:#806030; ">)</code> config<code style="color:#806030; ">.</code>enabled <code style="color:#806030; ">=</code> <code style="color:#c00000; ">1</code><code style="color:#806030; ">;</code> + <code style="color:#400000; font-weight:bold; ">else</code> config<code style="color:#806030; ">.</code>enabled <code style="color:#806030; ">=</code> <code style="color:#c00000; ">0</code><code style="color:#806030; ">;</code> + <code style="color:#400000; font-weight:bold; ">return</code> <code style="color:#007d45; ">NULL</code><code style="color:#806030; ">;</code> +<code style="color:#806030; ">}</code> + +<code style="color:#c34e00; ">/* Handler for the "examplePath" directive */</code> +<code style="color:#400000; font-weight:bold; ">const</code> <code style="color:#400000; font-weight:bold; ">char</code><code style="color:#806030; "> *</code>example_set_path<code style="color:#806030; ">(</code>cmd_parms <code style="color:#806030; ">*</code>cmd<code style="color:#806030; ">,</code> <code style="color:#400000; font-weight:bold; ">void</code> <code style="color:#806030; ">*</code>cfg<code style="color:#806030; ">,</code> <code style="color:#400000; font-weight:bold; ">const</code> <code style="color:#400000; font-weight:bold; ">char</code> <code style="color:#806030; ">*</code>arg<code style="color:#806030; ">)</code> +<code style="color:#806030; ">{</code> + config<code style="color:#806030; ">.</code>path <code style="color:#806030; ">=</code> arg<code style="color:#806030; ">;</code> + <code style="color:#400000; font-weight:bold; ">return</code> <code style="color:#007d45; ">NULL</code><code style="color:#806030; ">;</code> +<code style="color:#806030; ">}</code> + +<code style="color:#c34e00; ">/* Handler for the "exampleAction" directive */</code> +<code style="color:#c34e00; ">/* Let's pretend this one takes one argument (file or db), and a second (deny or allow), */</code> +<code style="color:#c34e00; ">/* and we store it in a bit-wise manner. */</code> +<code style="color:#400000; font-weight:bold; ">const</code> <code style="color:#400000; font-weight:bold; ">char</code><code style="color:#806030; "> *</code>example_set_action<code style="color:#806030; ">(</code>cmd_parms <code style="color:#806030; ">*</code>cmd<code style="color:#806030; ">,</code> <code style="color:#400000; font-weight:bold; ">void</code> <code style="color:#806030; ">*</code>cfg<code style="color:#806030; ">,</code> <code style="color:#400000; font-weight:bold; ">const</code> <code style="color:#400000; font-weight:bold; ">char</code> <code style="color:#806030; ">*</code>arg1<code style="color:#806030; ">,</code> <code style="color:#400000; font-weight:bold; ">const</code> <code style="color:#400000; font-weight:bold; ">char</code><code style="color:#806030; ">*</code> arg2<code style="color:#806030; ">)</code> +<code style="color:#806030; ">{</code> + <code style="color:#400000; font-weight:bold; ">if</code><code style="color:#806030; ">(</code><code style="color:#806030; ">!</code>strcasecmp<code style="color:#806030; ">(</code>arg1<code style="color:#806030; ">,</code> <code style="color:#800000; ">"</code><code style="color:#e60000; ">file</code><code style="color:#800000; ">"</code><code style="color:#806030; ">)</code><code style="color:#806030; ">)</code> config<code style="color:#806030; ">.</code>typeOfAction <code style="color:#806030; ">=</code> <code style="color:#c00000; ">0x01</code><code style="color:#806030; ">;</code> + <code style="color:#400000; font-weight:bold; ">else</code> config<code style="color:#806030; ">.</code>typeOfAction <code style="color:#806030; ">=</code> <code style="color:#c00000; ">0x02</code><code style="color:#806030; ">;</code> + + <code style="color:#400000; font-weight:bold; ">if</code><code style="color:#806030; ">(</code><code style="color:#806030; ">!</code>strcasecmp<code style="color:#806030; ">(</code>arg2<code style="color:#806030; ">,</code> <code style="color:#800000; ">"</code><code style="color:#e60000; ">deny</code><code style="color:#800000; ">"</code><code style="color:#806030; ">)</code><code style="color:#806030; ">)</code> config<code style="color:#806030; ">.</code>typeOfAction <code style="color:#806030; ">+</code><code style="color:#806030; ">=</code> <code style="color:#c00000; ">0x10</code><code style="color:#806030; ">;</code> + <code style="color:#400000; font-weight:bold; ">else</code> config<code style="color:#806030; ">.</code>typeOfAction <code style="color:#806030; ">+</code><code style="color:#806030; ">=</code> <code style="color:#c00000; ">0x20</code><code style="color:#806030; ">;</code> + <code style="color:#400000; font-weight:bold; ">return</code> <code style="color:#007d45; ">NULL</code><code style="color:#806030; ">;</code> +<code style="color:#806030; ">}</code> +</pre> + + + +</p> + +<h3><a name="directive_complete" id="directive_complete">Putting it all together</a></h3> +<p> +Now that we have our directives set up, and handlers configured for them, +we can assemble our module into one big file: + + + +<pre style="color:#000000;background:#ffffef;border: 1px dashed #333; padding: 0.5em; margin: 1em 2em 1em 1em;"> +<code style="color:#c34e00; ">/* mod_example_config_simple.c: */</code> +<code style="color:#004a43; ">#</code><code style="color:#004a43; ">include </code><code style="color:#800000; "><</code><code style="color:#40015a; ">stdio.h</code><code style="color:#800000; ">></code> +<code style="color:#004a43; ">#</code><code style="color:#004a43; ">include </code><code style="color:#800000; ">"</code><code style="color:#40015a; ">apr_hash.h</code><code style="color:#800000; ">"</code> +<code style="color:#004a43; ">#</code><code style="color:#004a43; ">include </code><code style="color:#800000; ">"</code><code style="color:#40015a; ">ap_config.h</code><code style="color:#800000; ">"</code> +<code style="color:#004a43; ">#</code><code style="color:#004a43; ">include </code><code style="color:#800000; ">"</code><code style="color:#40015a; ">ap_provider.h</code><code style="color:#800000; ">"</code> +<code style="color:#004a43; ">#</code><code style="color:#004a43; ">include </code><code style="color:#800000; ">"</code><code style="color:#40015a; ">httpd.h</code><code style="color:#800000; ">"</code> +<code style="color:#004a43; ">#</code><code style="color:#004a43; ">include </code><code style="color:#800000; ">"</code><code style="color:#40015a; ">http_core.h</code><code style="color:#800000; ">"</code> +<code style="color:#004a43; ">#</code><code style="color:#004a43; ">include </code><code style="color:#800000; ">"</code><code style="color:#40015a; ">http_config.h</code><code style="color:#800000; ">"</code> +<code style="color:#004a43; ">#</code><code style="color:#004a43; ">include </code><code style="color:#800000; ">"</code><code style="color:#40015a; ">http_log.h</code><code style="color:#800000; ">"</code> +<code style="color:#004a43; ">#</code><code style="color:#004a43; ">include </code><code style="color:#800000; ">"</code><code style="color:#40015a; ">http_protocol.h</code><code style="color:#800000; ">"</code> +<code style="color:#004a43; ">#</code><code style="color:#004a43; ">include </code><code style="color:#800000; ">"</code><code style="color:#40015a; ">http_request.h</code><code style="color:#800000; ">"</code> + +<code style="color:#c34e00; ">/*</code> +<code style="color:#c34e00; "> ==============================================================================</code> +<code style="color:#c34e00; "> Our configuration prototype and declaration:</code> +<code style="color:#c34e00; "> ==============================================================================</code> +<code style="color:#c34e00; "> */</code> +<code style="color:#400000; font-weight:bold; ">typedef</code> <code style="color:#400000; font-weight:bold; ">struct</code> <code style="color:#806030; ">{</code> + <code style="color:#400000; font-weight:bold; ">int</code> enabled<code style="color:#806030; ">;</code> <code style="color:#c34e00; ">/* Enable or disable our module */</code> + <code style="color:#400000; font-weight:bold; ">const</code> <code style="color:#400000; font-weight:bold; ">char</code> <code style="color:#806030; ">*</code>path<code style="color:#806030; ">;</code> <code style="color:#c34e00; ">/* Some path to...something */</code> + <code style="color:#400000; font-weight:bold; ">int</code> typeOfAction<code style="color:#806030; ">;</code> <code style="color:#c34e00; ">/* 1 means action A, 2 means action B and so on */</code> +<code style="color:#806030; ">}</code> example_config<code style="color:#806030; ">;</code> + +<code style="color:#400000; font-weight:bold; ">static</code> example_config config<code style="color:#806030; ">;</code> + +<code style="color:#c34e00; ">/*</code> [... 737 lines stripped ...]
|