modules.html revision b96cd8df63dfd6a55639a7cf6e3272c4122fb321
326N/A<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
326N/A "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
326N/A
326N/A<html xmlns="http://www.w3.org/1999/xhtml">
851N/A <head>
851N/A <meta name="generator" content="HTML Tidy, see www.w3.org" />
326N/A
326N/A <title>Converting Modules from Apache 1.3 to Apache 2.0</title>
326N/A </head>
326N/A <!-- Background white, links blue (unvisited), navy (visited), red (active) -->
326N/A
326N/A <body bgcolor="#FFFFFF" text="#000000" link="#0000FF"
326N/A vlink="#000080" alink="#FF0000">
326N/A <!--#include virtual="header.html" -->
326N/A
326N/A <h1 align="CENTER">From Apache 1.3 to Apache 2.0<br />
326N/A Modules</h1>
326N/A
326N/A <p>This is a first attempt at writing the lessons I learned
326N/A when trying to convert the mod_mmap_static module to Apache
326N/A 2.0. It's by no means definitive and probably won't even be
326N/A correct in some ways, but it's a start.</p>
326N/A <hr />
326N/A
326N/A <h2>The easier changes...</h2>
326N/A
326N/A <h3>Cleanup Routines</h3>
326N/A
326N/A <p>These now need to be of type apr_status_t and return a value
326N/A of that type. Normally the return value will be APR_SUCCESS
326N/A unless there is some need to signal an error in the cleanup. Be
326N/A aware that even though you signal an error not all code yet
851N/A checks and acts upon the error.</p>
326N/A
326N/A <h3>Initialisation Routines</h3>
326N/A
493N/A <p>These should now be renamed to better signify where they sit
326N/A in the overall process. So the name gets a small change from
326N/A mmap_init to mmap_post_config. The arguments passed have
851N/A undergone a radical change and now look like</p>
326N/A
326N/A <ul style="list-style:none">
326N/A <li>apr_pool_t *p,</li>
326N/A
326N/A <li>apr_pool_t *plog,</li>
326N/A
493N/A <li>apr_pool_t *ptemp,</li>
493N/A
326N/A <li>server_rec *s</li>
326N/A </ul>
<h3>Data Types</h3>
<p>A lot of the data types have been moved into the APR. This
means that some have had a name change, such as the one shown
above. The following is a brief list of some of the changes
that you are likely to have to make.</p>
<ul style="list-style:none">
<li>pool becomes apr_pool_t</li>
<li>table becomes apr_table_t</li>
</ul>
<hr />
<h2>The <em>messier</em> changes...</h2>
<h3>Register Hooks</h3>
<p>The new architecture uses a series of hooks to provide for
calling your functions. These you'll need to add to your module
by way of a new function, static void register_hooks(void). The
function is really reasonably straightforward once you
understand what needs to be done. Each function that needs
calling at some stage in the processing of a request needs to
be registered, handlers do not. There are a number of phases
where functions can be added, and for each you can specify with
a high degree of control the relative order that the function
will be called in.</p>
<p>This is the code that was added to mod_mmap_static:</p>
<pre>
static void register_hooks(void)
{
static const char * const aszPre[]={ "http_core.c",NULL };
ap_hook_post_config(mmap_post_config,NULL,NULL,HOOK_MIDDLE);
ap_hook_translate_name(mmap_static_xlat,aszPre,NULL,HOOK_LAST);
};
</pre>
<p>This registers 2 functions that need to be called, one in
the post_config stage (virtually every module will need this
one) and one for the translate_name phase. note that while
there are different function names the format of each is
identical. So what is the format?</p>
<p><strong>ap_hook_[phase_name](function_name, predecessors,
successors, position);</strong></p>
<p>There are 3 hook positions defined...</p>
<ul style="list-style:none">
<li>HOOK_FIRST</li>
<li>HOOK_MIDDLE</li>
<li>HOOK_LAST</li>
</ul>
<p>To define the position you use the position and then modify
it with the predecessors and successors. Each of the modifiers
can be a list of functions that should be called, either before
the function is run (predecessors) or after the function has
run (successors).</p>
<p>In the mod_mmap_static case I didn't care about the
post_config stage, but the mmap_static_xlat MUST be called
after the core module had done it's name translation, hence the
use of the aszPre to define a modifier to the position
HOOK_LAST.</p>
<h3>Module Definition</h3>
<p>There are now a lot fewer stages to worry about when
creating your module definition. The old defintion looked
like</p>
<pre>
module MODULE_VAR_EXPORT [module_name]_module =
{
STANDARD_MODULE_STUFF,
/* initializer */
/* dir config creater */
/* dir merger --- default is to override */
/* server config */
/* merge server config */
/* command handlers */
/* handlers */
/* filename translation */
/* check_user_id */
/* check auth */
/* check access */
/* type_checker */
/* fixups */
/* logger */
/* header parser */
/* child_init */
/* child_exit */
/* post read-request */
};
</pre>
<p>The new structure is a great deal simpler...</p>
<pre>
module MODULE_VAR_EXPORT [module_name]_module =
{
STANDARD20_MODULE_STUFF,
/* create per-directory config structures */
/* merge per-directory config structures */
/* create per-server config structures */
/* merge per-server config structures */
/* command handlers */
/* handlers */
/* register hooks */
};
</pre>
<p>Some of these read directly across, some don't. I'll try to
summarise what should be done below.</p>
<p>The stages that read directly across :</p>
<ul style="list-style:none">
<li>/* dir config creater */ ==&gt; /* create per-directory
config structures */</li>
<li>/* server config */ ==&gt; /* create per-server config
structures */</li>
<li>/* dir merger */ ==&gt; /* merge per-directory config
structures */</li>
<li>/* merge server config */ ==&gt; /* merge per-server
config structures */</li>
<li>/* command table */ ==&gt; /* command apr_table_t */</li>
<li>/* handlers */ ==&gt; /* handlers */</li>
</ul>
<p>The remainder of the old functions should be registered as
hooks. There are the following hook stages defined so
far...</p>
<ul style="list-style:none">
<li>ap_hook_post_config <em>(this is where the old _init
routines get registered)</em></li>
<li>ap_hook_http_method <em>(retrieve the http method from a
request. (legacy))</em></li>
<li>ap_hook_open_logs <em>(open any specified logs)</em></li>
<li>ap_hook_auth_checker <em>(check if the resource requires
authorization)</em></li>
<li>ap_hook_access_checker <em>(check for module-specific
restrictions)</em></li>
<li>ap_hook_check_user_id <em>(check the user-id and
password)</em></li>
<li>ap_hook_default_port <em>(retrieve the default port for
the server)</em></li>
<li>ap_hook_pre_connection <em>(do any setup required just
before processing, but after accepting)</em></li>
<li>ap_hook_process_connection <em>(run the correct
protocol)</em></li>
<li>ap_hook_child_init <em>(call as soon as the child is
started)</em></li>
<li>ap_hook_create_request <em>(??)</em></li>
<li>ap_hook_fixups <em>(last chance to modify things before
generating content)</em></li>
<li>ap_hook_handler <em>(generate the content)</em></li>
<li>ap_hook_header_parser <em>(let's modules look at the
headers, not used by most modules, because they use
post_read_request for this.)</em></li>
<li>ap_hook_insert_filter <em>(to insert filters into the
filter chain)</em></li>
<li>ap_hook_log_transaction <em>(log information about the
request)</em></li>
<li>ap_hook_optional_fn_retrieve <em>(retrieve any functions
registered as optional)</em></li>
<li>ap_hook_post_read_request <em>(called after reading the
request, before any other phase)</em></li>
<li>ap_hook_quick_handler <em>(??)</em></li>
<li>ap_hook_translate_name <em>(translate the URI into a
filename)</em></li>
<li>ap_hook_type_checker <em>(determine and/or set the doc
type)</em> <!--#include virtual="footer.html" -->
</li>
</ul>
</body>
</html>