modguide.xml revision cd42ded5addf01f4ac3b3357565034572388f614
03532fb1cbb7e8c1d5cf2e93aa3719f926631cabStephen Gallagher<?xml version='1.0' encoding='UTF-8' ?>
03532fb1cbb7e8c1d5cf2e93aa3719f926631cabStephen Gallagher<!DOCTYPE manualpage SYSTEM "/style/manualpage.dtd">
03532fb1cbb7e8c1d5cf2e93aa3719f926631cabStephen Gallagher<?xml-stylesheet type="text/xsl" href="/style/manual.en.xsl"?>
03532fb1cbb7e8c1d5cf2e93aa3719f926631cabStephen Gallagher
03532fb1cbb7e8c1d5cf2e93aa3719f926631cabStephen Gallagher<!-- $LastChangedRevision$ -->
03532fb1cbb7e8c1d5cf2e93aa3719f926631cabStephen Gallagher
03532fb1cbb7e8c1d5cf2e93aa3719f926631cabStephen Gallagher<!--
03532fb1cbb7e8c1d5cf2e93aa3719f926631cabStephen Gallagher Licensed to the Apache Software Foundation (ASF) under one or more
03532fb1cbb7e8c1d5cf2e93aa3719f926631cabStephen Gallagher contributor license agreements. See the NOTICE file distributed with
03532fb1cbb7e8c1d5cf2e93aa3719f926631cabStephen Gallagher this work for additional information regarding copyright ownership.
03532fb1cbb7e8c1d5cf2e93aa3719f926631cabStephen Gallagher The ASF licenses this file to You under the Apache License, Version 2.0
03532fb1cbb7e8c1d5cf2e93aa3719f926631cabStephen Gallagher (the "License"); you may not use this file except in compliance with
03532fb1cbb7e8c1d5cf2e93aa3719f926631cabStephen Gallagher the License. You may obtain a copy of the License at
03532fb1cbb7e8c1d5cf2e93aa3719f926631cabStephen Gallagher
03532fb1cbb7e8c1d5cf2e93aa3719f926631cabStephen Gallagher http://www.apache.org/licenses/LICENSE-2.0
03532fb1cbb7e8c1d5cf2e93aa3719f926631cabStephen Gallagher
7b58d637c20f87e1e49ffc1d49a4de8b25ef06bbJakub Hrozek Unless required by applicable law or agreed to in writing, software
03532fb1cbb7e8c1d5cf2e93aa3719f926631cabStephen Gallagher distributed under the License is distributed on an "AS IS" BASIS,
03532fb1cbb7e8c1d5cf2e93aa3719f926631cabStephen Gallagher WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
03532fb1cbb7e8c1d5cf2e93aa3719f926631cabStephen Gallagher See the License for the specific language governing permissions and
03532fb1cbb7e8c1d5cf2e93aa3719f926631cabStephen Gallagher limitations under the License.
03532fb1cbb7e8c1d5cf2e93aa3719f926631cabStephen Gallagher-->
03532fb1cbb7e8c1d5cf2e93aa3719f926631cabStephen Gallagher
03532fb1cbb7e8c1d5cf2e93aa3719f926631cabStephen Gallagher<manualpage metafile="modguide.xml.meta">
03532fb1cbb7e8c1d5cf2e93aa3719f926631cabStephen Gallagher<parentdocument href="./">Developer</parentdocument>
03532fb1cbb7e8c1d5cf2e93aa3719f926631cabStephen Gallagher
03532fb1cbb7e8c1d5cf2e93aa3719f926631cabStephen Gallagher <title>Developing modules for the Apache HTTP Server 2.4</title>
03532fb1cbb7e8c1d5cf2e93aa3719f926631cabStephen Gallagher
03532fb1cbb7e8c1d5cf2e93aa3719f926631cabStephen Gallagher<summary>
03532fb1cbb7e8c1d5cf2e93aa3719f926631cabStephen Gallagher<p>This document explains how you can develop modules for the Apache HTTP
03532fb1cbb7e8c1d5cf2e93aa3719f926631cabStephen GallagherServer 2.4</p>
03532fb1cbb7e8c1d5cf2e93aa3719f926631cabStephen Gallagher</summary>
03532fb1cbb7e8c1d5cf2e93aa3719f926631cabStephen Gallagher
03532fb1cbb7e8c1d5cf2e93aa3719f926631cabStephen Gallagher<seealso><a href="request.html">Request Processing in Apache 2.4</a></seealso>
03532fb1cbb7e8c1d5cf2e93aa3719f926631cabStephen Gallagher<seealso><a href="hooks.html">Apache 2.x Hook Functions</a></seealso>
03532fb1cbb7e8c1d5cf2e93aa3719f926631cabStephen Gallagher
03532fb1cbb7e8c1d5cf2e93aa3719f926631cabStephen Gallagher<section id="introduction"><title>Introduction</title>
03532fb1cbb7e8c1d5cf2e93aa3719f926631cabStephen Gallagher<section id="what"><title>What we will be discussing in this document</title>
03532fb1cbb7e8c1d5cf2e93aa3719f926631cabStephen Gallagher<p>
03532fb1cbb7e8c1d5cf2e93aa3719f926631cabStephen GallagherThis document will discuss how you can easily create modules for the Apache
03532fb1cbb7e8c1d5cf2e93aa3719f926631cabStephen GallagherHTTP Server 2.4, by exploring an example module called
03532fb1cbb7e8c1d5cf2e93aa3719f926631cabStephen Gallagher<code>mod_example</code>. In the first part of this document, the purpose
03532fb1cbb7e8c1d5cf2e93aa3719f926631cabStephen Gallagherof this module will be to calculate and print out various digest values for
728a1812b7c5f70febb522342c5b357da598acfeJakub Hrozekexisting files on your web server, whenever we access the URL <code>
728a1812b7c5f70febb522342c5b357da598acfeJakub Hrozekhttp://hostname/filename.sum</code>. For instance, if we want to know the
728a1812b7c5f70febb522342c5b357da598acfeJakub HrozekMD5 digest value of the file located at <code>
728a1812b7c5f70febb522342c5b357da598acfeJakub Hrozekhttp://www.example.com/index.html</code>, we would visit <code>
728a1812b7c5f70febb522342c5b357da598acfeJakub Hrozekhttp://www.example.com/index.html.sum</code>.
03532fb1cbb7e8c1d5cf2e93aa3719f926631cabStephen Gallagher</p>
03532fb1cbb7e8c1d5cf2e93aa3719f926631cabStephen Gallagher
03532fb1cbb7e8c1d5cf2e93aa3719f926631cabStephen Gallagher<p>
03532fb1cbb7e8c1d5cf2e93aa3719f926631cabStephen GallagherIn the second part of this document, which deals with configuration
03532fb1cbb7e8c1d5cf2e93aa3719f926631cabStephen Gallagherdirective and context awareness, we will be looking at a module that simply
03532fb1cbb7e8c1d5cf2e93aa3719f926631cabStephen Gallagherwrite out its own configuration to the client.
03532fb1cbb7e8c1d5cf2e93aa3719f926631cabStephen Gallagher</p>
03532fb1cbb7e8c1d5cf2e93aa3719f926631cabStephen Gallagher</section>
03532fb1cbb7e8c1d5cf2e93aa3719f926631cabStephen Gallagher
03532fb1cbb7e8c1d5cf2e93aa3719f926631cabStephen Gallagher<section id="prerequisites"><title>Prerequisites</title>
03532fb1cbb7e8c1d5cf2e93aa3719f926631cabStephen Gallagher<p>
03532fb1cbb7e8c1d5cf2e93aa3719f926631cabStephen GallagherFirst and foremost, you are expected to have a basic knowledge of how the C
03532fb1cbb7e8c1d5cf2e93aa3719f926631cabStephen Gallagherprogramming language works. In most cases, we will try to be as pedagogical
03532fb1cbb7e8c1d5cf2e93aa3719f926631cabStephen Gallagheras possible and link to documents describing the functions used in the
61804568ce5ede3b1a699cda17c033dd6c23f0e3Sumit Boseexamples, but there are also many cases where it is necessary to either
61804568ce5ede3b1a699cda17c033dd6c23f0e3Sumit Bosejust assume that "it works" or do some digging yourself into what the hows
61804568ce5ede3b1a699cda17c033dd6c23f0e3Sumit Boseand whys of various function calls.
03532fb1cbb7e8c1d5cf2e93aa3719f926631cabStephen Gallagher</p>
5f879ab8b6c1cefbc63e1c2303f79b09b6246ca3Stephen Gallagher<p>
5f879ab8b6c1cefbc63e1c2303f79b09b6246ca3Stephen GallagherLastly, you will need to have a basic understanding of how modules are
5f879ab8b6c1cefbc63e1c2303f79b09b6246ca3Stephen Gallagherloaded and configured in the Apache HTTP Server, as well as how to get the headers for
5f879ab8b6c1cefbc63e1c2303f79b09b6246ca3Stephen GallagherApache if you do not have them already, as these are needed for compiling
5f879ab8b6c1cefbc63e1c2303f79b09b6246ca3Stephen Gallaghernew modules.
5f879ab8b6c1cefbc63e1c2303f79b09b6246ca3Stephen Gallagher</p>
5f879ab8b6c1cefbc63e1c2303f79b09b6246ca3Stephen Gallagher</section>
5f879ab8b6c1cefbc63e1c2303f79b09b6246ca3Stephen Gallagher<section id="compiling"><title>Compiling your module</title>
5f879ab8b6c1cefbc63e1c2303f79b09b6246ca3Stephen Gallagher<p>
4343b618051d295cbb1a805a85feb117a91c6945Jakub HrozekTo compile the source code we are building in this document, we will be
4343b618051d295cbb1a805a85feb117a91c6945Jakub Hrozekusing <a href="/programs/apxs.html">APXS</a>. Assuming your source file
4343b618051d295cbb1a805a85feb117a91c6945Jakub Hrozekis called mod_example.c, compiling, installing and activating the module is
4343b618051d295cbb1a805a85feb117a91c6945Jakub Hrozekas simple as:
4343b618051d295cbb1a805a85feb117a91c6945Jakub Hrozek</p>
c7a4383b3b5549d0627c21bb02bd5f0bd46a3531Jakub Hrozek<example><pre>
c7a4383b3b5549d0627c21bb02bd5f0bd46a3531Jakub Hrozekapxs -i -a -c mod_example.c
c7a4383b3b5549d0627c21bb02bd5f0bd46a3531Jakub Hrozek</pre></example>
5f879ab8b6c1cefbc63e1c2303f79b09b6246ca3Stephen Gallagher
03532fb1cbb7e8c1d5cf2e93aa3719f926631cabStephen Gallagher</section>
03532fb1cbb7e8c1d5cf2e93aa3719f926631cabStephen Gallagher</section>
65a8e6e655c22027d3e02ea697972111f2a33e33Jakub Hrozek
03532fb1cbb7e8c1d5cf2e93aa3719f926631cabStephen Gallagher<section id="basics"><title>Defining a module</title>
03532fb1cbb7e8c1d5cf2e93aa3719f926631cabStephen Gallagher<p>
03532fb1cbb7e8c1d5cf2e93aa3719f926631cabStephen Gallagher<img src="/images/build_a_mod_3.png" alt="Module name tags"/><br/>
03532fb1cbb7e8c1d5cf2e93aa3719f926631cabStephen GallagherEvery module starts with the same declaration, or name tag if you will,
03532fb1cbb7e8c1d5cf2e93aa3719f926631cabStephen Gallagherthat defines a module as <em>a separate entity within Apache</em>:</p>
03532fb1cbb7e8c1d5cf2e93aa3719f926631cabStephen Gallagher
03532fb1cbb7e8c1d5cf2e93aa3719f926631cabStephen Gallagher
03532fb1cbb7e8c1d5cf2e93aa3719f926631cabStephen Gallagher<!-- BEGIN EXAMPLE CODE -->
03532fb1cbb7e8c1d5cf2e93aa3719f926631cabStephen Gallagher<highlight language="c">
03532fb1cbb7e8c1d5cf2e93aa3719f926631cabStephen Gallaghermodule AP_MODULE_DECLARE_DATA example_module =
03532fb1cbb7e8c1d5cf2e93aa3719f926631cabStephen Gallagher{
03532fb1cbb7e8c1d5cf2e93aa3719f926631cabStephen Gallagher STANDARD20_MODULE_STUFF,
03532fb1cbb7e8c1d5cf2e93aa3719f926631cabStephen Gallagher create_dir_conf, /* Per-directory configuration handler */
03532fb1cbb7e8c1d5cf2e93aa3719f926631cabStephen Gallagher merge_dir_conf, /* Merge handler for per-directory configurations */
03532fb1cbb7e8c1d5cf2e93aa3719f926631cabStephen Gallagher create_svr_conf, /* Per-server configuration handler */
03532fb1cbb7e8c1d5cf2e93aa3719f926631cabStephen Gallagher merge_svr_conf, /* Merge handler for per-server configurations */
03532fb1cbb7e8c1d5cf2e93aa3719f926631cabStephen Gallagher directives, /* Any directives we may have for httpd */
03532fb1cbb7e8c1d5cf2e93aa3719f926631cabStephen Gallagher register_hooks /* Our hook registering function */
03532fb1cbb7e8c1d5cf2e93aa3719f926631cabStephen Gallagher};
03532fb1cbb7e8c1d5cf2e93aa3719f926631cabStephen Gallagher</highlight>
4cdaf239d4504966bed8ecd5e3fa07def74c7302Sumit Bose<!-- END EXAMPLE CODE -->
4cdaf239d4504966bed8ecd5e3fa07def74c7302Sumit Bose
4cdaf239d4504966bed8ecd5e3fa07def74c7302Sumit Bose<p>
4cdaf239d4504966bed8ecd5e3fa07def74c7302Sumit BoseThis bit of code lets the server know that we have now registered a new module
03532fb1cbb7e8c1d5cf2e93aa3719f926631cabStephen Gallagherin the system, and that its name is <code>example_module</code>. The name
03532fb1cbb7e8c1d5cf2e93aa3719f926631cabStephen Gallagherof the module is used primarily for two things:<br/>
03532fb1cbb7e8c1d5cf2e93aa3719f926631cabStephen Gallagher</p>
03532fb1cbb7e8c1d5cf2e93aa3719f926631cabStephen Gallagher<ul>
294e9a5521d327c5cdc49beeb9cb9e703b3134f1Jan Zeleny<li>Letting the server know how to load the module using the LoadModule</li>
03532fb1cbb7e8c1d5cf2e93aa3719f926631cabStephen Gallagher<li>Setting up a namespace for the module to use in configurations</li>
03532fb1cbb7e8c1d5cf2e93aa3719f926631cabStephen Gallagher</ul>
02ec52b73c1714b877b0b7bc43fbc8d36ad8ca40Jakub Hrozek<p>
03532fb1cbb7e8c1d5cf2e93aa3719f926631cabStephen GallagherFor now, we're only concerned with the first purpose of the module name,
03532fb1cbb7e8c1d5cf2e93aa3719f926631cabStephen Gallagherwhich comes into play when we need to load the module:
03532fb1cbb7e8c1d5cf2e93aa3719f926631cabStephen Gallagher</p>
03532fb1cbb7e8c1d5cf2e93aa3719f926631cabStephen Gallagher<example><pre><a href="/mod/mod_so.html#LoadModule">LoadModule</a> example_module modules/mod_example.so</pre></example>
03532fb1cbb7e8c1d5cf2e93aa3719f926631cabStephen Gallagher<p>
03532fb1cbb7e8c1d5cf2e93aa3719f926631cabStephen GallagherIn essence, this tells the server to open up <code>mod_example.so</code> and look for a module
c0d9babd59c81c12ca182ab3a72176d4fae494a4Yuri Chornoivancalled <code>example_module</code>.
03532fb1cbb7e8c1d5cf2e93aa3719f926631cabStephen Gallagher</p>
03532fb1cbb7e8c1d5cf2e93aa3719f926631cabStephen Gallagher<p>
03532fb1cbb7e8c1d5cf2e93aa3719f926631cabStephen GallagherWithin this name tag of ours is also a bunch of references to how we would
03532fb1cbb7e8c1d5cf2e93aa3719f926631cabStephen Gallagherlike to handle things: Which directives do we respond to in a configuration
03532fb1cbb7e8c1d5cf2e93aa3719f926631cabStephen Gallagherfile or .htaccess, how do we operate within specific contexts, and what
03532fb1cbb7e8c1d5cf2e93aa3719f926631cabStephen Gallagherhandlers are we interested in registering with the Apache HTTP service. We'll
03532fb1cbb7e8c1d5cf2e93aa3719f926631cabStephen Gallagherreturn to all these elements later in this document.
03532fb1cbb7e8c1d5cf2e93aa3719f926631cabStephen Gallagher</p>
03532fb1cbb7e8c1d5cf2e93aa3719f926631cabStephen Gallagher</section>
03532fb1cbb7e8c1d5cf2e93aa3719f926631cabStephen Gallagher<section id="hooking"><title>Getting started: Hooking into the server</title>
03532fb1cbb7e8c1d5cf2e93aa3719f926631cabStephen Gallagher<section id="hook_intro"><title>An introduction to hooks</title>
03532fb1cbb7e8c1d5cf2e93aa3719f926631cabStephen Gallagher<p>
03532fb1cbb7e8c1d5cf2e93aa3719f926631cabStephen GallagherWhen handling requests in Apache HTTP Server 2.4, the first thing you will need to do is
03532fb1cbb7e8c1d5cf2e93aa3719f926631cabStephen Gallaghercreate a hook into the request handling process. A hook is essentially a
03532fb1cbb7e8c1d5cf2e93aa3719f926631cabStephen Gallaghermessage telling the server that you are willing to either serve or at least
03532fb1cbb7e8c1d5cf2e93aa3719f926631cabStephen Gallaghertake a glance at certain requests given by clients. All handlers, whether
03532fb1cbb7e8c1d5cf2e93aa3719f926631cabStephen Gallagherit's mod_rewrite, mod_authn_*, mod_proxy and so on, are hooked into
03532fb1cbb7e8c1d5cf2e93aa3719f926631cabStephen Gallagherspecific parts of the request process. As you are probably aware, modules
03532fb1cbb7e8c1d5cf2e93aa3719f926631cabStephen Gallagherserve different purposes; Some are authentication/authorization handlers,
03532fb1cbb7e8c1d5cf2e93aa3719f926631cabStephen Gallagherothers are file or script handlers while some third modules rewrite URIs or
03532fb1cbb7e8c1d5cf2e93aa3719f926631cabStephen Gallagherproxies content. Furthermore, in the end, it is up to the user of the server
a679f0167b646cffdae86546ed77e105576991b0Pavel Březinahow and when each module will come into place. Thus, the server itself does not
a679f0167b646cffdae86546ed77e105576991b0Pavel Březinapresume to know which module is responsible for handling a specific
a679f0167b646cffdae86546ed77e105576991b0Pavel Březinarequest, and will ask each module whether they have an interest in a given
a679f0167b646cffdae86546ed77e105576991b0Pavel Březinarequest or not. It is then up to each module to either gently decline
a679f0167b646cffdae86546ed77e105576991b0Pavel Březinaserving a request, accept serving it or flat out deny the request from
a679f0167b646cffdae86546ed77e105576991b0Pavel Březinabeing served, as authentication/authorization modules do: <br/>
a679f0167b646cffdae86546ed77e105576991b0Pavel Březina<img src="/images/build_a_mod_2.png" alt="Hook handling in httpd"/><br/>
a679f0167b646cffdae86546ed77e105576991b0Pavel BřezinaTo make it a bit easier for handlers such as our mod_example to know
a679f0167b646cffdae86546ed77e105576991b0Pavel Březinawhether the client is requesting content we should handle or not, the server
a679f0167b646cffdae86546ed77e105576991b0Pavel Březinahas directives for hinting to modules whether their assistance is needed or
a679f0167b646cffdae86546ed77e105576991b0Pavel Březinanot. Two of these are <directive module="mod_mime">AddHandler</directive>
a679f0167b646cffdae86546ed77e105576991b0Pavel Březinaand <directive module="core">SetHandler</directive>. Let's take a look at
a679f0167b646cffdae86546ed77e105576991b0Pavel Březinaan example using <directive module="mod_mime">AddHandler</directive>. In
de4ce3477497c20416c6397adb520bb60f3c6d28Jakub Hrozekour example case, we want every request ending with .sum to be served by
de4ce3477497c20416c6397adb520bb60f3c6d28Jakub Hrozek<code>mod_example</code>, so we'll add a configuration directive that tells
de4ce3477497c20416c6397adb520bb60f3c6d28Jakub Hrozekthe server to do just that:
a679f0167b646cffdae86546ed77e105576991b0Pavel Březina</p>
a679f0167b646cffdae86546ed77e105576991b0Pavel Březina<example><pre>
a679f0167b646cffdae86546ed77e105576991b0Pavel BřezinaAddHandler example-handler .sum
a679f0167b646cffdae86546ed77e105576991b0Pavel Březina</pre></example>
a679f0167b646cffdae86546ed77e105576991b0Pavel Březina<p>
a679f0167b646cffdae86546ed77e105576991b0Pavel BřezinaWhat this tells the server is the following: <em>Whenever we receive a request
a679f0167b646cffdae86546ed77e105576991b0Pavel Březinafor a URI ending in .sum, we are to let all modules know that we are
8a05fd320a44636d120a18eb7e9956c7b35b3138Jakub Hrozeklooking for whoever goes by the name of &quot;example-handler&quot; </em>.
7a7fe9ace6990f20bddccfbb8fbbe91204df979eYassir ElleyThus, when a request is being served that ends in .sum, the server will let all
8a05fd320a44636d120a18eb7e9956c7b35b3138Jakub Hrozekmodules know, that this request should be served by &quot;example-handler
8a05fd320a44636d120a18eb7e9956c7b35b3138Jakub Hrozek&quot;. As you will see later, when we start building mod_example, we will
8a05fd320a44636d120a18eb7e9956c7b35b3138Jakub Hrozekcheck for this handler tag relayed by <code>AddHandler</code> and reply to
8a05fd320a44636d120a18eb7e9956c7b35b3138Jakub Hrozekthe server based on the value of this tag.
8a05fd320a44636d120a18eb7e9956c7b35b3138Jakub Hrozek</p>
19d56eacc786d83fcea1805743370c53098ef552Jakub Hrozek</section>
8a05fd320a44636d120a18eb7e9956c7b35b3138Jakub Hrozek<section id="hook_declaration"><title>Hooking into httpd</title>
8a05fd320a44636d120a18eb7e9956c7b35b3138Jakub Hrozek<p>
8a05fd320a44636d120a18eb7e9956c7b35b3138Jakub HrozekTo begin with, we only want to create a simple handler, that replies to the
8a05fd320a44636d120a18eb7e9956c7b35b3138Jakub Hrozekclient browser when a specific URL is requested, so we won't bother setting
1ce58f139699dd26b8888f4131c996263b6a80a5Jakub Hrozekup configuration handlers and directives just yet. Our initial module
1ce58f139699dd26b8888f4131c996263b6a80a5Jakub Hrozekdefinition will look like this:</p>
1ce58f139699dd26b8888f4131c996263b6a80a5Jakub Hrozek
1ce58f139699dd26b8888f4131c996263b6a80a5Jakub Hrozek
1ce58f139699dd26b8888f4131c996263b6a80a5Jakub Hrozek<!-- BEGIN EXAMPLE CODE -->
1ce58f139699dd26b8888f4131c996263b6a80a5Jakub Hrozek<highlight language="c">
1ce58f139699dd26b8888f4131c996263b6a80a5Jakub Hrozekmodule AP_MODULE_DECLARE_DATA example_module =
1ce58f139699dd26b8888f4131c996263b6a80a5Jakub Hrozek{
1ce58f139699dd26b8888f4131c996263b6a80a5Jakub Hrozek STANDARD20_MODULE_STUFF,
1ce58f139699dd26b8888f4131c996263b6a80a5Jakub Hrozek NULL,
1ce58f139699dd26b8888f4131c996263b6a80a5Jakub Hrozek NULL,
1ce58f139699dd26b8888f4131c996263b6a80a5Jakub Hrozek NULL,
1ce58f139699dd26b8888f4131c996263b6a80a5Jakub Hrozek NULL,
1ce58f139699dd26b8888f4131c996263b6a80a5Jakub Hrozek NULL,
1ce58f139699dd26b8888f4131c996263b6a80a5Jakub Hrozek register_hooks /* Our hook registering function */
1ce58f139699dd26b8888f4131c996263b6a80a5Jakub Hrozek};
1ce58f139699dd26b8888f4131c996263b6a80a5Jakub Hrozek</highlight>
1ce58f139699dd26b8888f4131c996263b6a80a5Jakub Hrozek<!-- END EXAMPLE CODE -->
1ce58f139699dd26b8888f4131c996263b6a80a5Jakub Hrozek
1ce58f139699dd26b8888f4131c996263b6a80a5Jakub Hrozek
1ce58f139699dd26b8888f4131c996263b6a80a5Jakub Hrozek<p>This lets the server know that we are not interesting in anything fancy, we
1ce58f139699dd26b8888f4131c996263b6a80a5Jakub Hrozekjust want to hook onto the requests and possibly handle some of them. </p>
1ce58f139699dd26b8888f4131c996263b6a80a5Jakub Hrozek
1ce58f139699dd26b8888f4131c996263b6a80a5Jakub Hrozek<p> The reference in our example declaration, <code>register_hooks</code>
1ce58f139699dd26b8888f4131c996263b6a80a5Jakub Hrozekis the name of a function we will create to manage how we hook onto the
1ce58f139699dd26b8888f4131c996263b6a80a5Jakub Hrozekrequest process. In this example module, the function has just one purpose;
1ce58f139699dd26b8888f4131c996263b6a80a5Jakub HrozekTo create a simple hook that gets called after all the rewrites, access
1ce58f139699dd26b8888f4131c996263b6a80a5Jakub Hrozekcontrol etc has been handled. Thus, we will let the server know, that we want
1ce58f139699dd26b8888f4131c996263b6a80a5Jakub Hrozekto hook into its process as one of the last modules:
1ce58f139699dd26b8888f4131c996263b6a80a5Jakub Hrozek</p>
8a05fd320a44636d120a18eb7e9956c7b35b3138Jakub Hrozek
8a05fd320a44636d120a18eb7e9956c7b35b3138Jakub Hrozek<!-- BEGIN EXAMPLE CODE -->
1ce58f139699dd26b8888f4131c996263b6a80a5Jakub Hrozek<highlight language="c">
1ce58f139699dd26b8888f4131c996263b6a80a5Jakub Hrozekstatic void register_hooks(apr_pool_t *pool)
1ce58f139699dd26b8888f4131c996263b6a80a5Jakub Hrozek{
1ce58f139699dd26b8888f4131c996263b6a80a5Jakub Hrozek /* Create a hook in the request handler, so we get called when a request arrives */
1ce58f139699dd26b8888f4131c996263b6a80a5Jakub Hrozek ap_hook_handler(example_handler, NULL, NULL, APR_HOOK_LAST);
1ce58f139699dd26b8888f4131c996263b6a80a5Jakub Hrozek}
1ce58f139699dd26b8888f4131c996263b6a80a5Jakub Hrozek</highlight>
1ce58f139699dd26b8888f4131c996263b6a80a5Jakub Hrozek<!-- END EXAMPLE CODE -->
8a05fd320a44636d120a18eb7e9956c7b35b3138Jakub Hrozek
8a05fd320a44636d120a18eb7e9956c7b35b3138Jakub Hrozek<p>
8a05fd320a44636d120a18eb7e9956c7b35b3138Jakub HrozekThe <code>example_handler</code> reference is the function that will handle
8a05fd320a44636d120a18eb7e9956c7b35b3138Jakub Hrozekthe request. We will discuss how to create a handler in the next chapter.
8a05fd320a44636d120a18eb7e9956c7b35b3138Jakub Hrozek</p>
8a05fd320a44636d120a18eb7e9956c7b35b3138Jakub Hrozek</section>
8a05fd320a44636d120a18eb7e9956c7b35b3138Jakub Hrozek<section id="hook_others"><title>Other useful hooks</title>
ba4a81e933deebb416603369b447ead6ebaa040dJakub Hrozek<p>
ba4a81e933deebb416603369b447ead6ebaa040dJakub HrozekHooking into the request handling phase is but one of many hooks that you
ba4a81e933deebb416603369b447ead6ebaa040dJakub Hrozekcan create. Some other ways of hooking are:
ba4a81e933deebb416603369b447ead6ebaa040dJakub Hrozek</p>
ba4a81e933deebb416603369b447ead6ebaa040dJakub Hrozek<ul>
fdaaf2525e333af04ee9b48429b6766b5fd6cab6Jakub Hrozek<li><code>ap_hook_child_init</code>: Place a hook that executes when a child process is spawned (commonly used for initializing modules after the server has forked)</li>
fdaaf2525e333af04ee9b48429b6766b5fd6cab6Jakub Hrozek<li><code>ap_hook_pre_config</code>: Place a hook that executes before any configuration data has been read (very early hook)</li>
fdaaf2525e333af04ee9b48429b6766b5fd6cab6Jakub Hrozek<li><code>ap_hook_post_config</code>: Place a hook that executes after configuration has been parsed, but before the server has forked</li>
fdaaf2525e333af04ee9b48429b6766b5fd6cab6Jakub Hrozek<li><code>ap_hook_translate_name</code>: Place a hook that executes when a URI needs to be translated into a filename on the server (think <code>mod_rewrite</code>)</li>
fdaaf2525e333af04ee9b48429b6766b5fd6cab6Jakub Hrozek</ul>
fdaaf2525e333af04ee9b48429b6766b5fd6cab6Jakub Hrozek
fdaaf2525e333af04ee9b48429b6766b5fd6cab6Jakub Hrozek</section>
fdaaf2525e333af04ee9b48429b6766b5fd6cab6Jakub Hrozek</section>
fdaaf2525e333af04ee9b48429b6766b5fd6cab6Jakub Hrozek
fdaaf2525e333af04ee9b48429b6766b5fd6cab6Jakub Hrozek<section id="handling"><title>Building a handler</title>
fdaaf2525e333af04ee9b48429b6766b5fd6cab6Jakub Hrozek<p>
fdaaf2525e333af04ee9b48429b6766b5fd6cab6Jakub HrozekA handler is essentially a function that receives a callback when a request
fdaaf2525e333af04ee9b48429b6766b5fd6cab6Jakub Hrozekto the server is made. It is passed a record of the current request (how it was
ba4a81e933deebb416603369b447ead6ebaa040dJakub Hrozekmade, which headers and requests were passed along, who's giving the
ba4a81e933deebb416603369b447ead6ebaa040dJakub Hrozekrequest and so on), and is put in charge of either telling the server that it's
ba4a81e933deebb416603369b447ead6ebaa040dJakub Hrozeknot interested in the request or handle the request with the tools provided.
ba4a81e933deebb416603369b447ead6ebaa040dJakub Hrozek</p>
ba4a81e933deebb416603369b447ead6ebaa040dJakub Hrozek<section id="simple_handler"><title>A simple &quot;Hello, world!&quot;
ba4a81e933deebb416603369b447ead6ebaa040dJakub Hrozekhandler</title>
ba4a81e933deebb416603369b447ead6ebaa040dJakub Hrozek<p>Let's start off by making a very simple request handler
60cab26b12df9a2153823972cde0c38ca86e01b9Yassir Elleythat does the following:
60cab26b12df9a2153823972cde0c38ca86e01b9Yassir Elley</p>
60cab26b12df9a2153823972cde0c38ca86e01b9Yassir Elley<ol>
60cab26b12df9a2153823972cde0c38ca86e01b9Yassir Elley<li>Check that this is a request that should be served by &quot;example-handler&quot;</li>
60cab26b12df9a2153823972cde0c38ca86e01b9Yassir Elley<li>Set the content type of our output to <code>text/html</code></li>
60cab26b12df9a2153823972cde0c38ca86e01b9Yassir Elley<li>Write &quot;Hello, world!&quot; back to the client browser</li>
60cab26b12df9a2153823972cde0c38ca86e01b9Yassir Elley<li>Let the server know that we took care of this request and everything went fine</li>
60cab26b12df9a2153823972cde0c38ca86e01b9Yassir Elley</ol>
60cab26b12df9a2153823972cde0c38ca86e01b9Yassir Elley<p>
60cab26b12df9a2153823972cde0c38ca86e01b9Yassir ElleyIn C code, our example handler will now look like this:
60cab26b12df9a2153823972cde0c38ca86e01b9Yassir Elley</p>
60cab26b12df9a2153823972cde0c38ca86e01b9Yassir Elley
60cab26b12df9a2153823972cde0c38ca86e01b9Yassir Elley<!-- BEGIN EXAMPLE CODE -->
60cab26b12df9a2153823972cde0c38ca86e01b9Yassir Elley<highlight language="c">
60cab26b12df9a2153823972cde0c38ca86e01b9Yassir Elleystatic int example_handler(request_rec *r)
60cab26b12df9a2153823972cde0c38ca86e01b9Yassir Elley{
60cab26b12df9a2153823972cde0c38ca86e01b9Yassir Elley /* First off, we need to check if this is a call for the "example-handler" handler.
60cab26b12df9a2153823972cde0c38ca86e01b9Yassir Elley * If it is, we accept it and do our things, if not, we simply return DECLINED,
60cab26b12df9a2153823972cde0c38ca86e01b9Yassir Elley * and the server will try somewhere else.
60cab26b12df9a2153823972cde0c38ca86e01b9Yassir Elley */
60cab26b12df9a2153823972cde0c38ca86e01b9Yassir Elley if (!r->handler || strcmp(r->handler, "example-handler")) return (DECLINED);
60cab26b12df9a2153823972cde0c38ca86e01b9Yassir Elley
60cab26b12df9a2153823972cde0c38ca86e01b9Yassir Elley /* Now that we are handling this request, we'll write out "Hello, world!" to the client.
60cab26b12df9a2153823972cde0c38ca86e01b9Yassir Elley * To do so, we must first set the appropriate content type, followed by our output.
60cab26b12df9a2153823972cde0c38ca86e01b9Yassir Elley */
60cab26b12df9a2153823972cde0c38ca86e01b9Yassir Elley ap_set_content_type(r, "text/html");
60cab26b12df9a2153823972cde0c38ca86e01b9Yassir Elley ap_rprintf(r, "Hello, world!");
60cab26b12df9a2153823972cde0c38ca86e01b9Yassir Elley
60cab26b12df9a2153823972cde0c38ca86e01b9Yassir Elley /* Lastly, we must tell the server that we took care of this request and everything went fine.
60cab26b12df9a2153823972cde0c38ca86e01b9Yassir Elley * We do so by simply returning the value OK to the server.
60cab26b12df9a2153823972cde0c38ca86e01b9Yassir Elley */
60cab26b12df9a2153823972cde0c38ca86e01b9Yassir Elley return OK;
60cab26b12df9a2153823972cde0c38ca86e01b9Yassir Elley}
60cab26b12df9a2153823972cde0c38ca86e01b9Yassir Elley</highlight>
60cab26b12df9a2153823972cde0c38ca86e01b9Yassir Elley<!-- END EXAMPLE CODE -->
60cab26b12df9a2153823972cde0c38ca86e01b9Yassir Elley
60cab26b12df9a2153823972cde0c38ca86e01b9Yassir Elley<p>
60cab26b12df9a2153823972cde0c38ca86e01b9Yassir ElleyNow, we put all we have learned together and end up with a program that
60cab26b12df9a2153823972cde0c38ca86e01b9Yassir Elleylooks like
60cab26b12df9a2153823972cde0c38ca86e01b9Yassir Elley<a href="http://people.apache.org/~humbedooh/mods/examples/mod_example_1.c">mod_example_1.c</a>
60cab26b12df9a2153823972cde0c38ca86e01b9Yassir Elley. The functions used in this example will be explained later in the section
60cab26b12df9a2153823972cde0c38ca86e01b9Yassir Elley<a href= "#functions">&quot;Some useful functions you should know&quot;</a>.
60cab26b12df9a2153823972cde0c38ca86e01b9Yassir Elley</p>
60cab26b12df9a2153823972cde0c38ca86e01b9Yassir Elley</section>
60cab26b12df9a2153823972cde0c38ca86e01b9Yassir Elley<section id="request_rec"><title>The request_rec structure</title>
60cab26b12df9a2153823972cde0c38ca86e01b9Yassir Elley<p>The most essential part of any request is the <em>request record
60cab26b12df9a2153823972cde0c38ca86e01b9Yassir Elley</em>. In a call to a handler function, this is represented by the <code>
60cab26b12df9a2153823972cde0c38ca86e01b9Yassir Elleyrequest_req* </code> structure passed along with every call that is made.
60cab26b12df9a2153823972cde0c38ca86e01b9Yassir ElleyThis struct, typically just refered to as <code>r</code> in modules,
60cab26b12df9a2153823972cde0c38ca86e01b9Yassir Elleycontains all the information you need for your module to fully process any
60cab26b12df9a2153823972cde0c38ca86e01b9Yassir ElleyHTTP request and respond accordingly.</p> <p>Some key elements of the <code>
60cab26b12df9a2153823972cde0c38ca86e01b9Yassir Elleyrequest_req </code> structure are:
60cab26b12df9a2153823972cde0c38ca86e01b9Yassir Elley</p>
60cab26b12df9a2153823972cde0c38ca86e01b9Yassir Elley<ul>
60cab26b12df9a2153823972cde0c38ca86e01b9Yassir Elley<li><code>r-&gt;handler (char*):</code> Contains the name of the handler the server is currently asking to do the handling of this request</li>
60cab26b12df9a2153823972cde0c38ca86e01b9Yassir Elley<li><code>r-&gt;method (char*):</code> Contains the HTTP method being used, f.x. GET or POST</li>
60cab26b12df9a2153823972cde0c38ca86e01b9Yassir Elley<li><code>r-&gt;filename (char*):</code> Contains the translated filename the client is requesting</li>
60cab26b12df9a2153823972cde0c38ca86e01b9Yassir Elley<li><code>r-&gt;args (char*):</code> Contains the query string of the request, if any</li>
60cab26b12df9a2153823972cde0c38ca86e01b9Yassir Elley<li><code>r-&gt;headers_in (apr_table_t*):</code> Contains all the headers sent by the client</li>
60cab26b12df9a2153823972cde0c38ca86e01b9Yassir Elley<li><code>r-&gt;connection (conn_rec*):</code> A record containing information about the current connection</li>
60cab26b12df9a2153823972cde0c38ca86e01b9Yassir Elley<li><code>r-&gt;useragent_ip (char*):</code> The IP address of the client connecting to us</li>
60cab26b12df9a2153823972cde0c38ca86e01b9Yassir Elley<li><code>r-&gt;pool (apr_pool_t*)</code>: The memory pool of this request. We'll discuss this in the &quot;
60cab26b12df9a2153823972cde0c38ca86e01b9Yassir Elley<a href="#memory">Memory management</a>&quot; chapter.</li>
60cab26b12df9a2153823972cde0c38ca86e01b9Yassir Elley</ul>
ff4b603cc14ea6ea15caaf89a03e927920124af4Yassir Elley<p>
ff4b603cc14ea6ea15caaf89a03e927920124af4Yassir ElleyA complete list of all the values contained with in the <code>request_req</code> structure can be found in
ff4b603cc14ea6ea15caaf89a03e927920124af4Yassir Elleythe <a href="http://svn.apache.org/repos/asf/httpd/httpd/trunk/include/httpd.h"><code>httpd.h</code></a> header
ff4b603cc14ea6ea15caaf89a03e927920124af4Yassir Elleyfile or at <a href="http://ci.apache.org/projects/httpd/trunk/doxygen/structrequest__rec.html">http://ci.apache.org/projects/httpd/trunk/doxygen/structrequest__rec.html</a>.
ff4b603cc14ea6ea15caaf89a03e927920124af4Yassir Elley</p>
ff4b603cc14ea6ea15caaf89a03e927920124af4Yassir Elley
ff4b603cc14ea6ea15caaf89a03e927920124af4Yassir Elley
ff4b603cc14ea6ea15caaf89a03e927920124af4Yassir Elley<p>
ff4b603cc14ea6ea15caaf89a03e927920124af4Yassir ElleyLet's try out some of these variables in another example handler:<br/>
ff4b603cc14ea6ea15caaf89a03e927920124af4Yassir Elley</p>
ff4b603cc14ea6ea15caaf89a03e927920124af4Yassir Elley
ff4b603cc14ea6ea15caaf89a03e927920124af4Yassir Elley<!-- BEGIN EXAMPLE CODE -->
ff4b603cc14ea6ea15caaf89a03e927920124af4Yassir Elley<highlight language="c">
ff4b603cc14ea6ea15caaf89a03e927920124af4Yassir Elleystatic int example_handler(request_rec *r)
ff4b603cc14ea6ea15caaf89a03e927920124af4Yassir Elley{
ff4b603cc14ea6ea15caaf89a03e927920124af4Yassir Elley /* Set the appropriate content type */
74e95cfd9d3939dfe9417d79d2f6fc79b361405fJakub Hrozek ap_set_content_type(r, &quot;text/html&quot;);
74e95cfd9d3939dfe9417d79d2f6fc79b361405fJakub Hrozek
74e95cfd9d3939dfe9417d79d2f6fc79b361405fJakub Hrozek /* Print out the IP address of the client connecting to us: */
74e95cfd9d3939dfe9417d79d2f6fc79b361405fJakub Hrozek ap_rprintf(r, &quot;&lt;h2&gt;Hello, %s!&lt;/h2&gt;&quot;, r-&gt;useragent_ip);
74e95cfd9d3939dfe9417d79d2f6fc79b361405fJakub Hrozek
74e95cfd9d3939dfe9417d79d2f6fc79b361405fJakub Hrozek /* If we were reached through a GET or a POST request, be happy, else sad. */
31c1f3a2e699fad82258aab83d756e1e7ca923a2Jakub Hrozek if ( !strcmp(r-&gt;method, &quot;POST&quot;) || !strcmp(r-&gt;method, &quot;GET&quot;) ) {
31c1f3a2e699fad82258aab83d756e1e7ca923a2Jakub Hrozek ap_rputs(&quot;You used a GET or a POST method, that makes us happy!&lt;br/&gt;&quot;, r);
31c1f3a2e699fad82258aab83d756e1e7ca923a2Jakub Hrozek }
593c4a91596640eafe798e8aac700d0f3ce7ba37Ondrej Kos else {
593c4a91596640eafe798e8aac700d0f3ce7ba37Ondrej Kos ap_rputs(&quot;You did not use POST or GET, that makes us sad :(&lt;br/&gt;&quot;, r);
593c4a91596640eafe798e8aac700d0f3ce7ba37Ondrej Kos }
593c4a91596640eafe798e8aac700d0f3ce7ba37Ondrej Kos
74e95cfd9d3939dfe9417d79d2f6fc79b361405fJakub Hrozek /* Lastly, if there was a query string, let's print that too! */
74e95cfd9d3939dfe9417d79d2f6fc79b361405fJakub Hrozek if (r-&gt;args) {
74e95cfd9d3939dfe9417d79d2f6fc79b361405fJakub Hrozek ap_rprintf(r, &quot;Your query string was: %s&quot;, r-&gt;args);
74e95cfd9d3939dfe9417d79d2f6fc79b361405fJakub Hrozek }
74e95cfd9d3939dfe9417d79d2f6fc79b361405fJakub Hrozek return OK;
74e95cfd9d3939dfe9417d79d2f6fc79b361405fJakub Hrozek}
74e95cfd9d3939dfe9417d79d2f6fc79b361405fJakub Hrozek</highlight>
ad1be6fd04234f61f108773ff39aa7485abda47cJakub Hrozek<!-- END EXAMPLE CODE -->
74e95cfd9d3939dfe9417d79d2f6fc79b361405fJakub Hrozek
74e95cfd9d3939dfe9417d79d2f6fc79b361405fJakub Hrozek</section>
74e95cfd9d3939dfe9417d79d2f6fc79b361405fJakub Hrozek
74e95cfd9d3939dfe9417d79d2f6fc79b361405fJakub Hrozek<section id="return_value"><title>Return values</title>
74e95cfd9d3939dfe9417d79d2f6fc79b361405fJakub Hrozek<p>
74e95cfd9d3939dfe9417d79d2f6fc79b361405fJakub HrozekApache relies on return values from handlers to signify whether a request
74e95cfd9d3939dfe9417d79d2f6fc79b361405fJakub Hrozekwas handled or not, and if so, whether the request went well or not. If a
74e95cfd9d3939dfe9417d79d2f6fc79b361405fJakub Hrozekmodule is not interested in handling a specific request, it should always
74e95cfd9d3939dfe9417d79d2f6fc79b361405fJakub Hrozekreturn the value <code>DECLINED</code>. If it is handling a request, it
74e95cfd9d3939dfe9417d79d2f6fc79b361405fJakub Hrozekshould either return the generic value <code>OK</code>, or a specific HTTP
74e95cfd9d3939dfe9417d79d2f6fc79b361405fJakub Hrozekstatus code, for example:
74e95cfd9d3939dfe9417d79d2f6fc79b361405fJakub Hrozek</p>
74e95cfd9d3939dfe9417d79d2f6fc79b361405fJakub Hrozek
74e95cfd9d3939dfe9417d79d2f6fc79b361405fJakub Hrozek<!-- BEGIN EXAMPLE CODE -->
74e95cfd9d3939dfe9417d79d2f6fc79b361405fJakub Hrozek<highlight language="c">
74e95cfd9d3939dfe9417d79d2f6fc79b361405fJakub Hrozekstatic int example_handler(request_rec *r)
74e95cfd9d3939dfe9417d79d2f6fc79b361405fJakub Hrozek{
74e95cfd9d3939dfe9417d79d2f6fc79b361405fJakub Hrozek /* Return 404: Not found */
74e95cfd9d3939dfe9417d79d2f6fc79b361405fJakub Hrozek return HTTP_NOT_FOUND;
74e95cfd9d3939dfe9417d79d2f6fc79b361405fJakub Hrozek}
74e95cfd9d3939dfe9417d79d2f6fc79b361405fJakub Hrozek</highlight>
74e95cfd9d3939dfe9417d79d2f6fc79b361405fJakub Hrozek<!-- END EXAMPLE CODE -->
74e95cfd9d3939dfe9417d79d2f6fc79b361405fJakub Hrozek
74e95cfd9d3939dfe9417d79d2f6fc79b361405fJakub Hrozek<p>
74e95cfd9d3939dfe9417d79d2f6fc79b361405fJakub HrozekReturning <code>OK</code> or a HTTP status code does not necessarily mean
74e95cfd9d3939dfe9417d79d2f6fc79b361405fJakub Hrozekthat the request will end. The server may still have other handlers that are
74e95cfd9d3939dfe9417d79d2f6fc79b361405fJakub Hrozekinterested in this request, for instance the logging modules which, upon a
65e454c64dbeb4b74e0cc4ad952a54861dc0c3e4Jakub Hrozeksuccessful request, will write down a summary of what was requested and how
74e95cfd9d3939dfe9417d79d2f6fc79b361405fJakub Hrozekit went. To do a full stop and prevent any further processing after your
74e95cfd9d3939dfe9417d79d2f6fc79b361405fJakub Hrozekmodule is done, you can return the value <code>DONE</code> to let the server
74e95cfd9d3939dfe9417d79d2f6fc79b361405fJakub Hrozekknow that it should cease all activity on this request and carry on with
74e95cfd9d3939dfe9417d79d2f6fc79b361405fJakub Hrozekthe next, without informing other handlers.
74e95cfd9d3939dfe9417d79d2f6fc79b361405fJakub Hrozek<br/>
74e95cfd9d3939dfe9417d79d2f6fc79b361405fJakub Hrozek<strong>General response codes:</strong>
74e95cfd9d3939dfe9417d79d2f6fc79b361405fJakub Hrozek</p>
74e95cfd9d3939dfe9417d79d2f6fc79b361405fJakub Hrozek<ul>
74e95cfd9d3939dfe9417d79d2f6fc79b361405fJakub Hrozek<li><code>DECLINED</code>: We are not handling this request</li>
74e95cfd9d3939dfe9417d79d2f6fc79b361405fJakub Hrozek<li><code>OK</code>: We handled this request and it went well</li>
74e95cfd9d3939dfe9417d79d2f6fc79b361405fJakub Hrozek<li><code>DONE</code>: We handled this request and the server should just close this thread without further processing</li>
74e95cfd9d3939dfe9417d79d2f6fc79b361405fJakub Hrozek</ul>
74e95cfd9d3939dfe9417d79d2f6fc79b361405fJakub Hrozek<p>
74e95cfd9d3939dfe9417d79d2f6fc79b361405fJakub Hrozek<strong>HTTP specific return codes (excerpt):</strong>
74e95cfd9d3939dfe9417d79d2f6fc79b361405fJakub Hrozek</p>
74e95cfd9d3939dfe9417d79d2f6fc79b361405fJakub Hrozek<ul>
74e95cfd9d3939dfe9417d79d2f6fc79b361405fJakub Hrozek<li><code>HTTP_OK (200)</code>: Request was okay</li>
74e95cfd9d3939dfe9417d79d2f6fc79b361405fJakub Hrozek<li><code>HTTP_MOVED_PERMANENTLY (301)</code>: The resource has moved to a new URL</li>
74e95cfd9d3939dfe9417d79d2f6fc79b361405fJakub Hrozek<li><code>HTTP_UNAUTHORIZED (401)</code>: Client is not authorized to visit this page</li>
74e95cfd9d3939dfe9417d79d2f6fc79b361405fJakub Hrozek<li><code>HTTP_FORBIDDEN (403)</code>: Permission denied</li>
74e95cfd9d3939dfe9417d79d2f6fc79b361405fJakub Hrozek<li><code>HTTP_NOT_FOUND (404)</code>: File not found</li>
74e95cfd9d3939dfe9417d79d2f6fc79b361405fJakub Hrozek<li><code>HTTP_INTERNAL_SERVER_ERROR (500)</code>: Internal server error (self explanatory)</li>
74e95cfd9d3939dfe9417d79d2f6fc79b361405fJakub Hrozek</ul>
74e95cfd9d3939dfe9417d79d2f6fc79b361405fJakub Hrozek</section>
74e95cfd9d3939dfe9417d79d2f6fc79b361405fJakub Hrozek
74e95cfd9d3939dfe9417d79d2f6fc79b361405fJakub Hrozek<section id="functions"><title>Some useful functions you should know</title>
74e95cfd9d3939dfe9417d79d2f6fc79b361405fJakub Hrozek
74e95cfd9d3939dfe9417d79d2f6fc79b361405fJakub Hrozek<ul>
74e95cfd9d3939dfe9417d79d2f6fc79b361405fJakub Hrozek<li>
74e95cfd9d3939dfe9417d79d2f6fc79b361405fJakub Hrozek <code>ap_rputs(const char *string, request_req *r)</code>: <br/>
74e95cfd9d3939dfe9417d79d2f6fc79b361405fJakub Hrozek Sends a string of text to the client. This is a shorthand version of <a
74e95cfd9d3939dfe9417d79d2f6fc79b361405fJakub Hrozek href="http://ci.apache.org/projects/httpd/trunk/doxygen/group__APACHE__CORE__PROTO.html#gac827cd0537d2b6213a7c06d7c26cc36e">
74e95cfd9d3939dfe9417d79d2f6fc79b361405fJakub Hrozek ap_rwrite</a>.
74e95cfd9d3939dfe9417d79d2f6fc79b361405fJakub Hrozek
74e95cfd9d3939dfe9417d79d2f6fc79b361405fJakub Hrozek
74e95cfd9d3939dfe9417d79d2f6fc79b361405fJakub Hrozek<!-- BEGIN EXAMPLE CODE -->
74e95cfd9d3939dfe9417d79d2f6fc79b361405fJakub Hrozek<highlight language="c">ap_rputs("Hello, world!", r);</highlight>
74e95cfd9d3939dfe9417d79d2f6fc79b361405fJakub Hrozek<!-- END EXAMPLE CODE -->
74e95cfd9d3939dfe9417d79d2f6fc79b361405fJakub Hrozek
74e95cfd9d3939dfe9417d79d2f6fc79b361405fJakub Hrozek
74e95cfd9d3939dfe9417d79d2f6fc79b361405fJakub Hrozek</li>
74e95cfd9d3939dfe9417d79d2f6fc79b361405fJakub Hrozek<li>
74e95cfd9d3939dfe9417d79d2f6fc79b361405fJakub Hrozek <code>
74e95cfd9d3939dfe9417d79d2f6fc79b361405fJakub Hrozek <a href="http://ci.apache.org/projects/httpd/trunk/doxygen/group__APACHE__CORE__PROTO.html#ga5e91eb6ca777c9a427b2e82bf1eeb81d">ap_rprintf</a></code>: <br/>
74e95cfd9d3939dfe9417d79d2f6fc79b361405fJakub Hrozek This function works just like <code>printf</code>, except it sends the result to the client.
74e95cfd9d3939dfe9417d79d2f6fc79b361405fJakub Hrozek
74e95cfd9d3939dfe9417d79d2f6fc79b361405fJakub Hrozek
591b0325f5d6f70ae71e61a8c563b437acfb1884Jakub Hrozek<!-- BEGIN EXAMPLE CODE -->
ae0a5011e2644eaa482ea1b9e1451eff05c676b9Lukas Slebodnik<highlight language="c">ap_rprintf(r, "Hello, %s!", r->useragent_ip);</highlight>
edaa983d094c239c3e1ba667bcd20ed3934be3b8Sumit Bose<!-- END EXAMPLE CODE -->
edaa983d094c239c3e1ba667bcd20ed3934be3b8Sumit Bose
edaa983d094c239c3e1ba667bcd20ed3934be3b8Sumit Bose</li>
edaa983d094c239c3e1ba667bcd20ed3934be3b8Sumit Bose<li>
edaa983d094c239c3e1ba667bcd20ed3934be3b8Sumit Bose <code>
edaa983d094c239c3e1ba667bcd20ed3934be3b8Sumit Bose <a href="http://ci.apache.org/projects/httpd/trunk/doxygen/group__APACHE__CORE__PROTO.html#gaa2f8412c400197338ec509f4a45e4579">ap_set_content_type</a>(request_req *r, const char *type)</code>: <br/>
edaa983d094c239c3e1ba667bcd20ed3934be3b8Sumit Bose Sets the content type of the output you are sending.
edaa983d094c239c3e1ba667bcd20ed3934be3b8Sumit Bose
edaa983d094c239c3e1ba667bcd20ed3934be3b8Sumit Bose
edaa983d094c239c3e1ba667bcd20ed3934be3b8Sumit Bose<!-- BEGIN EXAMPLE CODE -->
edaa983d094c239c3e1ba667bcd20ed3934be3b8Sumit Bose<highlight language="c">ap_set_content_type(r, "text/plain"); /* force a raw text output */</highlight>
edaa983d094c239c3e1ba667bcd20ed3934be3b8Sumit Bose<!-- END EXAMPLE CODE -->
edaa983d094c239c3e1ba667bcd20ed3934be3b8Sumit Bose
edaa983d094c239c3e1ba667bcd20ed3934be3b8Sumit Bose</li>
edaa983d094c239c3e1ba667bcd20ed3934be3b8Sumit Bose
edaa983d094c239c3e1ba667bcd20ed3934be3b8Sumit Bose
edaa983d094c239c3e1ba667bcd20ed3934be3b8Sumit Bose</ul>
edaa983d094c239c3e1ba667bcd20ed3934be3b8Sumit Bose</section>
edaa983d094c239c3e1ba667bcd20ed3934be3b8Sumit Bose
03532fb1cbb7e8c1d5cf2e93aa3719f926631cabStephen Gallagher<section id="memory"><title>Memory management</title>
03532fb1cbb7e8c1d5cf2e93aa3719f926631cabStephen Gallagher<p>
03532fb1cbb7e8c1d5cf2e93aa3719f926631cabStephen GallagherManaging your resources in Apache HTTP Server 2.4 is quite easy, thanks to the memory pool
03532fb1cbb7e8c1d5cf2e93aa3719f926631cabStephen Gallaghersystem. In essence, each server, connection and request have their own
03532fb1cbb7e8c1d5cf2e93aa3719f926631cabStephen Gallaghermemory pool that gets cleaned up when its scope ends, e.g. when a request
03532fb1cbb7e8c1d5cf2e93aa3719f926631cabStephen Gallagheris done or when a server process shuts down. All your module needs to do is
03532fb1cbb7e8c1d5cf2e93aa3719f926631cabStephen Gallagherlatch onto this memory pool, and you won't have to worry about having to
03532fb1cbb7e8c1d5cf2e93aa3719f926631cabStephen Gallagherclean up after yourself - pretty neat, huh?
5f879ab8b6c1cefbc63e1c2303f79b09b6246ca3Stephen Gallagher</p>
5f879ab8b6c1cefbc63e1c2303f79b09b6246ca3Stephen Gallagher
03532fb1cbb7e8c1d5cf2e93aa3719f926631cabStephen Gallagher<p>
03532fb1cbb7e8c1d5cf2e93aa3719f926631cabStephen GallagherIn our module, we will primarily be allocating memory for each request, so
03532fb1cbb7e8c1d5cf2e93aa3719f926631cabStephen Gallagherit's appropriate to use the <code>r-&gt;pool</code>
03532fb1cbb7e8c1d5cf2e93aa3719f926631cabStephen Gallagherreference when creating new objects. A few of the functions for allocating
03532fb1cbb7e8c1d5cf2e93aa3719f926631cabStephen Gallaghermemory within a pool are:
03532fb1cbb7e8c1d5cf2e93aa3719f926631cabStephen Gallagher</p>
03532fb1cbb7e8c1d5cf2e93aa3719f926631cabStephen Gallagher<ul>
03532fb1cbb7e8c1d5cf2e93aa3719f926631cabStephen Gallagher<li><code>void* <a href="http://apr.apache.org/docs/apr/1.4/group__apr__pools.html#ga85f1e193c31d109affda72f9a92c6915">apr_palloc</a>(
03532fb1cbb7e8c1d5cf2e93aa3719f926631cabStephen Gallagherapr_pool_t *p, apr_size_t size)</code>: Allocates <code>size</code> number of bytes in the pool for you</li>
03532fb1cbb7e8c1d5cf2e93aa3719f926631cabStephen Gallagher<li><code>void* <a href="http://apr.apache.org/docs/apr/1.4/group__apr__pools.html#gaf61c098ad258069d64cdf8c0a9369f9e">apr_pcalloc</a>(
03532fb1cbb7e8c1d5cf2e93aa3719f926631cabStephen Gallagherapr_pool_t *p, apr_size_t size)</code>: Allocates <code>size</code> number of bytes in the pool for you and sets all bytes to 0</li>
03532fb1cbb7e8c1d5cf2e93aa3719f926631cabStephen Gallagher<li><code>char* <a href="http://apr.apache.org/docs/apr/1.4/group__apr__strings.html#gabc79e99ff19abbd7cfd18308c5f85d47">apr_pstrdup</a>(
03532fb1cbb7e8c1d5cf2e93aa3719f926631cabStephen Gallagherapr_pool_t *p, const char *s)</code>: Creates a duplicate of the string <code>s</code>. This is useful for copying constant values so you can edit them</li>
03532fb1cbb7e8c1d5cf2e93aa3719f926631cabStephen Gallagher<li><code>char* <a href="http://apr.apache.org/docs/apr/1.4/group__apr__strings.html#ga3eca76b8d293c5c3f8021e45eda813d8">apr_psprintf</a>(
03532fb1cbb7e8c1d5cf2e93aa3719f926631cabStephen Gallagherapr_pool_t *p, const char *fmt, ...)</code>: Similar to <code>sprintf</code>, except the server supplies you with an appropriately allocated target variable</li>
03532fb1cbb7e8c1d5cf2e93aa3719f926631cabStephen Gallagher</ul>
03532fb1cbb7e8c1d5cf2e93aa3719f926631cabStephen Gallagher
03532fb1cbb7e8c1d5cf2e93aa3719f926631cabStephen Gallagher<p>Let's put these functions into an example handler:</p>
03532fb1cbb7e8c1d5cf2e93aa3719f926631cabStephen Gallagher
d231e95b0a5e1bd377f67e041e8b502a79fdc605Jakub Hrozek
d231e95b0a5e1bd377f67e041e8b502a79fdc605Jakub Hrozek<!-- BEGIN EXAMPLE CODE -->
d231e95b0a5e1bd377f67e041e8b502a79fdc605Jakub Hrozek<highlight language="c">
d231e95b0a5e1bd377f67e041e8b502a79fdc605Jakub Hrozekstatic int example_handler(request_rec *r)
d231e95b0a5e1bd377f67e041e8b502a79fdc605Jakub Hrozek{
d231e95b0a5e1bd377f67e041e8b502a79fdc605Jakub Hrozek const char* original = "You can't edit this!";
d231e95b0a5e1bd377f67e041e8b502a79fdc605Jakub Hrozek char* copy;
d231e95b0a5e1bd377f67e041e8b502a79fdc605Jakub Hrozek int* integers;
d231e95b0a5e1bd377f67e041e8b502a79fdc605Jakub Hrozek
d231e95b0a5e1bd377f67e041e8b502a79fdc605Jakub Hrozek /* Allocate space for 10 integer values and set them all to zero. */
d231e95b0a5e1bd377f67e041e8b502a79fdc605Jakub Hrozek integers = apr_pcalloc(r->pool, sizeof(int)*10);
d231e95b0a5e1bd377f67e041e8b502a79fdc605Jakub Hrozek
d231e95b0a5e1bd377f67e041e8b502a79fdc605Jakub Hrozek /* Create a copy of the 'original' variable that we can edit. */
d231e95b0a5e1bd377f67e041e8b502a79fdc605Jakub Hrozek copy = apr_pstrdup(r->pool, original);
03532fb1cbb7e8c1d5cf2e93aa3719f926631cabStephen Gallagher return OK;
03532fb1cbb7e8c1d5cf2e93aa3719f926631cabStephen Gallagher}
8cc00c355862f5573f884efe828aa4c0f855376aJakub Hrozek</highlight>
8cc00c355862f5573f884efe828aa4c0f855376aJakub Hrozek<!-- END EXAMPLE CODE -->
8cc00c355862f5573f884efe828aa4c0f855376aJakub Hrozek
b3f56d9e4bd065590383eb1f812a3b77e3c56f24Jakub Hrozek<p>
b3f56d9e4bd065590383eb1f812a3b77e3c56f24Jakub HrozekThis is all well and good for our module, which won't need any
b3f56d9e4bd065590383eb1f812a3b77e3c56f24Jakub Hrozekpre-initialized variables or structures. However, if we wanted to
b3f56d9e4bd065590383eb1f812a3b77e3c56f24Jakub Hrozekinitialize something early on, before the requests come rolling in, we
8cc00c355862f5573f884efe828aa4c0f855376aJakub Hrozekcould simply add a call to a function in our <code>register_hooks</code>
03532fb1cbb7e8c1d5cf2e93aa3719f926631cabStephen Gallagherfunction to sort it out:
03532fb1cbb7e8c1d5cf2e93aa3719f926631cabStephen Gallagher</p>
03532fb1cbb7e8c1d5cf2e93aa3719f926631cabStephen Gallagher
03532fb1cbb7e8c1d5cf2e93aa3719f926631cabStephen Gallagher<!-- BEGIN EXAMPLE CODE -->
03532fb1cbb7e8c1d5cf2e93aa3719f926631cabStephen Gallagher<highlight language="c">
03532fb1cbb7e8c1d5cf2e93aa3719f926631cabStephen Gallagherstatic void register_hooks(apr_pool_t *pool)
{
/* Call a function that initializes some stuff */
example_init_function(pool);
/* Create a hook in the request handler, so we get called when a request arrives */
ap_hook_handler(example_handler, NULL, NULL, APR_HOOK_LAST);
}
</highlight>
<!-- END EXAMPLE CODE -->
<p>
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 the server for allocating memory
on a per-process based level.
</p>
</section>
<section id="parsing"><title>Parsing request data</title>
<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&amp;valueB=no&amp;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 HTTP Server 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:
</p>
<!-- BEGIN EXAMPLE CODE -->
<highlight language="c">
<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, &amp;GET);
<a href="http://ci.apache.org/projects/httpd/trunk/doxygen/group__APACHE__CORE__DAEMON.html#ga9d426b6382b49754d4f87c55f65af202">ap_parse_form_data</a>(r, NULL, &amp;POST, -1, 8192);
</highlight>
<!-- END EXAMPLE CODE -->
<p>
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:
</p>
<!-- BEGIN EXAMPLE CODE -->
<highlight language="c">
/* Get the "digest" key from the query string, if any. */
const char *digestType = apr_table_get(GET, "digest");
/* If no key was returned, we will set a default value instead. */
if (!digestType) digestType = "sha1";
</highlight>
<!-- END EXAMPLE CODE -->
<p>
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>
</section>
<section id="advanced_handler"><title>Making an advanced handler</title>
<p>
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:
</p>
<!-- BEGIN EXAMPLE CODE -->
<highlight language="c">
static int example_handler(request_rec *r)
{
int rc, exists;
apr_finfo_t finfo;
apr_file_t *file;
char *filename;
char buffer[256];
apr_size_t readBytes;
int n;
apr_table_t *GET;
apr_array_header_t *POST;
const char *digestType;
/* Check that the &quot;example-handler&quot; handler is being called. */
if (!r-&gt;handler || strcmp(r-&gt;handler, &quot;example-handler&quot;)) return (DECLINED);
/* Figure out which file is being requested by removing the .sum from it */
filename = apr_pstrdup(r-&gt;pool, r-&gt;filename);
filename[strlen(filename)-4] = 0; /* Cut off the last 4 characters. */
/* Figure out if the file we request a sum on exists and isn't a directory */
rc = apr_stat(&amp;finfo, filename, APR_FINFO_MIN, r-&gt;pool);
if (rc == APR_SUCCESS) {
exists =
(
(finfo.filetype != APR_NOFILE)
&amp;&amp; !(finfo.filetype &amp; APR_DIR)
);
if (!exists) return HTTP_NOT_FOUND; /* Return a 404 if not found. */
}
/* If apr_stat failed, we're probably not allowed to check this file. */
else return HTTP_FORBIDDEN;
/* Parse the GET and, optionally, the POST data sent to us */
ap_args_to_table(r, &amp;GET);
ap_parse_form_data(r, NULL, &amp;POST, -1, 8192);
/* Set the appropriate content type */
ap_set_content_type(r, &quot;text/html&quot;);
/* Print a title and some general information */
ap_rprintf(r, &quot;&lt;h2&gt;Information on %s:&lt;/h2&gt;&quot;, filename);
ap_rprintf(r, &quot;&lt;b&gt;Size:&lt;/b&gt; %u bytes&lt;br/&gt;&quot;, finfo.size);
/* Get the digest type the client wants to see */
digestType = apr_table_get(GET, &quot;digest&quot;);
if (!digestType) digestType = &quot;MD5&quot;;
rc = apr_file_open(&amp;file, filename, APR_READ, APR_OS_DEFAULT, r-&gt;pool);
if (rc == APR_SUCCESS) {
/* Are we trying to calculate the MD5 or the SHA1 digest? */
if (!strcasecmp(digestType, &quot;md5&quot;)) {
/* Calculate the MD5 sum of the file */
union {
char chr[16];
uint32_t num[4];
} digest;
apr_md5_ctx_t md5;
apr_md5_init(&amp;md5);
readBytes = 256;
while ( apr_file_read(file, buffer, &amp;readBytes) == APR_SUCCESS ) {
apr_md5_update(&amp;md5, buffer, readBytes);
}
apr_md5_final(digest.chr, &amp;md5);
/* Print out the MD5 digest */
ap_rputs(&quot;&lt;b&gt;MD5: &lt;/b&gt;&lt;code&gt;&quot;, r);
for (n = 0; n &lt; APR_MD5_DIGESTSIZE/4; n++) {
ap_rprintf(r, &quot;%08x&quot;, digest.num[n]);
}
ap_rputs(&quot;&lt;/code&gt;&quot;, r);
/* Print a link to the SHA1 version */
ap_rputs(&quot;&lt;br/&gt;&lt;a href='?digest=sha1'&gt;View the SHA1 hash instead&lt;/a&gt;&quot;, r);
}
else {
/* Calculate the SHA1 sum of the file */
union {
char chr[20];
uint32_t num[5];
} digest;
apr_sha1_ctx_t sha1;
apr_sha1_init(&amp;sha1);
readBytes = 256;
while ( apr_file_read(file, buffer, &amp;readBytes) == APR_SUCCESS ) {
apr_sha1_update(&amp;sha1, buffer, readBytes);
}
apr_sha1_final(digest.chr, &amp;sha1);
/* Print out the SHA1 digest */
ap_rputs(&quot;&lt;b&gt;SHA1: &lt;/b&gt;&lt;code&gt;&quot;, r);
for (n = 0; n &lt; APR_SHA1_DIGESTSIZE/4; n++) {
ap_rprintf(r, &quot;%08x&quot;, digest.num[n]);
}
ap_rputs(&quot;&lt;/code&gt;&quot;, r);
/* Print a link to the MD5 version */
ap_rputs(&quot;&lt;br/&gt;&lt;a href='?digest=md5'&gt;View the MD5 hash instead&lt;/a&gt;&quot;, r);
}
apr_file_close(file);
}
/* Let the server know that we responded to this request. */
return OK;
}
</highlight>
<!-- END EXAMPLE CODE -->
<p>
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>.
</p>
</section>
</section>
<section id="configuration"><title>Adding configuration options</title>
<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
the server works with configuration, and what happens when you start writing
advanced configurations
for your modules.
</p>
<section id="config_intro"><title>An introduction to configuration
directives</title>
<p>
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:
</p>
<example><pre>
RewriteEngine On
RewriteCond %{REQUEST_URI} ^/foo/bar
RewriteRule ^/foo/bar/(.*)$ /foobar?page=$1
</pre></example>
<p>
Each of these configuration directives are handled by a separate function,
that parses the parameters given and sets up a configuration accordingly.
</p>
</section>
<section id="config_simple"><title>Making an example configuration</title>
<p>To begin with, we'll create a basic configuration in C-space:</p>
<!-- BEGIN EXAMPLE CODE -->
<highlight language="c">
typedef struct {
int enabled; /* Enable or disable our module */
const char *path; /* Some path to...something */
int typeOfAction; /* 1 means action A, 2 means action B and so on */
} example_config;
</highlight>
<!-- END EXAMPLE CODE -->
<p>
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:
</p>
<!-- BEGIN EXAMPLE CODE -->
<highlight language="c">
typedef struct {
int enabled; /* Enable or disable our module */
const char *path; /* Some path to...something */
int typeOfAction; /* 1 means action A, 2 means action B and so on */
} example_config;
static example_config config;
static int example_handler(request_rec *r)
{
if (!r-&gt;handler || strcmp(r-&gt;handler, &quot;example-handler&quot;)) return(DECLINED);
ap_set_content_type(r, &quot;text/plain&quot;);
ap_rprintf(r, &quot;Enabled: %u\n&quot;, config.enabled);
ap_rprintf(r, &quot;Path: %s\n&quot;, config.path);
ap_rprintf(r, &quot;TypeOfAction: %x\n&quot;, config.typeOfAction);
return OK;
}
static void register_hooks(apr_pool_t *pool)
{
config.enabled = 1;
config.path = &quot;/foo/bar&quot;;
config.typeOfAction = 0x00;
ap_hook_handler(example_handler, NULL, NULL, APR_HOOK_LAST);
}
/* Define our module as an entity and assign a function for registering hooks */
module AP_MODULE_DECLARE_DATA example_module =
{
STANDARD20_MODULE_STUFF,
NULL, /* Per-directory configuration handler */
NULL, /* Merge handler for per-directory configurations */
NULL, /* Per-server configuration handler */
NULL, /* Merge handler for per-server configurations */
NULL, /* Any directives we may have for httpd */
register_hooks /* Our hook registering function */
};
</highlight>
<!-- END EXAMPLE CODE -->
<p>
So far so good. To access our new handler, we could add the following to
our configuration:
</p>
<example><pre>
&lt;Location /example&gt;
SetHandler example-handler
&lt;/Location&gt;
</pre></example>
<p>
When we visit, we'll see our current configuration being spit out by our
module.
</p>
</section>
<section id="register_directive"><title>Registering directives with the server</title>
<p>
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 the server 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 the server:
</p>
<!-- BEGIN EXAMPLE CODE -->
<highlight language="c">
module AP_MODULE_DECLARE_DATA example_module =
{
STANDARD20_MODULE_STUFF,
NULL, /* Per-directory configuration handler */
NULL, /* Merge handler for per-directory configurations */
NULL, /* Per-server configuration handler */
NULL, /* Merge handler for per-server configurations */
example_directives, /* Any directives we may have for httpd */
register_hooks /* Our hook registering function */
};
</highlight>
<!-- END EXAMPLE CODE -->
<p>
This will tell the server 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:
</p>
<!-- BEGIN EXAMPLE CODE -->
<highlight language="c">
static const command_rec example_directives[] =
{
AP_INIT_TAKE1("exampleEnabled", example_set_enabled, NULL, RSRC_CONF, "Enable or disable mod_example"),
AP_INIT_TAKE1("examplePath", example_set_path, NULL, RSRC_CONF, "The path to whatever"),
AP_INIT_TAKE2("exampleAction", example_set_action, NULL, RSRC_CONF, "Special action value!"),
{ NULL }
};
</highlight>
<!-- END EXAMPLE CODE -->
<p>
<img src="/images/build_a_mod_4.png" border="1" alt="Directives structure"/><br/>
As you can see, each directive needs at least 5 parameters set:
</p>
<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 the server that this directive takes one and only one argument.
If we required two arguments, we could use the macro <code><a href="http://ci.apache.org/projects/httpd/trunk/doxygen/group__APACHE__CORE__CONFIG.html#gafaec43534fcf200f37d9fecbf9247c21">AP_INIT_TAKE2</a></code> and so on (refer to httpd_conf.h
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 the server where the directive is permitted. We'll go into details on this value in the
later chapters, but for now, <code>RSRC_CONF</code> means that the server will only accept these directives in a server context.</li>
<li><code>"Enable or disable...."</code>: This is simply a brief description of what the directive does.</li>
</ol>
<p>
(<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>
</section>
<section id="directive_handler"><title>The directive handler function</title>
<p>
Now that we've told the server to expect some directives for our module, it's
time to make a few functions for handling these. What the server 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:</p>
<!-- BEGIN EXAMPLE CODE -->
<highlight language="c">
/* Handler for the "exambleEnabled" directive */
const char *example_set_enabled(cmd_parms *cmd, void *cfg, const char *arg)
{
if(!strcasecmp(arg, "on")) config.enabled = 1;
else config.enabled = 0;
return NULL;
}
/* Handler for the "examplePath" directive */
const char *example_set_path(cmd_parms *cmd, void *cfg, const char *arg)
{
config.path = arg;
return NULL;
}
/* Handler for the "exampleAction" directive */
/* Let's pretend this one takes one argument (file or db), and a second (deny or allow), */
/* and we store it in a bit-wise manner. */
const char *example_set_action(cmd_parms *cmd, void *cfg, const char *arg1, const char* arg2)
{
if(!strcasecmp(arg1, "file")) config.typeOfAction = 0x01;
else config.typeOfAction = 0x02;
if(!strcasecmp(arg2, "deny")) config.typeOfAction += 0x10;
else config.typeOfAction += 0x20;
return NULL;
}
</highlight>
<!-- END EXAMPLE CODE -->
</section>
<section id="directive_complete"><title>Putting it all together</title>
<p>
Now that we have our directives set up, and handlers configured for them,
we can assemble our module into one big file:
</p>
<!-- BEGIN EXAMPLE CODE -->
<highlight language="c">
/* mod_example_config_simple.c: */
#include &lt;stdio.h&gt;
#include "apr_hash.h"
#include "ap_config.h"
#include "ap_provider.h"
#include "httpd.h"
#include "http_core.h"
#include "http_config.h"
#include "http_log.h"
#include "http_protocol.h"
#include "http_request.h"
/*
==============================================================================
Our configuration prototype and declaration:
==============================================================================
*/
typedef struct {
int enabled; /* Enable or disable our module */
const char *path; /* Some path to...something */
int typeOfAction; /* 1 means action A, 2 means action B and so on */
} example_config;
static example_config config;
/*
==============================================================================
Our directive handlers:
==============================================================================
*/
/* Handler for the &quot;exambleEnabled&quot; directive */
const char *example_set_enabled(cmd_parms *cmd, void *cfg, const char *arg)
{
if(!strcasecmp(arg, &quot;on&quot;)) config.enabled = 1;
else config.enabled = 0;
return NULL;
}
/* Handler for the &quot;examplePath&quot; directive */
const char *example_set_path(cmd_parms *cmd, void *cfg, const char *arg)
{
config.path = arg;
return NULL;
}
/* Handler for the &quot;exampleAction&quot; directive */
/* Let's pretend this one takes one argument (file or db), and a second (deny or allow), */
/* and we store it in a bit-wise manner. */
const char *example_set_action(cmd_parms *cmd, void *cfg, const char *arg1, const char* arg2)
{
if(!strcasecmp(arg1, &quot;file&quot;)) config.typeOfAction = 0x01;
else config.typeOfAction = 0x02;
if(!strcasecmp(arg2, &quot;deny&quot;)) config.typeOfAction += 0x10;
else config.typeOfAction += 0x20;
return NULL;
}
/*
==============================================================================
The directive structure for our name tag:
==============================================================================
*/
static const command_rec example_directives[] =
{
AP_INIT_TAKE1(&quot;exampleEnabled&quot;, example_set_enabled, NULL, RSRC_CONF, &quot;Enable or disable mod_example&quot;),
AP_INIT_TAKE1(&quot;examplePath&quot;, example_set_path, NULL, RSRC_CONF, &quot;The path to whatever&quot;),
AP_INIT_TAKE2(&quot;exampleAction&quot;, example_set_action, NULL, RSRC_CONF, &quot;Special action value!&quot;),
{ NULL }
};
/*
==============================================================================
Our module handler:
==============================================================================
*/
static int example_handler(request_rec *r)
{
if(!r-&gt;handler || strcmp(r-&gt;handler, &quot;example-handler&quot;)) return(DECLINED);
ap_set_content_type(r, &quot;text/plain&quot;);
ap_rprintf(r, &quot;Enabled: %u\n&quot;, config.enabled);
ap_rprintf(r, &quot;Path: %s\n&quot;, config.path);
ap_rprintf(r, &quot;TypeOfAction: %x\n&quot;, config.typeOfAction);
return OK;
}
/*
==============================================================================
The hook registration function (also initializes the default config values):
==============================================================================
*/
static void register_hooks(apr_pool_t *pool)
{
config.enabled = 1;
config.path = &quot;/foo/bar&quot;;
config.typeOfAction = 3;
ap_hook_handler(example_handler, NULL, NULL, APR_HOOK_LAST);
}
/*
==============================================================================
Our module name tag:
==============================================================================
*/
module AP_MODULE_DECLARE_DATA example_module =
{
STANDARD20_MODULE_STUFF,
NULL, /* Per-directory configuration handler */
NULL, /* Merge handler for per-directory configurations */
NULL, /* Per-server configuration handler */
NULL, /* Merge handler for per-server configurations */
example_directives, /* Any directives we may have for httpd */
register_hooks /* Our hook registering function */
};
</highlight>
<!-- END EXAMPLE CODE -->
<p>
In our httpd.conf file, we can now change the hard-coded configuration by
adding a few lines:
</p>
<example><pre>
ExampleEnabled On
ExamplePath "/usr/bin/foo"
ExampleAction file allow
</pre></example>
<p>
And thus we apply the configuration, visit <code>/example</code> on our
web site, and we see the configuration has adapted to what we wrote in our
configuration file.
</p>
</section>
</section>
<section id="context"><title>Context aware configurations</title>
<section id="context_intro"><title>Introduction to context aware configurations</title>
<p>
In Apache HTTP Server 2.4, different URLs, virtual hosts, directories etc can have very
different meanings to the user of the server, and thus different contexts
within which modules must operate. For example, let's assume you have this
configuration set up for mod_rewrite:
</p>
<highlight language="config">
&lt;Directory &quot;/var/www&quot;&gt;
RewriteCond %{HTTP_HOST} ^example.com$
RewriteRule (.*) http://www.example.com/$1
&lt;/Directory&gt;
&lt;Directory &quot;/var/www/sub&quot;&gt;
RewriteRule ^foobar$ index.php?foobar=true
&lt;/Directory&gt;
</highlight>
<p>
In this example, you will have set up two different contexts for
mod_rewrite:</p>
<ol>
<li>Inside <code>/var/www</code>, all requests for <code>http://example.com</code> must go to <code>http://www.example.com</code></li>
<li>Inside <code>/var/www/sub</code>, all requests for <code>foobar</code> must go to <code>index.php?foobar=true</code></li>
</ol>
<p>
If mod_rewrite (or the entire server for that matter) wasn't context aware, then
these rewrite rules would just apply to every and any request made,
regardless of where and how they were made, but since the module can pull
the context specific configuration straight from the server, it does not need
to know itself, which of the directives are valid in this context, since
the server takes care of this.</p>
<p>
So how does a module get the specific configuration for the server,
directory or location in question? It does so by making one simple call:
</p>
<!-- BEGIN EXAMPLE CODE -->
<highlight language="c">
example_config *config = (example_config*) <a href="http://ci.apache.org/projects/httpd/trunk/doxygen/group__APACHE__CORE__CONFIG.html#ga1093a5908a384eacc929b028c79f2a02">ap_get_module_config</a>(r-&gt;per_dir_config, &amp;example_module);
</highlight>
<!-- END EXAMPLE CODE -->
<p>
That's it! Of course, a whole lot goes on behind the scenes, which we will
discuss in this chapter, starting with how the server came to know what our
configuration looks like, and how it came to be set up as it is in the
specific context.
</p>
</section>
<section id="context_base"><title>Our basic configuration setup</title>
<p>In this chapter, we will be working with a slightly modified version of
our previous context structure. We will set a <code>context</code>
variable that we can use to track which context configuration is being
used by the server in various places:
</p>
<!-- BEGIN EXAMPLE CODE -->
<highlight language="c">
typedef struct {
char context[256];
char path[256];
int typeOfAction;
int enabled;
} example_config;
</highlight>
<!-- END EXAMPLE CODE -->
<p>Our handler for requests will also be modified, yet still very simple:</p>
<!-- BEGIN EXAMPLE CODE -->
<highlight language="c">
static int example_handler(request_rec *r)
{
if(!r->handler || strcmp(r->handler, "example-handler")) return(DECLINED);
example_config *config = (example_config*) ap_get_module_config(r->per_dir_config, &amp;example_module);
ap_set_content_type(r, "text/plain");
ap_rprintf("Enabled: %u\n", config->enabled);
ap_rprintf("Path: %s\n", config->path);
ap_rprintf("TypeOfAction: %x\n", config->typeOfAction);
ap_rprintf("Context: %s\n", config->context);
return OK;
}
</highlight>
<!-- END EXAMPLE CODE -->
</section>
<section id="context_which"><title>Choosing a context</title>
<p>
Before we can start making our module context aware, we must first define,
which contexts we will accept. As we saw in the previous chapter, defining
a directive required five elements be set:</p>
<!-- BEGIN EXAMPLE CODE -->
<highlight language="c">
AP_INIT_TAKE1("exampleEnabled", example_set_enabled, NULL, RSRC_CONF, "Enable or disable mod_example"),
</highlight>
<!-- END EXAMPLE CODE -->
<p>The <code>RSRC_CONF</code> definition told the server that we would only allow
this directive in a global server context, but since we are now trying out
a context aware version of our module, we should set this to something
more lenient, namely the value <code>ACCESS_CONF</code>, which lets us use
the directive inside &lt;Directory&gt; and &lt;Location&gt; blocks.
</p>
</section>
<section id="context_pool"><title>Using the server to allocate configuration slots</title>
<p> A much smarter way to manage your configurations is by letting the server
help you create them. To do so, we must first start off by changing our
<em>name tag</em> to let the server know, that it should assist us in creating
and managing our configurations. Since we have chosen the per-directory
(or per-location) context for our module configurations, we'll add a
per-directory creator and merger function reference in our tag:</p>
<!-- BEGIN EXAMPLE CODE -->
<highlight language="c">
module AP_MODULE_DECLARE_DATA example_module =
{
STANDARD20_MODULE_STUFF,
create_dir_conf, /* Per-directory configuration handler */
merge_dir_conf, /* Merge handler for per-directory configurations */
NULL, /* Per-server configuration handler */
NULL, /* Merge handler for per-server configurations */
directives, /* Any directives we may have for httpd */
register_hooks /* Our hook registering function */
};
</highlight>
<!-- END EXAMPLE CODE -->
</section>
<section id="context_new"><title>Creating new context configurations</title>
<p>
Now that we have told the server to help us create and manage configurations,
our first step is to make a function for creating new, blank
configurations. We do so by creating the function we just referenced in
our name tag as the Per-directory configuration handler:</p>
<!-- BEGIN EXAMPLE CODE -->
<highlight language="c">
void* example_create_dir_conf(apr_pool_t* pool, char* context) {
context = context ? context : "(undefined context)";
example_config *cfg = apr_pcalloc(pool, sizeof(example_config));
if(cfg) {
/* Set some default values */
strcpy(cfg->context, x);
cfg->enabled = 0;
cfg->path = "/foo/bar";
cfg->typeOfAction = 0x11;
}
return cfg;
}
</highlight>
<!-- END EXAMPLE CODE -->
</section>
<section id="context_merge"><title>Merging configurations</title>
<p>
Our next step in creating a context aware configuration is merging
configurations. This part of the process particularly apply to scenarios
where you have a parent configuration and a child, such as the following:
</p>
<example><pre>
&lt;Directory &quot;/var/www&quot;&gt;
ExampleEnable On
ExamplePath /foo/bar
ExampleAction file allow
&lt;/Directory&gt;
&lt;Directory &quot;/var/www/subdir&quot;&gt;
ExampleAction file deny
&lt;/Directory&gt;
</pre></example>
<p>
In this example, it is natural to assume that the directory <code>
/var/www/subdir</code> should inherit the value set for the <code>/var/www
</code> directory, as we did not specify a <code>ExampleEnable</code> nor
an <code>ExamplePath</code> for this directory. The server does not presume to
know if this is true, but cleverly does the following:
</p>
<ol>
<li>Creates a new configuration for <code>/var/www</code></li>
<li>Sets the configuration values according to the directives given for <code>/var/www</code></li>
<li>Creates a new configuration for <code>/var/www/subdir</code></li>
<li>Sets the configuration values according to the directives given for <code>/var/www/subdir</code></li>
<li><strong>Proposes a merge</strong> of the two configurations into a new configuration for <code>/var/www/subdir</code></li>
</ol>
<p>
This proposal is handled by the <code>merge_dir_conf</code> function we
referenced in our name tag. The purpose of this function is to assess the
two configurations and decide how they are to be merged:</p>
<!-- BEGIN EXAMPLE CODE -->
<highlight language="c">
void* merge_dir_conf(apr_pool_t* pool, void* BASE, void* ADD) {
example_config* base = (example_config *) BASE ;
example_config* add = (example_config *) ADD ;
example_config* conf = (example_config *) create_dir_conf(pool, "Merged configuration");
conf->enabled = ( add->enabled == 0 ) ? base->enabled : add->enabled ;
conf->typeOfAction = add->typeOfAction ? add->typeOfAction : base->typeOfAction;
strcpy(conf->path, strlen(add->path) ? add->path : base->path);
return conf ;
}
</highlight>
<!-- END EXAMPLE CODE -->
</section>
<section id="context_example"><title>Trying out our new context aware configurations</title>
<p>
Now, let's try putting it all together to create a new module that is
context aware. First off, we'll create a configuration that lets us test
how the module works:
</p>
<example><pre>
&lt;Location &quot;/a&quot;&gt;
SetHandler example-handler
ExampleEnabled on
ExamplePath &quot;/foo/bar&quot;
ExampleAction file allow
&lt;/Location&gt;
&lt;Location &quot;/a/b&quot;&gt;
ExampleAction file deny
ExampleEnabled off
&lt;/Location&gt;
&lt;Location &quot;/a/b/c&quot;&gt;
ExampleAction db deny
ExamplePath &quot;/foo/bar/baz&quot;
ExampleEnabled on
&lt;/Location&gt;
</pre></example>
<p>
Then we'll assemble our module code. Note, that since we are now using our
name tag as reference when fetching configurations in our handler, I have
added some prototypes to keep the compiler happy:
</p>
<!-- BEGIN EXAMPLE CODE -->
<highlight language="c">
/*$6
+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
* mod_example_config.c
+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
*/
#include &lt;stdio.h&gt;
#include "apr_hash.h"
#include "ap_config.h"
#include "ap_provider.h"
#include "httpd.h"
#include "http_core.h"
#include "http_config.h"
#include "http_log.h"
#include "http_protocol.h"
#include "http_request.h"
/*$1
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Configuration structure
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
*/
typedef struct
{
char context[256];
char path[256];
int typeOfAction;
int enabled;
} example_config;
/*$1
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Prototypes
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
*/
static int example_handler(request_rec *r);
const char *example_set_enabled(cmd_parms *cmd, void *cfg, const char *arg);
const char *example_set_path(cmd_parms *cmd, void *cfg, const char *arg);
const char *example_set_action(cmd_parms *cmd, void *cfg, const char *arg1, const char *arg2);
void *create_dir_conf(apr_pool_t *pool, char *context);
void *merge_dir_conf(apr_pool_t *pool, void *BASE, void *ADD);
static void register_hooks(apr_pool_t *pool);
/*$1
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Configuration directives
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
*/
static const command_rec directives[] =
{
AP_INIT_TAKE1(&quot;exampleEnabled&quot;, example_set_enabled, NULL, ACCESS_CONF, &quot;Enable or disable mod_example&quot;),
AP_INIT_TAKE1(&quot;examplePath&quot;, example_set_path, NULL, ACCESS_CONF, &quot;The path to whatever&quot;),
AP_INIT_TAKE2(&quot;exampleAction&quot;, example_set_action, NULL, ACCESS_CONF, &quot;Special action value!&quot;),
{ NULL }
};
/*$1
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Our name tag
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
*/
module AP_MODULE_DECLARE_DATA example_module =
{
STANDARD20_MODULE_STUFF,
create_dir_conf, /* Per-directory configuration handler */
merge_dir_conf, /* Merge handler for per-directory configurations */
NULL, /* Per-server configuration handler */
NULL, /* Merge handler for per-server configurations */
directives, /* Any directives we may have for httpd */
register_hooks /* Our hook registering function */
};
/*
=======================================================================================================================
Hook registration function
=======================================================================================================================
*/
static void register_hooks(apr_pool_t *pool)
{
ap_hook_handler(example_handler, NULL, NULL, APR_HOOK_LAST);
}
/*
=======================================================================================================================
Our example web service handler
=======================================================================================================================
*/
static int example_handler(request_rec *r)
{
if(!r-&gt;handler || strcmp(r-&gt;handler, &quot;example-handler&quot;)) return(DECLINED);
/*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
example_config *config = (example_config *) ap_get_module_config(r-&gt;per_dir_config, &amp;example_module);
/*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
ap_set_content_type(r, &quot;text/plain&quot;);
ap_rprintf(r, &quot;Enabled: %u\n&quot;, config-&gt;enabled);
ap_rprintf(r, &quot;Path: %s\n&quot;, config-&gt;path);
ap_rprintf(r, &quot;TypeOfAction: %x\n&quot;, config-&gt;typeOfAction);
ap_rprintf(r, &quot;Context: %s\n&quot;, config-&gt;context);
return OK;
}
/*
=======================================================================================================================
Handler for the &quot;exambleEnabled&quot; directive
=======================================================================================================================
*/
const char *example_set_enabled(cmd_parms *cmd, void *cfg, const char *arg)
{
/*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
example_config *conf = (example_config *) cfg;
/*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
if(conf)
{
if(!strcasecmp(arg, &quot;on&quot;))
conf-&gt;enabled = 1;
else
conf-&gt;enabled = 0;
}
return NULL;
}
/*
=======================================================================================================================
Handler for the &quot;examplePath&quot; directive
=======================================================================================================================
*/
const char *example_set_path(cmd_parms *cmd, void *cfg, const char *arg)
{
/*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
example_config *conf = (example_config *) cfg;
/*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
if(conf)
{
strcpy(conf-&gt;path, arg);
}
return NULL;
}
/*
=======================================================================================================================
Handler for the &quot;exampleAction&quot; directive ;
Let's pretend this one takes one argument (file or db), and a second (deny or allow), ;
and we store it in a bit-wise manner.
=======================================================================================================================
*/
const char *example_set_action(cmd_parms *cmd, void *cfg, const char *arg1, const char *arg2)
{
/*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
example_config *conf = (example_config *) cfg;
/*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
if(conf)
{
{
if(!strcasecmp(arg1, &quot;file&quot;))
conf-&gt;typeOfAction = 0x01;
else
conf-&gt;typeOfAction = 0x02;
if(!strcasecmp(arg2, &quot;deny&quot;))
conf-&gt;typeOfAction += 0x10;
else
conf-&gt;typeOfAction += 0x20;
}
}
return NULL;
}
/*
=======================================================================================================================
Function for creating new configurations for per-directory contexts
=======================================================================================================================
*/
void *create_dir_conf(apr_pool_t *pool, char *context)
{
context = context ? context : &quot;Newly created configuration&quot;;
/*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
example_config *cfg = apr_pcalloc(pool, sizeof(example_config));
/*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
if(cfg)
{
{
/* Set some default values */
strcpy(cfg-&gt;context, context);
cfg-&gt;enabled = 0;
memset(cfg-&gt;path, 0, 256);
cfg-&gt;typeOfAction = 0x00;
}
}
return cfg;
}
/*
=======================================================================================================================
Merging function for configurations
=======================================================================================================================
*/
void *merge_dir_conf(apr_pool_t *pool, void *BASE, void *ADD)
{
/*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
example_config *base = (example_config *) BASE;
example_config *add = (example_config *) ADD;
example_config *conf = (example_config *) create_dir_conf(pool, &quot;Merged configuration&quot;);
/*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
conf-&gt;enabled = (add-&gt;enabled == 0) ? base-&gt;enabled : add-&gt;enabled;
conf-&gt;typeOfAction = add-&gt;typeOfAction ? add-&gt;typeOfAction : base-&gt;typeOfAction;
strcpy(conf-&gt;path, strlen(add-&gt;path) ? add-&gt;path : base-&gt;path);
return conf;
}
</highlight>
<!-- END EXAMPLE CODE -->
</section>
</section>
<section id="summary"><title>Summing up</title>
<p>
We have now looked at how to create simple modules for Apache HTTP Server 2.4 and
configuring them. What you do next is entirely up to you, but it is my
hope that something valuable has come out of reading this documentation.
If you have questions on how to further develop modules, you are welcome
to join our <a href="http://httpd.apache.org/lists.html">mailing lists</a>
or check out the rest of our documentation for further tips.
</p>
</section>
<section id="snippets"><title>Some useful snippets of code</title>
<section id="get_post"><title>Retrieve a variable from POST form data</title>
<!-- BEGIN EXAMPLE CODE -->
<highlight language="c">
const char *read_post_value(const apr_array_header_t *fields, const char *key)
{
/*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
int i;
apr_table_entry_t *e = 0;
/*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
e = (apr_table_entry_t *) fields-&gt;elts;
for(i = 0; i &lt; fields-&gt;nelts; i++) {
if(!strcmp(e[i].key, key)) return e[i].val;
}
return 0;
}
static int example_handler(request_req *r)
{
/*~~~~~~~~~~~~~~~~~~~~~~*/
apr_array_header_t *POST;
const char *value;
/*~~~~~~~~~~~~~~~~~~~~~~*/
ap_parse_form_data(r, NULL, &amp;POST, -1, 8192);
value = read_post_value(POST, &quot;valueA&quot;);
if (!value) value = &quot;(undefined)&quot;;
ap_rprintf(r, &quot;The value of valueA is: %s&quot;, value);
return OK;
}
</highlight>
<!-- END EXAMPLE CODE -->
</section>
<section id="headers_out"><title>Printing out every HTTP header received</title>
<!-- BEGIN EXAMPLE CODE -->
<highlight language="c">
static int example_handler(request_req *r)
{
/*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
const apr_array_header_t *fields;
int i;
apr_table_entry_t *e = 0;
/*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
fields = apr_table_elts(r-&gt;headers_in);
e = (apr_table_entry_t *) fields-&gt;elts;
for(i = 0; i &lt; fields-&gt;nelts; i++) {
ap_rprintf(r, &quot;&lt;b&gt;%s&lt;/b&gt;: %s&lt;br/&gt;&quot;, e[i].key, e[i].val);
}
return OK;
}
</highlight>
<!-- END EXAMPLE CODE -->
</section>
<section id="request_body"><title>Reading the request body into memory</title>
<!-- BEGIN EXAMPLE CODE -->
<highlight language="c">
static int util_read(request_rec *r, const char **rbuf, apr_off_t *size)
{
/*~~~~~~~~*/
int rc = OK;
/*~~~~~~~~*/
if((rc = ap_setup_client_block(r, REQUEST_CHUNKED_ERROR))) {
return(rc);
}
if(ap_should_client_block(r)) {
/*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
char argsbuffer[HUGE_STRING_LEN];
apr_off_t rsize, len_read, rpos = 0;
apr_off_t length = r-&gt;remaining;
/*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
*rbuf = (const char *) apr_pcalloc(r-&gt;pool, (apr_size_t) (length + 1));
*size = length;
while((len_read = ap_get_client_block(r, argsbuffer, sizeof(argsbuffer))) &gt; 0) {
if((rpos + len_read) &gt; length) {
rsize = length - rpos;
}
else {
rsize = len_read;
}
memcpy((char *) *rbuf + rpos, argsbuffer, (size_t) rsize);
rpos += rsize;
}
}
return(rc);
}
static int example_handler(request_req* r)
{
/*~~~~~~~~~~~~~~~~*/
apr_off_t size;
const char *buffer;
/*~~~~~~~~~~~~~~~~*/
if(util_read(r, &amp;data, &amp;size) == OK) {
ap_rprintf(&quot;We read a request body that was %u bytes long&quot;, size);
}
return OK;
}
</highlight>
<!-- END EXAMPLE CODE -->
</section>
</section>
</manualpage>