diff options
author | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-07 15:01:30 +0000 |
---|---|---|
committer | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-07 15:01:30 +0000 |
commit | 6beeb1b708550be0d4a53b272283e17e5e35fe17 (patch) | |
tree | 1ce8673d4aaa948e5554000101f46536a1e4cc29 /docs/manual/developer | |
parent | Initial commit. (diff) | |
download | apache2-upstream/2.4.57.tar.xz apache2-upstream/2.4.57.zip |
Adding upstream version 2.4.57.upstream/2.4.57
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'docs/manual/developer')
27 files changed, 6357 insertions, 0 deletions
diff --git a/docs/manual/developer/API.html b/docs/manual/developer/API.html new file mode 100644 index 0000000..f178e90 --- /dev/null +++ b/docs/manual/developer/API.html @@ -0,0 +1,5 @@ +# GENERATED FROM XML -- DO NOT EDIT + +URI: API.html.en +Content-Language: en +Content-type: text/html; charset=UTF-8 diff --git a/docs/manual/developer/API.html.en b/docs/manual/developer/API.html.en new file mode 100644 index 0000000..60be1bc --- /dev/null +++ b/docs/manual/developer/API.html.en @@ -0,0 +1,1245 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd"> +<html xmlns="http://www.w3.org/1999/xhtml" lang="en" xml:lang="en"><head> +<meta content="text/html; charset=UTF-8" http-equiv="Content-Type" /> +<!-- + XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX + This file is generated from xml source: DO NOT EDIT + XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX + --> +<title>Apache 1.3 API notes - Apache HTTP Server Version 2.4</title> +<link href="../style/css/manual.css" rel="stylesheet" media="all" type="text/css" title="Main stylesheet" /> +<link href="../style/css/manual-loose-100pc.css" rel="alternate stylesheet" media="all" type="text/css" title="No Sidebar - Default font size" /> +<link href="../style/css/manual-print.css" rel="stylesheet" media="print" type="text/css" /><link rel="stylesheet" type="text/css" href="../style/css/prettify.css" /> +<script src="../style/scripts/prettify.min.js" type="text/javascript"> +</script> + +<link href="../images/favicon.ico" rel="shortcut icon" /></head> +<body id="manual-page"><div id="page-header"> +<p class="menu"><a href="../mod/">Modules</a> | <a href="../mod/directives.html">Directives</a> | <a href="http://wiki.apache.org/httpd/FAQ">FAQ</a> | <a href="../glossary.html">Glossary</a> | <a href="../sitemap.html">Sitemap</a></p> +<p class="apache">Apache HTTP Server Version 2.4</p> +<img alt="" src="../images/feather.png" /></div> +<div class="up"><a href="./"><img title="<-" alt="<-" src="../images/left.gif" /></a></div> +<div id="path"> +<a href="http://www.apache.org/">Apache</a> > <a href="http://httpd.apache.org/">HTTP Server</a> > <a href="http://httpd.apache.org/docs/">Documentation</a> > <a href="../">Version 2.4</a> > <a href="./">Developer Documentation</a></div><div id="page-content"><div id="preamble"><h1>Apache 1.3 API notes</h1> +<div class="toplang"> +<p><span>Available Languages: </span><a href="../en/developer/API.html" title="English"> en </a></p> +</div> + + <div class="warning"><h3>Warning</h3> + <p>This document has not been updated to take into account changes made + in the 2.0 version of the Apache HTTP Server. Some of the information may + still be relevant, but please use it with care.</p> + </div> + + <p>These are some notes on the Apache API and the data structures you have + to deal with, <em>etc.</em> They are not yet nearly complete, but hopefully, + they will help you get your bearings. Keep in mind that the API is still + subject to change as we gain experience with it. (See the TODO file for + what <em>might</em> be coming). However, it will be easy to adapt modules + to any changes that are made. (We have more modules to adapt than you + do).</p> + + <p>A few notes on general pedagogical style here. In the interest of + conciseness, all structure declarations here are incomplete -- the real + ones have more slots that I'm not telling you about. For the most part, + these are reserved to one component of the server core or another, and + should be altered by modules with caution. However, in some cases, they + really are things I just haven't gotten around to yet. Welcome to the + bleeding edge.</p> + + <p>Finally, here's an outline, to give you some bare idea of what's coming + up, and in what order:</p> + + <ul> + <li> + <a href="#basics">Basic concepts.</a> + + <ul> + <li><a href="#HMR">Handlers, Modules, and + Requests</a></li> + + <li><a href="#moduletour">A brief tour of a + module</a></li> + </ul> + </li> + + <li> + <a href="#handlers">How handlers work</a> + + <ul> + <li><a href="#req_tour">A brief tour of the + <code>request_rec</code></a></li> + + <li><a href="#req_orig">Where request_rec structures come + from</a></li> + + <li><a href="#req_return">Handling requests, declining, + and returning error codes</a></li> + + <li><a href="#resp_handlers">Special considerations for + response handlers</a></li> + + <li><a href="#auth_handlers">Special considerations for + authentication handlers</a></li> + + <li><a href="#log_handlers">Special considerations for + logging handlers</a></li> + </ul> + </li> + + <li><a href="#pools">Resource allocation and resource + pools</a></li> + + <li> + <a href="#config">Configuration, commands and the like</a> + + <ul> + <li><a href="#per-dir">Per-directory configuration + structures</a></li> + + <li><a href="#commands">Command handling</a></li> + + <li><a href="#servconf">Side notes --- per-server + configuration, virtual servers, <em>etc</em>.</a></li> + </ul> + </li> + </ul> +</div> +<div id="quickview"><a href="https://www.apache.org/foundation/contributing.html" class="badge"><img src="https://www.apache.org/images/SupportApache-small.png" alt="Support Apache!" /></a><ul id="toc"><li><img alt="" src="../images/down.gif" /> <a href="#basics">Basic concepts</a></li> +<li><img alt="" src="../images/down.gif" /> <a href="#handlers">How handlers work</a></li> +<li><img alt="" src="../images/down.gif" /> <a href="#pools">Resource allocation and resource pools</a></li> +<li><img alt="" src="../images/down.gif" /> <a href="#config">Configuration, commands and the like</a></li> +</ul><h3>See also</h3><ul class="seealso"><li><a href="#comments_section">Comments</a></li></ul></div> +<div class="top"><a href="#page-header"><img alt="top" src="../images/up.gif" /></a></div> +<div class="section"> +<h2><a name="basics" id="basics">Basic concepts</a></h2> + <p>We begin with an overview of the basic concepts behind the API, and how + they are manifested in the code.</p> + + <h3><a name="HMR" id="HMR">Handlers, Modules, and Requests</a></h3> + <p>Apache breaks down request handling into a series of steps, more or + less the same way the Netscape server API does (although this API has a + few more stages than NetSite does, as hooks for stuff I thought might be + useful in the future). These are:</p> + + <ul> + <li>URI -> Filename translation</li> + <li>Auth ID checking [is the user who they say they are?]</li> + <li>Auth access checking [is the user authorized <em>here</em>?]</li> + <li>Access checking other than auth</li> + <li>Determining MIME type of the object requested</li> + <li>`Fixups' -- there aren't any of these yet, but the phase is intended + as a hook for possible extensions like <code class="directive"><a href="../mod/mod_env.html#setenv">SetEnv</a></code>, which don't really fit well elsewhere.</li> + <li>Actually sending a response back to the client.</li> + <li>Logging the request</li> + </ul> + + <p>These phases are handled by looking at each of a succession of + <em>modules</em>, looking to see if each of them has a handler for the + phase, and attempting invoking it if so. The handler can typically do one + of three things:</p> + + <ul> + <li><em>Handle</em> the request, and indicate that it has done so by + returning the magic constant <code>OK</code>.</li> + + <li><em>Decline</em> to handle the request, by returning the magic integer + constant <code>DECLINED</code>. In this case, the server behaves in all + respects as if the handler simply hadn't been there.</li> + + <li>Signal an error, by returning one of the HTTP error codes. This + terminates normal handling of the request, although an ErrorDocument may + be invoked to try to mop up, and it will be logged in any case.</li> + </ul> + + <p>Most phases are terminated by the first module that handles them; + however, for logging, `fixups', and non-access authentication checking, + all handlers always run (barring an error). Also, the response phase is + unique in that modules may declare multiple handlers for it, via a + dispatch table keyed on the MIME type of the requested object. Modules may + declare a response-phase handler which can handle <em>any</em> request, + by giving it the key <code>*/*</code> (<em>i.e.</em>, a wildcard MIME type + specification). However, wildcard handlers are only invoked if the server + has already tried and failed to find a more specific response handler for + the MIME type of the requested object (either none existed, or they all + declined).</p> + + <p>The handlers themselves are functions of one argument (a + <code>request_rec</code> structure. vide infra), which returns an integer, + as above.</p> + + + <h3><a name="moduletour" id="moduletour">A brief tour of a module</a></h3> + <p>At this point, we need to explain the structure of a module. Our + candidate will be one of the messier ones, the CGI module -- this handles + both CGI scripts and the <code class="directive"><a href="../mod/mod_alias.html#scriptalias">ScriptAlias</a></code> config file command. It's actually a great deal + more complicated than most modules, but if we're going to have only one + example, it might as well be the one with its fingers in every place.</p> + + <p>Let's begin with handlers. In order to handle the CGI scripts, the + module declares a response handler for them. Because of <code class="directive"><a href="../mod/mod_alias.html#scriptalias">ScriptAlias</a></code>, it also has handlers for the + name translation phase (to recognize <code class="directive"><a href="../mod/mod_alias.html#scriptalias">ScriptAlias</a></code>ed URIs), the type-checking phase (any + <code class="directive"><a href="../mod/mod_alias.html#scriptalias">ScriptAlias</a></code>ed request is typed + as a CGI script).</p> + + <p>The module needs to maintain some per (virtual) server information, + namely, the <code class="directive"><a href="../mod/mod_alias.html#scriptalias">ScriptAlias</a></code>es in + effect; the module structure therefore contains pointers to a functions + which builds these structures, and to another which combines two of them + (in case the main server and a virtual server both have <code class="directive"><a href="../mod/mod_alias.html#scriptalias">ScriptAlias</a></code>es declared).</p> + + <p>Finally, this module contains code to handle the <code class="directive"><a href="../mod/mod_alias.html#scriptalias">ScriptAlias</a></code> command itself. This particular + module only declares one command, but there could be more, so modules have + <em>command tables</em> which declare their commands, and describe where + they are permitted, and how they are to be invoked.</p> + + <p>A final note on the declared types of the arguments of some of these + commands: a <code>pool</code> is a pointer to a <em>resource pool</em> + structure; these are used by the server to keep track of the memory which + has been allocated, files opened, <em>etc.</em>, either to service a + particular request, or to handle the process of configuring itself. That + way, when the request is over (or, for the configuration pool, when the + server is restarting), the memory can be freed, and the files closed, + <em>en masse</em>, without anyone having to write explicit code to track + them all down and dispose of them. Also, a <code>cmd_parms</code> + structure contains various information about the config file being read, + and other status information, which is sometimes of use to the function + which processes a config-file command (such as <code class="directive"><a href="../mod/mod_alias.html#scriptalias">ScriptAlias</a></code>). With no further ado, the + module itself:</p> + + <div class="example"><p><code> + /* Declarations of handlers. */<br /> + <br /> + int translate_scriptalias (request_rec *);<br /> + int type_scriptalias (request_rec *);<br /> + int cgi_handler (request_rec *);<br /> + <br /> + /* Subsidiary dispatch table for response-phase <br /> + * handlers, by MIME type */<br /> + <br /> + handler_rec cgi_handlers[] = {<br /> + <span class="indent"> + { "application/x-httpd-cgi", cgi_handler },<br /> + { NULL }<br /> + </span> + };<br /> + <br /> + /* Declarations of routines to manipulate the <br /> + * module's configuration info. Note that these are<br /> + * returned, and passed in, as void *'s; the server<br /> + * core keeps track of them, but it doesn't, and can't,<br /> + * know their internal structure.<br /> + */<br /> + <br /> + void *make_cgi_server_config (pool *);<br /> + void *merge_cgi_server_config (pool *, void *, void *);<br /> + <br /> + /* Declarations of routines to handle config-file commands */<br /> + <br /> + extern char *script_alias(cmd_parms *, void *per_dir_config, char *fake, + char *real);<br /> + <br /> + command_rec cgi_cmds[] = {<br /> + <span class="indent"> + { "ScriptAlias", script_alias, NULL, RSRC_CONF, TAKE2,<br /> + <span class="indent">"a fakename and a realname"},<br /></span> + { NULL }<br /> + </span> + };<br /> + <br /> + module cgi_module = { +</code></p><pre> STANDARD_MODULE_STUFF, + NULL, /* initializer */ + NULL, /* dir config creator */ + NULL, /* dir merger */ + make_cgi_server_config, /* server config */ + merge_cgi_server_config, /* merge server config */ + cgi_cmds, /* command table */ + cgi_handlers, /* handlers */ + translate_scriptalias, /* filename translation */ + NULL, /* check_user_id */ + NULL, /* check auth */ + NULL, /* check access */ + type_scriptalias, /* type_checker */ + NULL, /* fixups */ + NULL, /* logger */ + NULL /* header parser */ +};</pre></div> + +</div><div class="top"><a href="#page-header"><img alt="top" src="../images/up.gif" /></a></div> +<div class="section"> +<h2><a name="handlers" id="handlers">How handlers work</a></h2> + <p>The sole argument to handlers is a <code>request_rec</code> structure. + This structure describes a particular request which has been made to the + server, on behalf of a client. In most cases, each connection to the + client generates only one <code>request_rec</code> structure.</p> + + <h3><a name="req_tour" id="req_tour">A brief tour of the request_rec</a></h3> + <p>The <code>request_rec</code> contains pointers to a resource pool + which will be cleared when the server is finished handling the request; + to structures containing per-server and per-connection information, and + most importantly, information on the request itself.</p> + + <p>The most important such information is a small set of character strings + describing attributes of the object being requested, including its URI, + filename, content-type and content-encoding (these being filled in by the + translation and type-check handlers which handle the request, + respectively).</p> + + <p>Other commonly used data items are tables giving the MIME headers on + the client's original request, MIME headers to be sent back with the + response (which modules can add to at will), and environment variables for + any subprocesses which are spawned off in the course of servicing the + request. These tables are manipulated using the <code>ap_table_get</code> + and <code>ap_table_set</code> routines.</p> + + <div class="note"> + <p>Note that the <code>Content-type</code> header value <em>cannot</em> + be set by module content-handlers using the <code>ap_table_*()</code> + routines. Rather, it is set by pointing the <code>content_type</code> + field in the <code>request_rec</code> structure to an appropriate + string. <em>e.g.</em>,</p> + <div class="example"><p><code> + r->content_type = "text/html"; + </code></p></div> + </div> + + <p>Finally, there are pointers to two data structures which, in turn, + point to per-module configuration structures. Specifically, these hold + pointers to the data structures which the module has built to describe + the way it has been configured to operate in a given directory (via + <code>.htaccess</code> files or <code class="directive"><a href="../mod/core.html#directory"><Directory></a></code> sections), for private data it has built in the + course of servicing the request (so modules' handlers for one phase can + pass `notes' to their handlers for other phases). There is another such + configuration vector in the <code>server_rec</code> data structure pointed + to by the <code>request_rec</code>, which contains per (virtual) server + configuration data.</p> + + <p>Here is an abridged declaration, giving the fields most commonly + used:</p> + + <div class="example"><p><code> + struct request_rec {<br /> + <br /> + pool *pool;<br /> + conn_rec *connection;<br /> + server_rec *server;<br /> + <br /> + /* What object is being requested */<br /> + <br /> + char *uri;<br /> + char *filename;<br /> + char *path_info; +</code></p><pre>char *args; /* QUERY_ARGS, if any */ +struct stat finfo; /* Set by server core; + * st_mode set to zero if no such file */</pre><p><code> + char *content_type;<br /> + char *content_encoding;<br /> + <br /> + /* MIME header environments, in and out. Also, <br /> + * an array containing environment variables to<br /> + * be passed to subprocesses, so people can write<br /> + * modules to add to that environment.<br /> + *<br /> + * The difference between headers_out and <br /> + * err_headers_out is that the latter are printed <br /> + * even on error, and persist across internal<br /> + * redirects (so the headers printed for <br /> + * <code class="directive"><a href="../mod/core.html#errordocument">ErrorDocument</a></code> handlers will have + them).<br /> + */<br /> + <br /> + table *headers_in;<br /> + table *headers_out;<br /> + table *err_headers_out;<br /> + table *subprocess_env;<br /> + <br /> + /* Info about the request itself... */<br /> + <br /> +</code></p><pre>int header_only; /* HEAD request, as opposed to GET */ +char *protocol; /* Protocol, as given to us, or HTTP/0.9 */ +char *method; /* GET, HEAD, POST, <em>etc.</em> */ +int method_number; /* M_GET, M_POST, <em>etc.</em> */</pre><p><code> + /* Info for logging */<br /> + <br /> + char *the_request;<br /> + int bytes_sent;<br /> + <br /> + /* A flag which modules can set, to indicate that<br /> + * the data being returned is volatile, and clients<br /> + * should be told not to cache it.<br /> + */<br /> + <br /> + int no_cache;<br /> + <br /> + /* Various other config info which may change<br /> + * with .htaccess files<br /> + * These are config vectors, with one void*<br /> + * pointer for each module (the thing pointed<br /> + * to being the module's business).<br /> + */<br /> + <br /> +</code></p><pre>void *per_dir_config; /* Options set in config files, <em>etc.</em> */ +void *request_config; /* Notes on *this* request */</pre><p><code> + }; + </code></p></div> + + + <h3><a name="req_orig" id="req_orig">Where request_rec structures come from</a></h3> + <p>Most <code>request_rec</code> structures are built by reading an HTTP + request from a client, and filling in the fields. However, there are a + few exceptions:</p> + + <ul> + <li>If the request is to an imagemap, a type map (<em>i.e.</em>, a + <code>*.var</code> file), or a CGI script which returned a local + `Location:', then the resource which the user requested is going to be + ultimately located by some URI other than what the client originally + supplied. In this case, the server does an <em>internal redirect</em>, + constructing a new <code>request_rec</code> for the new URI, and + processing it almost exactly as if the client had requested the new URI + directly.</li> + + <li>If some handler signaled an error, and an <code>ErrorDocument</code> + is in scope, the same internal redirect machinery comes into play.</li> + + <li><p>Finally, a handler occasionally needs to investigate `what would + happen if' some other request were run. For instance, the directory + indexing module needs to know what MIME type would be assigned to a + request for each directory entry, in order to figure out what icon to + use.</p> + + <p>Such handlers can construct a <em>sub-request</em>, using the + functions <code>ap_sub_req_lookup_file</code>, + <code>ap_sub_req_lookup_uri</code>, and <code>ap_sub_req_method_uri</code>; + these construct a new <code>request_rec</code> structure and processes it + as you would expect, up to but not including the point of actually sending + a response. (These functions skip over the access checks if the + sub-request is for a file in the same directory as the original + request).</p> + + <p>(Server-side includes work by building sub-requests and then actually + invoking the response handler for them, via the function + <code>ap_run_sub_req</code>).</p> + </li> + </ul> + + + <h3><a name="req_return" id="req_return">Handling requests, declining, and returning + error codes</a></h3> + <p>As discussed above, each handler, when invoked to handle a particular + <code>request_rec</code>, has to return an <code>int</code> to indicate + what happened. That can either be</p> + + <ul> + <li><code>OK</code> -- the request was handled successfully. This may or + may not terminate the phase.</li> + + <li><code>DECLINED</code> -- no erroneous condition exists, but the module + declines to handle the phase; the server tries to find another.</li> + + <li>an HTTP error code, which aborts handling of the request.</li> + </ul> + + <p>Note that if the error code returned is <code>REDIRECT</code>, then + the module should put a <code>Location</code> in the request's + <code>headers_out</code>, to indicate where the client should be + redirected <em>to</em>.</p> + + + <h3><a name="resp_handlers" id="resp_handlers">Special considerations for response + handlers</a></h3> + <p>Handlers for most phases do their work by simply setting a few fields + in the <code>request_rec</code> structure (or, in the case of access + checkers, simply by returning the correct error code). However, response + handlers have to actually send a request back to the client.</p> + + <p>They should begin by sending an HTTP response header, using the + function <code>ap_send_http_header</code>. (You don't have to do anything + special to skip sending the header for HTTP/0.9 requests; the function + figures out on its own that it shouldn't do anything). If the request is + marked <code>header_only</code>, that's all they should do; they should + return after that, without attempting any further output.</p> + + <p>Otherwise, they should produce a request body which responds to the + client as appropriate. The primitives for this are <code>ap_rputc</code> + and <code>ap_rprintf</code>, for internally generated output, and + <code>ap_send_fd</code>, to copy the contents of some <code>FILE *</code> + straight to the client.</p> + + <p>At this point, you should more or less understand the following piece + of code, which is the handler which handles <code>GET</code> requests + which have no more specific handler; it also shows how conditional + <code>GET</code>s can be handled, if it's desirable to do so in a + particular response handler -- <code>ap_set_last_modified</code> checks + against the <code>If-modified-since</code> value supplied by the client, + if any, and returns an appropriate code (which will, if nonzero, be + USE_LOCAL_COPY). No similar considerations apply for + <code>ap_set_content_length</code>, but it returns an error code for + symmetry.</p> + + <div class="example"><p><code> + int default_handler (request_rec *r)<br /> + {<br /> + <span class="indent"> + int errstatus;<br /> + FILE *f;<br /> + <br /> + if (r->method_number != M_GET) return DECLINED;<br /> + if (r->finfo.st_mode == 0) return NOT_FOUND;<br /> + <br /> + if ((errstatus = ap_set_content_length (r, r->finfo.st_size))<br /> + || + (errstatus = ap_set_last_modified (r, r->finfo.st_mtime)))<br /> + return errstatus;<br /> + <br /> + f = fopen (r->filename, "r");<br /> + <br /> + if (f == NULL) {<br /> + <span class="indent"> + log_reason("file permissions deny server access", r->filename, r);<br /> + return FORBIDDEN;<br /> + </span> + }<br /> + <br /> + register_timeout ("send", r);<br /> + ap_send_http_header (r);<br /> + <br /> + if (!r->header_only) send_fd (f, r);<br /> + ap_pfclose (r->pool, f);<br /> + return OK;<br /> + </span> + } + </code></p></div> + + <p>Finally, if all of this is too much of a challenge, there are a few + ways out of it. First off, as shown above, a response handler which has + not yet produced any output can simply return an error code, in which + case the server will automatically produce an error response. Secondly, + it can punt to some other handler by invoking + <code>ap_internal_redirect</code>, which is how the internal redirection + machinery discussed above is invoked. A response handler which has + internally redirected should always return <code>OK</code>.</p> + + <p>(Invoking <code>ap_internal_redirect</code> from handlers which are + <em>not</em> response handlers will lead to serious confusion).</p> + + + <h3><a name="auth_handlers" id="auth_handlers">Special considerations for authentication + handlers</a></h3> + <p>Stuff that should be discussed here in detail:</p> + + <ul> + <li>Authentication-phase handlers not invoked unless auth is + configured for the directory.</li> + + <li>Common auth configuration stored in the core per-dir + configuration; it has accessors <code>ap_auth_type</code>, + <code>ap_auth_name</code>, and <code>ap_requires</code>.</li> + + <li>Common routines, to handle the protocol end of things, at + least for HTTP basic authentication + (<code>ap_get_basic_auth_pw</code>, which sets the + <code>connection->user</code> structure field + automatically, and <code>ap_note_basic_auth_failure</code>, + which arranges for the proper <code>WWW-Authenticate:</code> + header to be sent back).</li> + </ul> + + + <h3><a name="log_handlers" id="log_handlers">Special considerations for logging + handlers</a></h3> + <p>When a request has internally redirected, there is the question of + what to log. Apache handles this by bundling the entire chain of redirects + into a list of <code>request_rec</code> structures which are threaded + through the <code>r->prev</code> and <code>r->next</code> pointers. + The <code>request_rec</code> which is passed to the logging handlers in + such cases is the one which was originally built for the initial request + from the client; note that the <code>bytes_sent</code> field will only be + correct in the last request in the chain (the one for which a response was + actually sent).</p> + +</div><div class="top"><a href="#page-header"><img alt="top" src="../images/up.gif" /></a></div> +<div class="section"> +<h2><a name="pools" id="pools">Resource allocation and resource pools</a></h2> + <p>One of the problems of writing and designing a server-pool server is + that of preventing leakage, that is, allocating resources (memory, open + files, <em>etc.</em>), without subsequently releasing them. The resource + pool machinery is designed to make it easy to prevent this from happening, + by allowing resource to be allocated in such a way that they are + <em>automatically</em> released when the server is done with them.</p> + + <p>The way this works is as follows: the memory which is allocated, file + opened, <em>etc.</em>, to deal with a particular request are tied to a + <em>resource pool</em> which is allocated for the request. The pool is a + data structure which itself tracks the resources in question.</p> + + <p>When the request has been processed, the pool is <em>cleared</em>. At + that point, all the memory associated with it is released for reuse, all + files associated with it are closed, and any other clean-up functions which + are associated with the pool are run. When this is over, we can be confident + that all the resource tied to the pool have been released, and that none of + them have leaked.</p> + + <p>Server restarts, and allocation of memory and resources for per-server + configuration, are handled in a similar way. There is a <em>configuration + pool</em>, which keeps track of resources which were allocated while reading + the server configuration files, and handling the commands therein (for + instance, the memory that was allocated for per-server module configuration, + log files and other files that were opened, and so forth). When the server + restarts, and has to reread the configuration files, the configuration pool + is cleared, and so the memory and file descriptors which were taken up by + reading them the last time are made available for reuse.</p> + + <p>It should be noted that use of the pool machinery isn't generally + obligatory, except for situations like logging handlers, where you really + need to register cleanups to make sure that the log file gets closed when + the server restarts (this is most easily done by using the function <code><a href="#pool-files">ap_pfopen</a></code>, which also arranges for the + underlying file descriptor to be closed before any child processes, such as + for CGI scripts, are <code>exec</code>ed), or in case you are using the + timeout machinery (which isn't yet even documented here). However, there are + two benefits to using it: resources allocated to a pool never leak (even if + you allocate a scratch string, and just forget about it); also, for memory + allocation, <code>ap_palloc</code> is generally faster than + <code>malloc</code>.</p> + + <p>We begin here by describing how memory is allocated to pools, and then + discuss how other resources are tracked by the resource pool machinery.</p> + + <h3>Allocation of memory in pools</h3> + <p>Memory is allocated to pools by calling the function + <code>ap_palloc</code>, which takes two arguments, one being a pointer to + a resource pool structure, and the other being the amount of memory to + allocate (in <code>char</code>s). Within handlers for handling requests, + the most common way of getting a resource pool structure is by looking at + the <code>pool</code> slot of the relevant <code>request_rec</code>; hence + the repeated appearance of the following idiom in module code:</p> + + <div class="example"><p><code> + int my_handler(request_rec *r)<br /> + {<br /> + <span class="indent"> + struct my_structure *foo;<br /> + ...<br /> + <br /> + foo = (foo *)ap_palloc (r->pool, sizeof(my_structure));<br /> + </span> + } + </code></p></div> + + <p>Note that <em>there is no <code>ap_pfree</code></em> -- + <code>ap_palloc</code>ed memory is freed only when the associated resource + pool is cleared. This means that <code>ap_palloc</code> does not have to + do as much accounting as <code>malloc()</code>; all it does in the typical + case is to round up the size, bump a pointer, and do a range check.</p> + + <p>(It also raises the possibility that heavy use of + <code>ap_palloc</code> could cause a server process to grow excessively + large. There are two ways to deal with this, which are dealt with below; + briefly, you can use <code>malloc</code>, and try to be sure that all of + the memory gets explicitly <code>free</code>d, or you can allocate a + sub-pool of the main pool, allocate your memory in the sub-pool, and clear + it out periodically. The latter technique is discussed in the section + on sub-pools below, and is used in the directory-indexing code, in order + to avoid excessive storage allocation when listing directories with + thousands of files).</p> + + + <h3>Allocating initialized memory</h3> + <p>There are functions which allocate initialized memory, and are + frequently useful. The function <code>ap_pcalloc</code> has the same + interface as <code>ap_palloc</code>, but clears out the memory it + allocates before it returns it. The function <code>ap_pstrdup</code> + takes a resource pool and a <code>char *</code> as arguments, and + allocates memory for a copy of the string the pointer points to, returning + a pointer to the copy. Finally <code>ap_pstrcat</code> is a varargs-style + function, which takes a pointer to a resource pool, and at least two + <code>char *</code> arguments, the last of which must be + <code>NULL</code>. It allocates enough memory to fit copies of each of + the strings, as a unit; for instance:</p> + + <div class="example"><p><code> + ap_pstrcat (r->pool, "foo", "/", "bar", NULL); + </code></p></div> + + <p>returns a pointer to 8 bytes worth of memory, initialized to + <code>"foo/bar"</code>.</p> + + + <h3><a name="pools-used" id="pools-used">Commonly-used pools in the Apache Web + server</a></h3> + <p>A pool is really defined by its lifetime more than anything else. + There are some static pools in http_main which are passed to various + non-http_main functions as arguments at opportune times. Here they + are:</p> + + <dl> + <dt><code>permanent_pool</code></dt> + <dd>never passed to anything else, this is the ancestor of all pools</dd> + + <dt><code>pconf</code></dt> + <dd> + <ul> + <li>subpool of permanent_pool</li> + + <li>created at the beginning of a config "cycle"; exists + until the server is terminated or restarts; passed to all + config-time routines, either via cmd->pool, or as the + "pool *p" argument on those which don't take pools</li> + + <li>passed to the module init() functions</li> + </ul> + </dd> + + <dt><code>ptemp</code></dt> + <dd> + <ul> + <li>sorry I lie, this pool isn't called this currently in + 1.3, I renamed it this in my pthreads development. I'm + referring to the use of ptrans in the parent... contrast + this with the later definition of ptrans in the + child.</li> + + <li>subpool of permanent_pool</li> + + <li>created at the beginning of a config "cycle"; exists + until the end of config parsing; passed to config-time + routines <em>via</em> cmd->temp_pool. Somewhat of a + "bastard child" because it isn't available everywhere. + Used for temporary scratch space which may be needed by + some config routines but which is deleted at the end of + config.</li> + </ul> + </dd> + + <dt><code>pchild</code></dt> + <dd> + <ul> + <li>subpool of permanent_pool</li> + + <li>created when a child is spawned (or a thread is + created); lives until that child (thread) is + destroyed</li> + + <li>passed to the module child_init functions</li> + + <li>destruction happens right after the child_exit + functions are called... (which may explain why I think + child_exit is redundant and unneeded)</li> + </ul> + </dd> + + <dt><code>ptrans</code></dt> + <dd> + <ul> + <li>should be a subpool of pchild, but currently is a + subpool of permanent_pool, see above</li> + + <li>cleared by the child before going into the accept() + loop to receive a connection</li> + + <li>used as connection->pool</li> + </ul> + </dd> + + <dt><code>r->pool</code></dt> + <dd> + <ul> + <li>for the main request this is a subpool of + connection->pool; for subrequests it is a subpool of + the parent request's pool.</li> + + <li>exists until the end of the request (<em>i.e.</em>, + ap_destroy_sub_req, or in child_main after + process_request has finished)</li> + + <li>note that r itself is allocated from r->pool; + <em>i.e.</em>, r->pool is first created and then r is + the first thing palloc()d from it</li> + </ul> + </dd> + </dl> + + <p>For almost everything folks do, <code>r->pool</code> is the pool to + use. But you can see how other lifetimes, such as pchild, are useful to + some modules... such as modules that need to open a database connection + once per child, and wish to clean it up when the child dies.</p> + + <p>You can also see how some bugs have manifested themself, such as + setting <code>connection->user</code> to a value from + <code>r->pool</code> -- in this case connection exists for the + lifetime of <code>ptrans</code>, which is longer than + <code>r->pool</code> (especially if <code>r->pool</code> is a + subrequest!). So the correct thing to do is to allocate from + <code>connection->pool</code>.</p> + + <p>And there was another interesting bug in <code class="module"><a href="../mod/mod_include.html">mod_include</a></code> + / <code class="module"><a href="../mod/mod_cgi.html">mod_cgi</a></code>. You'll see in those that they do this test + to decide if they should use <code>r->pool</code> or + <code>r->main->pool</code>. In this case the resource that they are + registering for cleanup is a child process. If it were registered in + <code>r->pool</code>, then the code would <code>wait()</code> for the + child when the subrequest finishes. With <code class="module"><a href="../mod/mod_include.html">mod_include</a></code> this + could be any old <code>#include</code>, and the delay can be up to 3 + seconds... and happened quite frequently. Instead the subprocess is + registered in <code>r->main->pool</code> which causes it to be + cleaned up when the entire request is done -- <em>i.e.</em>, after the + output has been sent to the client and logging has happened.</p> + + + <h3><a name="pool-files" id="pool-files">Tracking open files, etc.</a></h3> + <p>As indicated above, resource pools are also used to track other sorts + of resources besides memory. The most common are open files. The routine + which is typically used for this is <code>ap_pfopen</code>, which takes a + resource pool and two strings as arguments; the strings are the same as + the typical arguments to <code>fopen</code>, <em>e.g.</em>,</p> + + <div class="example"><p><code> + ...<br /> + FILE *f = ap_pfopen (r->pool, r->filename, "r");<br /> + <br /> + if (f == NULL) { ... } else { ... }<br /> + </code></p></div> + + <p>There is also a <code>ap_popenf</code> routine, which parallels the + lower-level <code>open</code> system call. Both of these routines arrange + for the file to be closed when the resource pool in question is + cleared.</p> + + <p>Unlike the case for memory, there <em>are</em> functions to close files + allocated with <code>ap_pfopen</code>, and <code>ap_popenf</code>, namely + <code>ap_pfclose</code> and <code>ap_pclosef</code>. (This is because, on + many systems, the number of files which a single process can have open is + quite limited). It is important to use these functions to close files + allocated with <code>ap_pfopen</code> and <code>ap_popenf</code>, since to + do otherwise could cause fatal errors on systems such as Linux, which + react badly if the same <code>FILE*</code> is closed more than once.</p> + + <p>(Using the <code>close</code> functions is not mandatory, since the + file will eventually be closed regardless, but you should consider it in + cases where your module is opening, or could open, a lot of files).</p> + + + <h3>Other sorts of resources -- cleanup functions</h3> + <p>More text goes here. Describe the cleanup primitives in terms of + which the file stuff is implemented; also, <code>spawn_process</code>.</p> + + <p>Pool cleanups live until <code>clear_pool()</code> is called: + <code>clear_pool(a)</code> recursively calls <code>destroy_pool()</code> + on all subpools of <code>a</code>; then calls all the cleanups for + <code>a</code>; then releases all the memory for <code>a</code>. + <code>destroy_pool(a)</code> calls <code>clear_pool(a)</code> and then + releases the pool structure itself. <em>i.e.</em>, + <code>clear_pool(a)</code> doesn't delete <code>a</code>, it just frees + up all the resources and you can start using it again immediately.</p> + + + <h3>Fine control -- creating and dealing with sub-pools, with + a note on sub-requests</h3> + <p>On rare occasions, too-free use of <code>ap_palloc()</code> and the + associated primitives may result in undesirably profligate resource + allocation. You can deal with such a case by creating a <em>sub-pool</em>, + allocating within the sub-pool rather than the main pool, and clearing or + destroying the sub-pool, which releases the resources which were + associated with it. (This really <em>is</em> a rare situation; the only + case in which it comes up in the standard module set is in case of listing + directories, and then only with <em>very</em> large directories. + Unnecessary use of the primitives discussed here can hair up your code + quite a bit, with very little gain).</p> + + <p>The primitive for creating a sub-pool is <code>ap_make_sub_pool</code>, + which takes another pool (the parent pool) as an argument. When the main + pool is cleared, the sub-pool will be destroyed. The sub-pool may also be + cleared or destroyed at any time, by calling the functions + <code>ap_clear_pool</code> and <code>ap_destroy_pool</code>, respectively. + (The difference is that <code>ap_clear_pool</code> frees resources + associated with the pool, while <code>ap_destroy_pool</code> also + deallocates the pool itself. In the former case, you can allocate new + resources within the pool, and clear it again, and so forth; in the + latter case, it is simply gone).</p> + + <p>One final note -- sub-requests have their own resource pools, which are + sub-pools of the resource pool for the main request. The polite way to + reclaim the resources associated with a sub request which you have + allocated (using the <code>ap_sub_req_...</code> functions) is + <code>ap_destroy_sub_req</code>, which frees the resource pool. Before + calling this function, be sure to copy anything that you care about which + might be allocated in the sub-request's resource pool into someplace a + little less volatile (for instance, the filename in its + <code>request_rec</code> structure).</p> + + <p>(Again, under most circumstances, you shouldn't feel obliged to call + this function; only 2K of memory or so are allocated for a typical sub + request, and it will be freed anyway when the main request pool is + cleared. It is only when you are allocating many, many sub-requests for a + single main request that you should seriously consider the + <code>ap_destroy_...</code> functions).</p> + +</div><div class="top"><a href="#page-header"><img alt="top" src="../images/up.gif" /></a></div> +<div class="section"> +<h2><a name="config" id="config">Configuration, commands and the like</a></h2> + <p>One of the design goals for this server was to maintain external + compatibility with the NCSA 1.3 server --- that is, to read the same + configuration files, to process all the directives therein correctly, and + in general to be a drop-in replacement for NCSA. On the other hand, another + design goal was to move as much of the server's functionality into modules + which have as little as possible to do with the monolithic server core. The + only way to reconcile these goals is to move the handling of most commands + from the central server into the modules.</p> + + <p>However, just giving the modules command tables is not enough to divorce + them completely from the server core. The server has to remember the + commands in order to act on them later. That involves maintaining data which + is private to the modules, and which can be either per-server, or + per-directory. Most things are per-directory, including in particular access + control and authorization information, but also information on how to + determine file types from suffixes, which can be modified by + <code class="directive"><a href="../mod/mod_mime.html#addtype">AddType</a></code> and <code class="directive"><a href="../mod/core.html#forcetype">ForceType</a></code> directives, and so forth. In general, + the governing philosophy is that anything which <em>can</em> be made + configurable by directory should be; per-server information is generally + used in the standard set of modules for information like + <code class="directive"><a href="../mod/mod_alias.html#alias">Alias</a></code>es and <code class="directive"><a href="../mod/mod_alias.html#redirect">Redirect</a></code>s which come into play before the + request is tied to a particular place in the underlying file system.</p> + + <p>Another requirement for emulating the NCSA server is being able to handle + the per-directory configuration files, generally called + <code>.htaccess</code> files, though even in the NCSA server they can + contain directives which have nothing at all to do with access control. + Accordingly, after URI -> filename translation, but before performing any + other phase, the server walks down the directory hierarchy of the underlying + filesystem, following the translated pathname, to read any + <code>.htaccess</code> files which might be present. The information which + is read in then has to be <em>merged</em> with the applicable information + from the server's own config files (either from the <code class="directive"><a href="../mod/core.html#directory"><Directory></a></code> sections in + <code>access.conf</code>, or from defaults in <code>srm.conf</code>, which + actually behaves for most purposes almost exactly like <code><Directory + /></code>).</p> + + <p>Finally, after having served a request which involved reading + <code>.htaccess</code> files, we need to discard the storage allocated for + handling them. That is solved the same way it is solved wherever else + similar problems come up, by tying those structures to the per-transaction + resource pool.</p> + + <h3><a name="per-dir" id="per-dir">Per-directory configuration structures</a></h3> + <p>Let's look out how all of this plays out in <code>mod_mime.c</code>, + which defines the file typing handler which emulates the NCSA server's + behavior of determining file types from suffixes. What we'll be looking + at, here, is the code which implements the <code class="directive"><a href="../mod/mod_mime.html#addtype">AddType</a></code> and <code class="directive"><a href="../mod/mod_mime.html#addencoding">AddEncoding</a></code> commands. These commands can appear in + <code>.htaccess</code> files, so they must be handled in the module's + private per-directory data, which in fact, consists of two separate + tables for MIME types and encoding information, and is declared as + follows:</p> + + <div class="example"><pre>typedef struct { + table *forced_types; /* Additional AddTyped stuff */ + table *encoding_types; /* Added with AddEncoding... */ +} mime_dir_config;</pre></div> + + <p>When the server is reading a configuration file, or <code class="directive"><a href="../mod/core.html#directory"><Directory></a></code> section, which includes + one of the MIME module's commands, it needs to create a + <code>mime_dir_config</code> structure, so those commands have something + to act on. It does this by invoking the function it finds in the module's + `create per-dir config slot', with two arguments: the name of the + directory to which this configuration information applies (or + <code>NULL</code> for <code>srm.conf</code>), and a pointer to a + resource pool in which the allocation should happen.</p> + + <p>(If we are reading a <code>.htaccess</code> file, that resource pool + is the per-request resource pool for the request; otherwise it is a + resource pool which is used for configuration data, and cleared on + restarts. Either way, it is important for the structure being created to + vanish when the pool is cleared, by registering a cleanup on the pool if + necessary).</p> + + <p>For the MIME module, the per-dir config creation function just + <code>ap_palloc</code>s the structure above, and a creates a couple of + tables to fill it. That looks like this:</p> + + <div class="example"><p><code> + void *create_mime_dir_config (pool *p, char *dummy)<br /> + {<br /> + <span class="indent"> + mime_dir_config *new =<br /> + <span class="indent"> + (mime_dir_config *) ap_palloc (p, sizeof(mime_dir_config));<br /> + </span> + <br /> + new->forced_types = ap_make_table (p, 4);<br /> + new->encoding_types = ap_make_table (p, 4);<br /> + <br /> + return new;<br /> + </span> + } + </code></p></div> + + <p>Now, suppose we've just read in a <code>.htaccess</code> file. We + already have the per-directory configuration structure for the next + directory up in the hierarchy. If the <code>.htaccess</code> file we just + read in didn't have any <code class="directive"><a href="../mod/mod_mime.html#addtype">AddType</a></code> + or <code class="directive"><a href="../mod/mod_mime.html#addencoding">AddEncoding</a></code> commands, its + per-directory config structure for the MIME module is still valid, and we + can just use it. Otherwise, we need to merge the two structures + somehow.</p> + + <p>To do that, the server invokes the module's per-directory config merge + function, if one is present. That function takes three arguments: the two + structures being merged, and a resource pool in which to allocate the + result. For the MIME module, all that needs to be done is overlay the + tables from the new per-directory config structure with those from the + parent:</p> + + <div class="example"><p><code> + void *merge_mime_dir_configs (pool *p, void *parent_dirv, void *subdirv)<br /> + {<br /> + <span class="indent"> + mime_dir_config *parent_dir = (mime_dir_config *)parent_dirv;<br /> + mime_dir_config *subdir = (mime_dir_config *)subdirv;<br /> + mime_dir_config *new =<br /> + <span class="indent"> + (mime_dir_config *)ap_palloc (p, sizeof(mime_dir_config));<br /> + </span> + <br /> + new->forced_types = ap_overlay_tables (p, subdir->forced_types,<br /> + <span class="indent"> + parent_dir->forced_types);<br /> + </span> + new->encoding_types = ap_overlay_tables (p, subdir->encoding_types,<br /> + <span class="indent"> + parent_dir->encoding_types);<br /> + </span> + <br /> + return new;<br /> + </span> + } + </code></p></div> + + <p>As a note -- if there is no per-directory merge function present, the + server will just use the subdirectory's configuration info, and ignore + the parent's. For some modules, that works just fine (<em>e.g.</em>, for + the includes module, whose per-directory configuration information + consists solely of the state of the <code>XBITHACK</code>), and for those + modules, you can just not declare one, and leave the corresponding + structure slot in the module itself <code>NULL</code>.</p> + + + <h3><a name="commands" id="commands">Command handling</a></h3> + <p>Now that we have these structures, we need to be able to figure out how + to fill them. That involves processing the actual <code class="directive"><a href="../mod/mod_mime.html#addtype">AddType</a></code> and <code class="directive"><a href="../mod/mod_mime.html#addencoding">AddEncoding</a></code> commands. To find commands, the server looks in + the module's command table. That table contains information on how many + arguments the commands take, and in what formats, where it is permitted, + and so forth. That information is sufficient to allow the server to invoke + most command-handling functions with pre-parsed arguments. Without further + ado, let's look at the <code class="directive"><a href="../mod/mod_mime.html#addtype">AddType</a></code> + command handler, which looks like this (the <code class="directive"><a href="../mod/mod_mime.html#addencoding">AddEncoding</a></code> command looks basically the same, and won't be + shown here):</p> + + <div class="example"><p><code> + char *add_type(cmd_parms *cmd, mime_dir_config *m, char *ct, char *ext)<br /> + {<br /> + <span class="indent"> + if (*ext == '.') ++ext;<br /> + ap_table_set (m->forced_types, ext, ct);<br /> + return NULL;<br /> + </span> + } + </code></p></div> + + <p>This command handler is unusually simple. As you can see, it takes + four arguments, two of which are pre-parsed arguments, the third being the + per-directory configuration structure for the module in question, and the + fourth being a pointer to a <code>cmd_parms</code> structure. That + structure contains a bunch of arguments which are frequently of use to + some, but not all, commands, including a resource pool (from which memory + can be allocated, and to which cleanups should be tied), and the (virtual) + server being configured, from which the module's per-server configuration + data can be obtained if required.</p> + + <p>Another way in which this particular command handler is unusually + simple is that there are no error conditions which it can encounter. If + there were, it could return an error message instead of <code>NULL</code>; + this causes an error to be printed out on the server's + <code>stderr</code>, followed by a quick exit, if it is in the main config + files; for a <code>.htaccess</code> file, the syntax error is logged in + the server error log (along with an indication of where it came from), and + the request is bounced with a server error response (HTTP error status, + code 500).</p> + + <p>The MIME module's command table has entries for these commands, which + look like this:</p> + + <div class="example"><p><code> + command_rec mime_cmds[] = {<br /> + <span class="indent"> + { "AddType", add_type, NULL, OR_FILEINFO, TAKE2,<br /> + <span class="indent">"a mime type followed by a file extension" },<br /></span> + { "AddEncoding", add_encoding, NULL, OR_FILEINFO, TAKE2,<br /> + <span class="indent"> + "an encoding (<em>e.g.</em>, gzip), followed by a file extension" },<br /> + </span> + { NULL }<br /> + </span> + }; + </code></p></div> + + <p>The entries in these tables are:</p> + <ul> + <li>The name of the command</li> + <li>The function which handles it</li> + <li>a <code>(void *)</code> pointer, which is passed in the + <code>cmd_parms</code> structure to the command handler --- + this is useful in case many similar commands are handled by + the same function.</li> + + <li>A bit mask indicating where the command may appear. There + are mask bits corresponding to each + <code>AllowOverride</code> option, and an additional mask + bit, <code>RSRC_CONF</code>, indicating that the command may + appear in the server's own config files, but <em>not</em> in + any <code>.htaccess</code> file.</li> + + <li>A flag indicating how many arguments the command handler + wants pre-parsed, and how they should be passed in. + <code>TAKE2</code> indicates two pre-parsed arguments. Other + options are <code>TAKE1</code>, which indicates one + pre-parsed argument, <code>FLAG</code>, which indicates that + the argument should be <code>On</code> or <code>Off</code>, + and is passed in as a boolean flag, <code>RAW_ARGS</code>, + which causes the server to give the command the raw, unparsed + arguments (everything but the command name itself). There is + also <code>ITERATE</code>, which means that the handler looks + the same as <code>TAKE1</code>, but that if multiple + arguments are present, it should be called multiple times, + and finally <code>ITERATE2</code>, which indicates that the + command handler looks like a <code>TAKE2</code>, but if more + arguments are present, then it should be called multiple + times, holding the first argument constant.</li> + + <li>Finally, we have a string which describes the arguments + that should be present. If the arguments in the actual config + file are not as required, this string will be used to help + give a more specific error message. (You can safely leave + this <code>NULL</code>).</li> + </ul> + + <p>Finally, having set this all up, we have to use it. This is ultimately + done in the module's handlers, specifically for its file-typing handler, + which looks more or less like this; note that the per-directory + configuration structure is extracted from the <code>request_rec</code>'s + per-directory configuration vector by using the + <code>ap_get_module_config</code> function.</p> + + <div class="example"><p><code> + int find_ct(request_rec *r)<br /> + {<br /> + <span class="indent"> + int i;<br /> + char *fn = ap_pstrdup (r->pool, r->filename);<br /> + mime_dir_config *conf = (mime_dir_config *)<br /> + <span class="indent"> + ap_get_module_config(r->per_dir_config, &mime_module);<br /> + </span> + char *type;<br /> + <br /> + if (S_ISDIR(r->finfo.st_mode)) {<br /> + <span class="indent"> + r->content_type = DIR_MAGIC_TYPE;<br /> + return OK;<br /> + </span> + }<br /> + <br /> + if((i=ap_rind(fn,'.')) < 0) return DECLINED;<br /> + ++i;<br /> + <br /> + if ((type = ap_table_get (conf->encoding_types, &fn[i])))<br /> + {<br /> + <span class="indent"> + r->content_encoding = type;<br /> + <br /> + /* go back to previous extension to try to use it as a type */<br /> + fn[i-1] = '\0';<br /> + if((i=ap_rind(fn,'.')) < 0) return OK;<br /> + ++i;<br /> + </span> + }<br /> + <br /> + if ((type = ap_table_get (conf->forced_types, &fn[i])))<br /> + {<br /> + <span class="indent"> + r->content_type = type;<br /> + </span> + }<br /> + <br /> + return OK; + </span> + } + </code></p></div> + + + <h3><a name="servconf" id="servconf">Side notes -- per-server configuration, + virtual servers, <em>etc</em>.</a></h3> + <p>The basic ideas behind per-server module configuration are basically + the same as those for per-directory configuration; there is a creation + function and a merge function, the latter being invoked where a virtual + server has partially overridden the base server configuration, and a + combined structure must be computed. (As with per-directory configuration, + the default if no merge function is specified, and a module is configured + in some virtual server, is that the base configuration is simply + ignored).</p> + + <p>The only substantial difference is that when a command needs to + configure the per-server private module data, it needs to go to the + <code>cmd_parms</code> data to get at it. Here's an example, from the + alias module, which also indicates how a syntax error can be returned + (note that the per-directory configuration argument to the command + handler is declared as a dummy, since the module doesn't actually have + per-directory config data):</p> + + <div class="example"><p><code> + char *add_redirect(cmd_parms *cmd, void *dummy, char *f, char *url)<br /> + {<br /> + <span class="indent"> + server_rec *s = cmd->server;<br /> + alias_server_conf *conf = (alias_server_conf *)<br /> + <span class="indent"> + ap_get_module_config(s->module_config,&alias_module);<br /> + </span> + alias_entry *new = ap_push_array (conf->redirects);<br /> + <br /> + if (!ap_is_url (url)) return "Redirect to non-URL";<br /> + <br /> + new->fake = f; new->real = url;<br /> + return NULL;<br /> + </span> + } + </code></p></div> + +</div></div> +<div class="bottomlang"> +<p><span>Available Languages: </span><a href="../en/developer/API.html" title="English"> en </a></p> +</div><div class="top"><a href="#page-header"><img src="../images/up.gif" alt="top" /></a></div><div class="section"><h2><a id="comments_section" name="comments_section">Comments</a></h2><div class="warning"><strong>Notice:</strong><br />This is not a Q&A section. Comments placed here should be pointed towards suggestions on improving the documentation or server, and may be removed by our moderators if they are either implemented or considered invalid/off-topic. Questions on how to manage the Apache HTTP Server should be directed at either our IRC channel, #httpd, on Libera.chat, or sent to our <a href="https://httpd.apache.org/lists.html">mailing lists</a>.</div> +<script type="text/javascript"><!--//--><![CDATA[//><!-- +var comments_shortname = 'httpd'; +var comments_identifier = 'http://httpd.apache.org/docs/2.4/developer/API.html'; +(function(w, d) { + if (w.location.hostname.toLowerCase() == "httpd.apache.org") { + d.write('<div id="comments_thread"><\/div>'); + var s = d.createElement('script'); + s.type = 'text/javascript'; + s.async = true; + s.src = 'https://comments.apache.org/show_comments.lua?site=' + comments_shortname + '&page=' + comments_identifier; + (d.getElementsByTagName('head')[0] || d.getElementsByTagName('body')[0]).appendChild(s); + } + else { + d.write('<div id="comments_thread">Comments are disabled for this page at the moment.<\/div>'); + } +})(window, document); +//--><!]]></script></div><div id="footer"> +<p class="apache">Copyright 2023 The Apache Software Foundation.<br />Licensed under the <a href="http://www.apache.org/licenses/LICENSE-2.0">Apache License, Version 2.0</a>.</p> +<p class="menu"><a href="../mod/">Modules</a> | <a href="../mod/directives.html">Directives</a> | <a href="http://wiki.apache.org/httpd/FAQ">FAQ</a> | <a href="../glossary.html">Glossary</a> | <a href="../sitemap.html">Sitemap</a></p></div><script type="text/javascript"><!--//--><![CDATA[//><!-- +if (typeof(prettyPrint) !== 'undefined') { + prettyPrint(); +} +//--><!]]></script> +</body></html>
\ No newline at end of file diff --git a/docs/manual/developer/debugging.html b/docs/manual/developer/debugging.html new file mode 100644 index 0000000..83dcee2 --- /dev/null +++ b/docs/manual/developer/debugging.html @@ -0,0 +1,5 @@ +# GENERATED FROM XML -- DO NOT EDIT + +URI: debugging.html.en +Content-Language: en +Content-type: text/html; charset=UTF-8 diff --git a/docs/manual/developer/debugging.html.en b/docs/manual/developer/debugging.html.en new file mode 100644 index 0000000..00ce08c --- /dev/null +++ b/docs/manual/developer/debugging.html.en @@ -0,0 +1,60 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd"> +<html xmlns="http://www.w3.org/1999/xhtml" lang="en" xml:lang="en"><head> +<meta content="text/html; charset=UTF-8" http-equiv="Content-Type" /> +<!-- + XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX + This file is generated from xml source: DO NOT EDIT + XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX + --> +<title>Debugging Memory Allocation in APR - Apache HTTP Server Version 2.4</title> +<link href="../style/css/manual.css" rel="stylesheet" media="all" type="text/css" title="Main stylesheet" /> +<link href="../style/css/manual-loose-100pc.css" rel="alternate stylesheet" media="all" type="text/css" title="No Sidebar - Default font size" /> +<link href="../style/css/manual-print.css" rel="stylesheet" media="print" type="text/css" /><link rel="stylesheet" type="text/css" href="../style/css/prettify.css" /> +<script src="../style/scripts/prettify.min.js" type="text/javascript"> +</script> + +<link href="../images/favicon.ico" rel="shortcut icon" /></head> +<body id="manual-page" class="no-sidebar"><div id="page-header"> +<p class="menu"><a href="../mod/">Modules</a> | <a href="../mod/directives.html">Directives</a> | <a href="http://wiki.apache.org/httpd/FAQ">FAQ</a> | <a href="../glossary.html">Glossary</a> | <a href="../sitemap.html">Sitemap</a></p> +<p class="apache">Apache HTTP Server Version 2.4</p> +<img alt="" src="../images/feather.png" /></div> +<div class="up"><a href="./"><img title="<-" alt="<-" src="../images/left.gif" /></a></div> +<div id="path"> +<a href="http://www.apache.org/">Apache</a> > <a href="http://httpd.apache.org/">HTTP Server</a> > <a href="http://httpd.apache.org/docs/">Documentation</a> > <a href="../">Version 2.4</a> > <a href="./">Developer Documentation</a></div><div id="page-content"><div id="preamble"><h1>Debugging Memory Allocation in APR</h1> +<div class="toplang"> +<p><span>Available Languages: </span><a href="../en/developer/debugging.html" title="English"> en </a></p> +</div> + + <p> + This document has been removed. + </p> +</div> +</div> +<div class="bottomlang"> +<p><span>Available Languages: </span><a href="../en/developer/debugging.html" title="English"> en </a></p> +</div><div class="top"><a href="#page-header"><img src="../images/up.gif" alt="top" /></a></div><div class="section"><h2><a id="comments_section" name="comments_section">Comments</a></h2><div class="warning"><strong>Notice:</strong><br />This is not a Q&A section. Comments placed here should be pointed towards suggestions on improving the documentation or server, and may be removed by our moderators if they are either implemented or considered invalid/off-topic. Questions on how to manage the Apache HTTP Server should be directed at either our IRC channel, #httpd, on Libera.chat, or sent to our <a href="https://httpd.apache.org/lists.html">mailing lists</a>.</div> +<script type="text/javascript"><!--//--><![CDATA[//><!-- +var comments_shortname = 'httpd'; +var comments_identifier = 'http://httpd.apache.org/docs/2.4/developer/debugging.html'; +(function(w, d) { + if (w.location.hostname.toLowerCase() == "httpd.apache.org") { + d.write('<div id="comments_thread"><\/div>'); + var s = d.createElement('script'); + s.type = 'text/javascript'; + s.async = true; + s.src = 'https://comments.apache.org/show_comments.lua?site=' + comments_shortname + '&page=' + comments_identifier; + (d.getElementsByTagName('head')[0] || d.getElementsByTagName('body')[0]).appendChild(s); + } + else { + d.write('<div id="comments_thread">Comments are disabled for this page at the moment.<\/div>'); + } +})(window, document); +//--><!]]></script></div><div id="footer"> +<p class="apache">Copyright 2023 The Apache Software Foundation.<br />Licensed under the <a href="http://www.apache.org/licenses/LICENSE-2.0">Apache License, Version 2.0</a>.</p> +<p class="menu"><a href="../mod/">Modules</a> | <a href="../mod/directives.html">Directives</a> | <a href="http://wiki.apache.org/httpd/FAQ">FAQ</a> | <a href="../glossary.html">Glossary</a> | <a href="../sitemap.html">Sitemap</a></p></div><script type="text/javascript"><!--//--><![CDATA[//><!-- +if (typeof(prettyPrint) !== 'undefined') { + prettyPrint(); +} +//--><!]]></script> +</body></html>
\ No newline at end of file diff --git a/docs/manual/developer/documenting.html b/docs/manual/developer/documenting.html new file mode 100644 index 0000000..fef7894 --- /dev/null +++ b/docs/manual/developer/documenting.html @@ -0,0 +1,9 @@ +# GENERATED FROM XML -- DO NOT EDIT + +URI: documenting.html.en +Content-Language: en +Content-type: text/html; charset=UTF-8 + +URI: documenting.html.zh-cn.utf8 +Content-Language: zh-cn +Content-type: text/html; charset=UTF-8 diff --git a/docs/manual/developer/documenting.html.en b/docs/manual/developer/documenting.html.en new file mode 100644 index 0000000..4902eb7 --- /dev/null +++ b/docs/manual/developer/documenting.html.en @@ -0,0 +1,112 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd"> +<html xmlns="http://www.w3.org/1999/xhtml" lang="en" xml:lang="en"><head> +<meta content="text/html; charset=UTF-8" http-equiv="Content-Type" /> +<!-- + XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX + This file is generated from xml source: DO NOT EDIT + XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX + --> +<title>Documenting code in Apache 2.4 - Apache HTTP Server Version 2.4</title> +<link href="../style/css/manual.css" rel="stylesheet" media="all" type="text/css" title="Main stylesheet" /> +<link href="../style/css/manual-loose-100pc.css" rel="alternate stylesheet" media="all" type="text/css" title="No Sidebar - Default font size" /> +<link href="../style/css/manual-print.css" rel="stylesheet" media="print" type="text/css" /><link rel="stylesheet" type="text/css" href="../style/css/prettify.css" /> +<script src="../style/scripts/prettify.min.js" type="text/javascript"> +</script> + +<link href="../images/favicon.ico" rel="shortcut icon" /></head> +<body id="manual-page" class="no-sidebar"><div id="page-header"> +<p class="menu"><a href="../mod/">Modules</a> | <a href="../mod/directives.html">Directives</a> | <a href="http://wiki.apache.org/httpd/FAQ">FAQ</a> | <a href="../glossary.html">Glossary</a> | <a href="../sitemap.html">Sitemap</a></p> +<p class="apache">Apache HTTP Server Version 2.4</p> +<img alt="" src="../images/feather.png" /></div> +<div class="up"><a href="./"><img title="<-" alt="<-" src="../images/left.gif" /></a></div> +<div id="path"> +<a href="http://www.apache.org/">Apache</a> > <a href="http://httpd.apache.org/">HTTP Server</a> > <a href="http://httpd.apache.org/docs/">Documentation</a> > <a href="../">Version 2.4</a> > <a href="./">Developer Documentation</a></div><div id="page-content"><div id="preamble"><h1>Documenting code in Apache 2.4</h1> +<div class="toplang"> +<p><span>Available Languages: </span><a href="../en/developer/documenting.html" title="English"> en </a> | +<a href="../zh-cn/developer/documenting.html" hreflang="zh-cn" rel="alternate" title="Simplified Chinese"> zh-cn </a></p> +</div> + + <p>Apache 2.4 uses <a href="http://www.doxygen.org/">Doxygen</a> to + document the APIs and global variables in the code. This will explain + the basics of how to document using Doxygen.</p> +</div> +<div class="top"><a href="#page-header"><img alt="top" src="../images/up.gif" /></a></div> +<div class="section"> +<h2><a name="brief" id="brief">Brief Description</a></h2> + <p>To start a documentation block, use <code>/**</code><br /> + To end a documentation block, use <code>*/</code></p> + + <p>In the middle of the block, there are multiple tags we can + use:</p> + + <div class="example"><p><code> + Description of this functions purpose<br /> + @param parameter_name description<br /> + @return description<br /> + @deffunc signature of the function<br /> + </code></p></div> + + <p>The <code>deffunc</code> is not always necessary. DoxyGen does not + have a full parser in it, so any prototype that use a macro in the + return type declaration is too complex for scandoc. Those functions + require a <code>deffunc</code>. An example (using &gt; rather + than >):</p> + + <div class="example"><p><code> + /**<br /> + * return the final element of the pathname<br /> + * @param pathname The path to get the final element of<br /> + * @return the final element of the path<br /> + * @tip Examples:<br /> + * <pre><br /> + * "/foo/bar/gum" -&gt; "gum"<br /> + * "/foo/bar/gum/" -&gt; ""<br /> + * "gum" -&gt; "gum"<br /> + * "wi\\n32\\stuff" -&gt; "stuff"<br /> + * </pre><br /> + * @deffunc const char * ap_filename_of_pathname(const char *pathname)<br /> + */ + </code></p></div> + + <p>At the top of the header file, always include:</p> + <div class="example"><p><code> + /**<br /> + * @package Name of library header<br /> + */ + </code></p></div> + + <p>Doxygen uses a new HTML file for each package. The HTML files are named + {Name_of_library_header}.html, so try to be concise with your names.</p> + + <p>For a further discussion of the possibilities please refer to + <a href="http://www.doxygen.org/">the Doxygen site</a>.</p> +</div></div> +<div class="bottomlang"> +<p><span>Available Languages: </span><a href="../en/developer/documenting.html" title="English"> en </a> | +<a href="../zh-cn/developer/documenting.html" hreflang="zh-cn" rel="alternate" title="Simplified Chinese"> zh-cn </a></p> +</div><div class="top"><a href="#page-header"><img src="../images/up.gif" alt="top" /></a></div><div class="section"><h2><a id="comments_section" name="comments_section">Comments</a></h2><div class="warning"><strong>Notice:</strong><br />This is not a Q&A section. Comments placed here should be pointed towards suggestions on improving the documentation or server, and may be removed by our moderators if they are either implemented or considered invalid/off-topic. Questions on how to manage the Apache HTTP Server should be directed at either our IRC channel, #httpd, on Libera.chat, or sent to our <a href="https://httpd.apache.org/lists.html">mailing lists</a>.</div> +<script type="text/javascript"><!--//--><![CDATA[//><!-- +var comments_shortname = 'httpd'; +var comments_identifier = 'http://httpd.apache.org/docs/2.4/developer/documenting.html'; +(function(w, d) { + if (w.location.hostname.toLowerCase() == "httpd.apache.org") { + d.write('<div id="comments_thread"><\/div>'); + var s = d.createElement('script'); + s.type = 'text/javascript'; + s.async = true; + s.src = 'https://comments.apache.org/show_comments.lua?site=' + comments_shortname + '&page=' + comments_identifier; + (d.getElementsByTagName('head')[0] || d.getElementsByTagName('body')[0]).appendChild(s); + } + else { + d.write('<div id="comments_thread">Comments are disabled for this page at the moment.<\/div>'); + } +})(window, document); +//--><!]]></script></div><div id="footer"> +<p class="apache">Copyright 2023 The Apache Software Foundation.<br />Licensed under the <a href="http://www.apache.org/licenses/LICENSE-2.0">Apache License, Version 2.0</a>.</p> +<p class="menu"><a href="../mod/">Modules</a> | <a href="../mod/directives.html">Directives</a> | <a href="http://wiki.apache.org/httpd/FAQ">FAQ</a> | <a href="../glossary.html">Glossary</a> | <a href="../sitemap.html">Sitemap</a></p></div><script type="text/javascript"><!--//--><![CDATA[//><!-- +if (typeof(prettyPrint) !== 'undefined') { + prettyPrint(); +} +//--><!]]></script> +</body></html>
\ No newline at end of file diff --git a/docs/manual/developer/documenting.html.zh-cn.utf8 b/docs/manual/developer/documenting.html.zh-cn.utf8 new file mode 100644 index 0000000..dab18a1 --- /dev/null +++ b/docs/manual/developer/documenting.html.zh-cn.utf8 @@ -0,0 +1,109 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd"> +<html xmlns="http://www.w3.org/1999/xhtml" lang="zh-cn" xml:lang="zh-cn"><head> +<meta content="text/html; charset=UTF-8" http-equiv="Content-Type" /> +<!-- + XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX + This file is generated from xml source: DO NOT EDIT + XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX + --> +<title>Apache 2.0 文档 - Apache HTTP 服务器 版本 2.4</title> +<link href="../style/css/manual.css" rel="stylesheet" media="all" type="text/css" title="Main stylesheet" /> +<link href="../style/css/manual-loose-100pc.css" rel="alternate stylesheet" media="all" type="text/css" title="No Sidebar - Default font size" /> +<link href="../style/css/manual-print.css" rel="stylesheet" media="print" type="text/css" /><link rel="stylesheet" type="text/css" href="../style/css/prettify.css" /> +<script src="../style/scripts/prettify.min.js" type="text/javascript"> +</script> + +<link href="../images/favicon.ico" rel="shortcut icon" /></head> +<body id="manual-page" class="no-sidebar"><div id="page-header"> +<p class="menu"><a href="../mod/">模块</a> | <a href="../mod/directives.html">指令</a> | <a href="http://wiki.apache.org/httpd/FAQ">常见问题</a> | <a href="../glossary.html">术语</a> | <a href="../sitemap.html">网站导航</a></p> +<p class="apache">Apache HTTP 服务器版本 2.4</p> +<img alt="" src="../images/feather.png" /></div> +<div class="up"><a href="./"><img title="<-" alt="<-" src="../images/left.gif" /></a></div> +<div id="path"> +<a href="http://www.apache.org/">Apache</a> > <a href="http://httpd.apache.org/">HTTP 服务器</a> > <a href="http://httpd.apache.org/docs/">文档</a> > <a href="../">版本 2.4</a> > <a href="./">开发者文档</a></div><div id="page-content"><div id="preamble"><h1>Apache 2.0 文档</h1> +<div class="toplang"> +<p><span>可用语言: </span><a href="../en/developer/documenting.html" hreflang="en" rel="alternate" title="English"> en </a> | +<a href="../zh-cn/developer/documenting.html" title="Simplified Chinese"> zh-cn </a></p> +</div> +<div class="outofdate">此翻译可能过期。要了解最近的更改,请阅读英文版。</div> + + <p>Apache 2.0 使用 <a href="http://www.doxygen.org/">Doxygen</a> 从代码中 + 生成 API 和全局变量的文档。下面是对使用 Doxygen 生成文档的简介。</p> +</div> +<div class="top"><a href="#page-header"><img alt="top" src="../images/up.gif" /></a></div> +<div class="section"> +<h2><a name="brief" id="brief">简要说明</a></h2> + <p>使用 <code>/**</code> 开始文档块<br /> + 使用 <code>*/</code> 结束文档块</p> + + <p>在文档块中,我们可以使用多个标签:</p> + + <div class="example"><p><code> + Description of this functions purpose<br /> + @param parameter_name description<br /> + @return description<br /> + @deffunc signature of the function<br /> + </code></p></div> + + <p>一般不需要 <code>deffunc</code> 。DoxyGen 没有完整的解析器,所以任何 + 在返回类型声明中使用宏的原型,都是太复杂了。这些函数就需要使用 <code>deffunc</code>。 + 例如 (使用 &gt; 而不是 >):</p> + + <div class="example"><p><code> + /**<br /> + * return the final element of the pathname<br /> + * @param pathname The path to get the final element of<br /> + * @return the final element of the path<br /> + * @tip Examples:<br /> + * <pre><br /> + * "/foo/bar/gum" -&gt; "gum"<br /> + * "/foo/bar/gum/" -&gt; ""<br /> + * "gum" -&gt; "gum"<br /> + * "wi\\n32\\stuff" -&gt; "stuff"<br /> + * </pre><br /> + * @deffunc const char * ap_filename_of_pathname(const char *pathname)<br /> + */ + </code></p></div> + + <p>总是在头文件开始包含:</p> + <div class="example"><p><code> + /**<br /> + * @package Name of library header<br /> + */ + </code></p></div> + + <p>Doxygen 为每个包生成一个新的 HTML 文件,名字是 + {Name_of_library_header}.html,所以请简化名称。</p> + + <p>更深入的讨论,请参见 + <a href="http://www.doxygen.org/">Doxygen 站点</a>。</p> +</div></div> +<div class="bottomlang"> +<p><span>可用语言: </span><a href="../en/developer/documenting.html" hreflang="en" rel="alternate" title="English"> en </a> | +<a href="../zh-cn/developer/documenting.html" title="Simplified Chinese"> zh-cn </a></p> +</div><div class="top"><a href="#page-header"><img src="../images/up.gif" alt="top" /></a></div><div class="section"><h2><a id="comments_section" name="comments_section">评论</a></h2><div class="warning"><strong>Notice:</strong><br />This is not a Q&A section. Comments placed here should be pointed towards suggestions on improving the documentation or server, and may be removed by our moderators if they are either implemented or considered invalid/off-topic. Questions on how to manage the Apache HTTP Server should be directed at either our IRC channel, #httpd, on Libera.chat, or sent to our <a href="https://httpd.apache.org/lists.html">mailing lists</a>.</div> +<script type="text/javascript"><!--//--><![CDATA[//><!-- +var comments_shortname = 'httpd'; +var comments_identifier = 'http://httpd.apache.org/docs/2.4/developer/documenting.html'; +(function(w, d) { + if (w.location.hostname.toLowerCase() == "httpd.apache.org") { + d.write('<div id="comments_thread"><\/div>'); + var s = d.createElement('script'); + s.type = 'text/javascript'; + s.async = true; + s.src = 'https://comments.apache.org/show_comments.lua?site=' + comments_shortname + '&page=' + comments_identifier; + (d.getElementsByTagName('head')[0] || d.getElementsByTagName('body')[0]).appendChild(s); + } + else { + d.write('<div id="comments_thread">Comments are disabled for this page at the moment.<\/div>'); + } +})(window, document); +//--><!]]></script></div><div id="footer"> +<p class="apache">Copyright 2023 The Apache Software Foundation.<br />基于 <a href="http://www.apache.org/licenses/LICENSE-2.0">Apache License, Version 2.0</a> 许可证.</p> +<p class="menu"><a href="../mod/">模块</a> | <a href="../mod/directives.html">指令</a> | <a href="http://wiki.apache.org/httpd/FAQ">常见问题</a> | <a href="../glossary.html">术语</a> | <a href="../sitemap.html">网站导航</a></p></div><script type="text/javascript"><!--//--><![CDATA[//><!-- +if (typeof(prettyPrint) !== 'undefined') { + prettyPrint(); +} +//--><!]]></script> +</body></html>
\ No newline at end of file diff --git a/docs/manual/developer/filters.html b/docs/manual/developer/filters.html new file mode 100644 index 0000000..48559da --- /dev/null +++ b/docs/manual/developer/filters.html @@ -0,0 +1,5 @@ +# GENERATED FROM XML -- DO NOT EDIT + +URI: filters.html.en +Content-Language: en +Content-type: text/html; charset=UTF-8 diff --git a/docs/manual/developer/filters.html.en b/docs/manual/developer/filters.html.en new file mode 100644 index 0000000..61971b5 --- /dev/null +++ b/docs/manual/developer/filters.html.en @@ -0,0 +1,234 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd"> +<html xmlns="http://www.w3.org/1999/xhtml" lang="en" xml:lang="en"><head> +<meta content="text/html; charset=UTF-8" http-equiv="Content-Type" /> +<!-- + XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX + This file is generated from xml source: DO NOT EDIT + XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX + --> +<title>How filters work in Apache 2.0 - Apache HTTP Server Version 2.4</title> +<link href="../style/css/manual.css" rel="stylesheet" media="all" type="text/css" title="Main stylesheet" /> +<link href="../style/css/manual-loose-100pc.css" rel="alternate stylesheet" media="all" type="text/css" title="No Sidebar - Default font size" /> +<link href="../style/css/manual-print.css" rel="stylesheet" media="print" type="text/css" /><link rel="stylesheet" type="text/css" href="../style/css/prettify.css" /> +<script src="../style/scripts/prettify.min.js" type="text/javascript"> +</script> + +<link href="../images/favicon.ico" rel="shortcut icon" /></head> +<body id="manual-page"><div id="page-header"> +<p class="menu"><a href="../mod/">Modules</a> | <a href="../mod/directives.html">Directives</a> | <a href="http://wiki.apache.org/httpd/FAQ">FAQ</a> | <a href="../glossary.html">Glossary</a> | <a href="../sitemap.html">Sitemap</a></p> +<p class="apache">Apache HTTP Server Version 2.4</p> +<img alt="" src="../images/feather.png" /></div> +<div class="up"><a href="./"><img title="<-" alt="<-" src="../images/left.gif" /></a></div> +<div id="path"> +<a href="http://www.apache.org/">Apache</a> > <a href="http://httpd.apache.org/">HTTP Server</a> > <a href="http://httpd.apache.org/docs/">Documentation</a> > <a href="../">Version 2.4</a> > <a href="./">Developer Documentation</a></div><div id="page-content"><div id="preamble"><h1>How filters work in Apache 2.0</h1> +<div class="toplang"> +<p><span>Available Languages: </span><a href="../en/developer/filters.html" title="English"> en </a></p> +</div> + + <div class="warning"><h3>Warning</h3> + <p>This is a cut 'n paste job from an email + (<022501c1c529$f63a9550$7f00000a@KOJ>) and only reformatted for + better readability. It's not up to date but may be a good start for + further research.</p> + </div> +</div> +<div id="quickview"><a href="https://www.apache.org/foundation/contributing.html" class="badge"><img src="https://www.apache.org/images/SupportApache-small.png" alt="Support Apache!" /></a><ul id="toc"><li><img alt="" src="../images/down.gif" /> <a href="#types">Filter Types</a></li> +<li><img alt="" src="../images/down.gif" /> <a href="#howinserted">How are filters inserted?</a></li> +<li><img alt="" src="../images/down.gif" /> <a href="#asis">Asis</a></li> +<li><img alt="" src="../images/down.gif" /> <a href="#conclusion">Explanations</a></li> +</ul><h3>See also</h3><ul class="seealso"><li><a href="#comments_section">Comments</a></li></ul></div> +<div class="top"><a href="#page-header"><img alt="top" src="../images/up.gif" /></a></div> +<div class="section"> +<h2><a name="types" id="types">Filter Types</a></h2> + <p>There are three basic filter types (each of these is actually broken + down into two categories, but that comes later).</p> + + <dl> + <dt><code>CONNECTION</code></dt> + <dd>Filters of this type are valid for the lifetime of this connection. + (<code>AP_FTYPE_CONNECTION</code>, <code>AP_FTYPE_NETWORK</code>)</dd> + + <dt><code>PROTOCOL</code></dt> + <dd>Filters of this type are valid for the lifetime of this request from + the point of view of the client, this means that the request is valid + from the time that the request is sent until the time that the response + is received. (<code>AP_FTYPE_PROTOCOL</code>, + <code>AP_FTYPE_TRANSCODE</code>)</dd> + + <dt><code>RESOURCE</code></dt> + <dd>Filters of this type are valid for the time that this content is used + to satisfy a request. For simple requests, this is identical to + <code>PROTOCOL</code>, but internal redirects and sub-requests can change + the content without ending the request. (<code>AP_FTYPE_RESOURCE</code>, + <code>AP_FTYPE_CONTENT_SET</code>)</dd> + </dl> + + <p>It is important to make the distinction between a protocol and a + resource filter. A resource filter is tied to a specific resource, it + may also be tied to header information, but the main binding is to a + resource. If you are writing a filter and you want to know if it is + resource or protocol, the correct question to ask is: "Can this filter + be removed if the request is redirected to a different resource?" If + the answer is yes, then it is a resource filter. If it is no, then it + is most likely a protocol or connection filter. I won't go into + connection filters, because they seem to be well understood. With this + definition, a few examples might help:</p> + + <dl> + <dt>Byterange</dt> + <dd>We have coded it to be inserted for all requests, and it is removed + if not used. Because this filter is active at the beginning of all + requests, it can not be removed if it is redirected, so this is a + protocol filter.</dd> + + <dt>http_header</dt> + <dd>This filter actually writes the headers to the network. This is + obviously a required filter (except in the asis case which is special + and will be dealt with below) and so it is a protocol filter.</dd> + + <dt>Deflate</dt> + <dd>The administrator configures this filter based on which file has been + requested. If we do an internal redirect from an autoindex page to an + index.html page, the deflate filter may be added or removed based on + config, so this is a resource filter.</dd> + </dl> + + <p>The further breakdown of each category into two more filter types is + strictly for ordering. We could remove it, and only allow for one + filter type, but the order would tend to be wrong, and we would need to + hack things to make it work. Currently, the <code>RESOURCE</code> filters + only have one filter type, but that should change.</p> +</div><div class="top"><a href="#page-header"><img alt="top" src="../images/up.gif" /></a></div> +<div class="section"> +<h2><a name="howinserted" id="howinserted">How are filters inserted?</a></h2> + <p>This is actually rather simple in theory, but the code is + complex. First of all, it is important that everybody realize that + there are three filter lists for each request, but they are all + concatenated together:</p> + <ul> + <li><code>r->output_filters</code> (corresponds to RESOURCE)</li> + <li><code>r->proto_output_filters</code> (corresponds to PROTOCOL)</li> + <li><code>r->connection->output_filters</code> (corresponds to CONNECTION)</li> + </ul> + + <p>The problem previously, was that we used a singly linked list to create the filter stack, and we + started from the "correct" location. This means that if I had a + <code>RESOURCE</code> filter on the stack, and I added a + <code>CONNECTION</code> filter, the <code>CONNECTION</code> filter would + be ignored. This should make sense, because we would insert the connection + filter at the top of the <code>c->output_filters</code> list, but the end + of <code>r->output_filters</code> pointed to the filter that used to be + at the front of <code>c->output_filters</code>. This is obviously wrong. + The new insertion code uses a doubly linked list. This has the advantage + that we never lose a filter that has been inserted. Unfortunately, it comes + with a separate set of headaches.</p> + + <p>The problem is that we have two different cases were we use subrequests. + The first is to insert more data into a response. The second is to + replace the existing response with an internal redirect. These are two + different cases and need to be treated as such.</p> + + <p>In the first case, we are creating the subrequest from within a handler + or filter. This means that the next filter should be passed to + <code>make_sub_request</code> function, and the last resource filter in the + sub-request will point to the next filter in the main request. This + makes sense, because the sub-request's data needs to flow through the + same set of filters as the main request. A graphical representation + might help:</p> + +<div class="example"><pre>Default_handler --> includes_filter --> byterange --> ...</pre></div> + + <p>If the includes filter creates a sub request, then we don't want the + data from that sub-request to go through the includes filter, because it + might not be SSI data. So, the subrequest adds the following:</p> + +<div class="example"><pre>Default_handler --> includes_filter -/-> byterange --> ... + / +Default_handler --> sub_request_core</pre></div> + + <p>What happens if the subrequest is SSI data? Well, that's easy, the + <code>includes_filter</code> is a resource filter, so it will be added to + the sub request in between the <code>Default_handler</code> and the + <code>sub_request_core</code> filter.</p> + + <p>The second case for sub-requests is when one sub-request is going to + become the real request. This happens whenever a sub-request is created + outside of a handler or filter, and NULL is passed as the next filter to + the <code>make_sub_request</code> function.</p> + + <p>In this case, the resource filters no longer make sense for the new + request, because the resource has changed. So, instead of starting from + scratch, we simply point the front of the resource filters for the + sub-request to the front of the protocol filters for the old request. + This means that we won't lose any of the protocol filters, neither will + we try to send this data through a filter that shouldn't see it.</p> + + <p>The problem is that we are using a doubly-linked list for our filter + stacks now. But, you should notice that it is possible for two lists to + intersect in this model. So, you do you handle the previous pointer? + This is a very difficult question to answer, because there is no "right" + answer, either method is equally valid. I looked at why we use the + previous pointer. The only reason for it is to allow for easier + addition of new servers. With that being said, the solution I chose was + to make the previous pointer always stay on the original request.</p> + + <p>This causes some more complex logic, but it works for all cases. My + concern in having it move to the sub-request, is that for the more + common case (where a sub-request is used to add data to a response), the + main filter chain would be wrong. That didn't seem like a good idea to + me.</p> +</div><div class="top"><a href="#page-header"><img alt="top" src="../images/up.gif" /></a></div> +<div class="section"> +<h2><a name="asis" id="asis">Asis</a></h2> + <p>The final topic. :-) Mod_Asis is a bit of a hack, but the + handler needs to remove all filters except for connection filters, and + send the data. If you are using <code class="module"><a href="../mod/mod_asis.html">mod_asis</a></code>, all other + bets are off.</p> +</div><div class="top"><a href="#page-header"><img alt="top" src="../images/up.gif" /></a></div> +<div class="section"> +<h2><a name="conclusion" id="conclusion">Explanations</a></h2> + <p>The absolutely last point is that the reason this code was so hard to + get right, was because we had hacked so much to force it to work. I + wrote most of the hacks originally, so I am very much to blame. + However, now that the code is right, I have started to remove some + hacks. Most people should have seen that the <code>reset_filters</code> + and <code>add_required_filters</code> functions are gone. Those inserted + protocol level filters for error conditions, in fact, both functions did + the same thing, one after the other, it was really strange. Because we + don't lose protocol filters for error cases any more, those hacks went away. + The <code>HTTP_HEADER</code>, <code>Content-length</code>, and + <code>Byterange</code> filters are all added in the + <code>insert_filters</code> phase, because if they were added earlier, we + had some interesting interactions. Now, those could all be moved to be + inserted with the <code>HTTP_IN</code>, <code>CORE</code>, and + <code>CORE_IN</code> filters. That would make the code easier to + follow.</p> +</div></div> +<div class="bottomlang"> +<p><span>Available Languages: </span><a href="../en/developer/filters.html" title="English"> en </a></p> +</div><div class="top"><a href="#page-header"><img src="../images/up.gif" alt="top" /></a></div><div class="section"><h2><a id="comments_section" name="comments_section">Comments</a></h2><div class="warning"><strong>Notice:</strong><br />This is not a Q&A section. Comments placed here should be pointed towards suggestions on improving the documentation or server, and may be removed by our moderators if they are either implemented or considered invalid/off-topic. Questions on how to manage the Apache HTTP Server should be directed at either our IRC channel, #httpd, on Libera.chat, or sent to our <a href="https://httpd.apache.org/lists.html">mailing lists</a>.</div> +<script type="text/javascript"><!--//--><![CDATA[//><!-- +var comments_shortname = 'httpd'; +var comments_identifier = 'http://httpd.apache.org/docs/2.4/developer/filters.html'; +(function(w, d) { + if (w.location.hostname.toLowerCase() == "httpd.apache.org") { + d.write('<div id="comments_thread"><\/div>'); + var s = d.createElement('script'); + s.type = 'text/javascript'; + s.async = true; + s.src = 'https://comments.apache.org/show_comments.lua?site=' + comments_shortname + '&page=' + comments_identifier; + (d.getElementsByTagName('head')[0] || d.getElementsByTagName('body')[0]).appendChild(s); + } + else { + d.write('<div id="comments_thread">Comments are disabled for this page at the moment.<\/div>'); + } +})(window, document); +//--><!]]></script></div><div id="footer"> +<p class="apache">Copyright 2023 The Apache Software Foundation.<br />Licensed under the <a href="http://www.apache.org/licenses/LICENSE-2.0">Apache License, Version 2.0</a>.</p> +<p class="menu"><a href="../mod/">Modules</a> | <a href="../mod/directives.html">Directives</a> | <a href="http://wiki.apache.org/httpd/FAQ">FAQ</a> | <a href="../glossary.html">Glossary</a> | <a href="../sitemap.html">Sitemap</a></p></div><script type="text/javascript"><!--//--><![CDATA[//><!-- +if (typeof(prettyPrint) !== 'undefined') { + prettyPrint(); +} +//--><!]]></script> +</body></html>
\ No newline at end of file diff --git a/docs/manual/developer/hooks.html b/docs/manual/developer/hooks.html new file mode 100644 index 0000000..75c3cad --- /dev/null +++ b/docs/manual/developer/hooks.html @@ -0,0 +1,5 @@ +# GENERATED FROM XML -- DO NOT EDIT + +URI: hooks.html.en +Content-Language: en +Content-type: text/html; charset=UTF-8 diff --git a/docs/manual/developer/hooks.html.en b/docs/manual/developer/hooks.html.en new file mode 100644 index 0000000..30aa6f9 --- /dev/null +++ b/docs/manual/developer/hooks.html.en @@ -0,0 +1,261 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd"> +<html xmlns="http://www.w3.org/1999/xhtml" lang="en" xml:lang="en"><head> +<meta content="text/html; charset=UTF-8" http-equiv="Content-Type" /> +<!-- + XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX + This file is generated from xml source: DO NOT EDIT + XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX + --> +<title>Hook Functions in the Apache HTTP Server 2.x - Apache HTTP Server Version 2.4</title> +<link href="../style/css/manual.css" rel="stylesheet" media="all" type="text/css" title="Main stylesheet" /> +<link href="../style/css/manual-loose-100pc.css" rel="alternate stylesheet" media="all" type="text/css" title="No Sidebar - Default font size" /> +<link href="../style/css/manual-print.css" rel="stylesheet" media="print" type="text/css" /><link rel="stylesheet" type="text/css" href="../style/css/prettify.css" /> +<script src="../style/scripts/prettify.min.js" type="text/javascript"> +</script> + +<link href="../images/favicon.ico" rel="shortcut icon" /></head> +<body id="manual-page"><div id="page-header"> +<p class="menu"><a href="../mod/">Modules</a> | <a href="../mod/directives.html">Directives</a> | <a href="http://wiki.apache.org/httpd/FAQ">FAQ</a> | <a href="../glossary.html">Glossary</a> | <a href="../sitemap.html">Sitemap</a></p> +<p class="apache">Apache HTTP Server Version 2.4</p> +<img alt="" src="../images/feather.png" /></div> +<div class="up"><a href="./"><img title="<-" alt="<-" src="../images/left.gif" /></a></div> +<div id="path"> +<a href="http://www.apache.org/">Apache</a> > <a href="http://httpd.apache.org/">HTTP Server</a> > <a href="http://httpd.apache.org/docs/">Documentation</a> > <a href="../">Version 2.4</a> > <a href="./">Developer Documentation</a></div><div id="page-content"><div id="preamble"><h1>Hook Functions in the Apache HTTP Server 2.x</h1> +<div class="toplang"> +<p><span>Available Languages: </span><a href="../en/developer/hooks.html" title="English"> en </a></p> +</div> + + <div class="warning"><h3>Warning</h3> + <p>This document is still in development and may be partially out of + date.</p> + </div> + + <p>In general, a hook function is one that the Apache HTTP Server + will call at some point during the processing of a request. + Modules can provide functions that are called, and specify when + they get called in comparison to other modules.</p> +</div> +<div id="quickview"><a href="https://www.apache.org/foundation/contributing.html" class="badge"><img src="https://www.apache.org/images/SupportApache-small.png" alt="Support Apache!" /></a><ul id="toc"><li><img alt="" src="../images/down.gif" /> <a href="#corehooks">Core Hooks</a></li> +<li><img alt="" src="../images/down.gif" /> <a href="#create">Creating a hook function</a></li> +<li><img alt="" src="../images/down.gif" /> <a href="#hooking">Hooking the hook</a></li> +</ul><h3>See also</h3><ul class="seealso"><li><a href="#comments_section">Comments</a></li></ul></div> +<div class="top"><a href="#page-header"><img alt="top" src="../images/up.gif" /></a></div> +<div class="section"> +<h2><a name="corehooks" id="corehooks">Core Hooks</a></h2> + <p>The httpd's core modules offer a predefinined list of hooks + used during the standard <a href="./request.html">request processing</a> + phase. Creating a new hook will expose a function that + implements it (see sections below) but it is essential to understand that you will not + extend the httpd's core hooks. Their presence and order in the request processing is in fact + a consequence of how they are called in <code>server/request.c</code> + (check <a href="./modguide.html#hooking">this section</a> + for an overview). The core hooks are listed in the + <a href="https://ci.apache.org/projects/httpd/trunk/doxygen/group__hooks.html">doxygen documentation</a>.</p> + + <p>Reading <a href="./modguide.html">guide for developing modules</a> and + <a href="./request.html">request processing</a> before proceeding is + highly recommended. + </p> +</div><div class="top"><a href="#page-header"><img alt="top" src="../images/up.gif" /></a></div> +<div class="section"> +<h2><a name="create" id="create">Creating a hook function</a></h2> + <p>In order to create a new hook, four things need to be + done:</p> + + <h3><a name="create-declare" id="create-declare">Declare the hook function</a></h3> + <p>Use the <code>AP_DECLARE_HOOK</code> macro, which needs to be given + the return type of the hook function, the name of the hook, and the + arguments. For example, if the hook returns an <code>int</code> and + takes a <code>request_rec *</code> and an <code>int</code> and is + called <code>do_something</code>, then declare it like this:</p> + <pre class="prettyprint lang-c">AP_DECLARE_HOOK(int, do_something, (request_rec *r, int n))</pre> + + + <p>This should go in a header which modules will include if + they want to use the hook.</p> + + + <h3><a name="create-create" id="create-create">Create the hook structure</a></h3> + <p>Each source file that exports a hook has a private structure + which is used to record the module functions that use the hook. + This is declared as follows:</p> + + <pre class="prettyprint lang-c">APR_HOOK_STRUCT( + APR_HOOK_LINK(do_something) + ... +)</pre> + + + + <h3><a name="create-implement" id="create-implement">Implement the hook caller</a></h3> + <p>The source file that exports the hook has to implement a + function that will call the hook. There are currently three + possible ways to do this. In all cases, the calling function is + called <code>ap_run_<var>hookname</var>()</code>.</p> + + <h4>Void hooks</h4> + <p>If the return value of a hook is <code>void</code>, then all the + hooks are called, and the caller is implemented like this:</p> + + <pre class="prettyprint lang-c">AP_IMPLEMENT_HOOK_VOID(do_something, (request_rec *r, int n), (r, n))</pre> + + + <p>The second and third arguments are the dummy argument + declaration and the dummy arguments as they will be used when + calling the hook. In other words, this macro expands to + something like this:</p> + + <pre class="prettyprint lang-c">void ap_run_do_something(request_rec *r, int n) +{ + ... + do_something(r, n); +}</pre> + + + + <h4>Hooks that return a value</h4> + <p>If the hook returns a value, then it can either be run until + the first hook that does something interesting, like so:</p> + + <pre class="prettyprint lang-c">AP_IMPLEMENT_HOOK_RUN_FIRST(int, do_something, (request_rec *r, int n), (r, n), DECLINED)</pre> + + + <p>The first hook that does <em>not</em> return <code>DECLINED</code> + stops the loop and its return value is returned from the hook + caller. Note that <code>DECLINED</code> is the traditional + hook return value meaning "I didn't do anything", but it can be + whatever suits you.</p> + + <p>Alternatively, all hooks can be run until an error occurs. + This boils down to permitting <em>two</em> return values, one of + which means "I did something, and it was OK" and the other + meaning "I did nothing". The first function that returns a + value other than one of those two stops the loop, and its + return is the return value. Declare these like so:</p> + + <pre class="prettyprint lang-c">AP_IMPLEMENT_HOOK_RUN_ALL(int, do_something, (request_rec *r, int n), (r, n), OK, DECLINED)</pre> + + + <p>Again, <code>OK</code> and <code>DECLINED</code> are the traditional + values. You can use what you want.</p> + + + + <h3><a name="create-call" id="create-call">Call the hook callers</a></h3> + <p>At appropriate moments in the code, call the hook caller, + like so:</p> + + <pre class="prettyprint lang-c">int n, ret; +request_rec *r; + +ret=ap_run_do_something(r, n);</pre> + + +</div><div class="top"><a href="#page-header"><img alt="top" src="../images/up.gif" /></a></div> +<div class="section"> +<h2><a name="hooking" id="hooking">Hooking the hook</a></h2> + <p>A module that wants a hook to be called needs to do two + things.</p> + + <h3><a name="hooking-implement" id="hooking-implement">Implement the hook function</a></h3> + <p>Include the appropriate header, and define a static function + of the correct type:</p> + + <pre class="prettyprint lang-c">static int my_something_doer(request_rec *r, int n) +{ + ... + return OK; +}</pre> + + + + <h3><a name="hooking-add" id="hooking-add">Add a hook registering function</a></h3> + <p>During initialisation, the server will call each modules hook + registering function, which is included in the module + structure:</p> + + <pre class="prettyprint lang-c">static void my_register_hooks() +{ + ap_hook_do_something(my_something_doer, NULL, NULL, APR_HOOK_MIDDLE); +} + +mode MODULE_VAR_EXPORT my_module = +{ + ... + my_register_hooks /* register hooks */ +};</pre> + + + + <h3><a name="hooking-order" id="hooking-order">Controlling hook calling order</a></h3> + <p>In the example above, we didn't use the three arguments in + the hook registration function that control calling order of + all the functions registered within the hook. + There are two mechanisms for doing this. The first, rather + crude, method, allows us to specify roughly where the hook is + run relative to other modules. The final argument control this. + There are three possible values: <code>APR_HOOK_FIRST</code>, + <code>APR_HOOK_MIDDLE</code> and <code>APR_HOOK_LAST</code>.</p> + + <p>All modules using any particular value may be run in any + order relative to each other, but, of course, all modules using + <code>APR_HOOK_FIRST</code> will be run before <code>APR_HOOK_MIDDLE</code> + which are before <code>APR_HOOK_LAST</code>. Modules that don't care + when they are run should use <code>APR_HOOK_MIDDLE</code>. <em>These + values are spaced out, so that positions like <code>APR_HOOK_FIRST-2</code> + are possible to hook slightly earlier than other functions.</em></p> + + <p>Note that there are two more values, + <code>APR_HOOK_REALLY_FIRST</code> and <code>APR_HOOK_REALLY_LAST</code>. These + should only be used by the hook exporter.</p> + + <p>The other method allows finer control. When a module knows + that it must be run before (or after) some other modules, it + can specify them by name. The second (third) argument is a + NULL-terminated array of strings consisting of the names of + modules that must be run before (after) the current module. For + example, suppose we want "mod_xyz.c" and "mod_abc.c" to run + before we do, then we'd hook as follows:</p> + + <pre class="prettyprint lang-c">static void register_hooks() +{ + static const char * const aszPre[] = { "mod_xyz.c", "mod_abc.c", NULL }; + + ap_hook_do_something(my_something_doer, aszPre, NULL, APR_HOOK_MIDDLE); +}</pre> + + + <p>Note that the sort used to achieve this is stable, so + ordering set by <code>APR_HOOK_<var>ORDER</var></code> is preserved, as far + as is possible.</p> + + +</div></div> +<div class="bottomlang"> +<p><span>Available Languages: </span><a href="../en/developer/hooks.html" title="English"> en </a></p> +</div><div class="top"><a href="#page-header"><img src="../images/up.gif" alt="top" /></a></div><div class="section"><h2><a id="comments_section" name="comments_section">Comments</a></h2><div class="warning"><strong>Notice:</strong><br />This is not a Q&A section. Comments placed here should be pointed towards suggestions on improving the documentation or server, and may be removed by our moderators if they are either implemented or considered invalid/off-topic. Questions on how to manage the Apache HTTP Server should be directed at either our IRC channel, #httpd, on Libera.chat, or sent to our <a href="https://httpd.apache.org/lists.html">mailing lists</a>.</div> +<script type="text/javascript"><!--//--><![CDATA[//><!-- +var comments_shortname = 'httpd'; +var comments_identifier = 'http://httpd.apache.org/docs/2.4/developer/hooks.html'; +(function(w, d) { + if (w.location.hostname.toLowerCase() == "httpd.apache.org") { + d.write('<div id="comments_thread"><\/div>'); + var s = d.createElement('script'); + s.type = 'text/javascript'; + s.async = true; + s.src = 'https://comments.apache.org/show_comments.lua?site=' + comments_shortname + '&page=' + comments_identifier; + (d.getElementsByTagName('head')[0] || d.getElementsByTagName('body')[0]).appendChild(s); + } + else { + d.write('<div id="comments_thread">Comments are disabled for this page at the moment.<\/div>'); + } +})(window, document); +//--><!]]></script></div><div id="footer"> +<p class="apache">Copyright 2023 The Apache Software Foundation.<br />Licensed under the <a href="http://www.apache.org/licenses/LICENSE-2.0">Apache License, Version 2.0</a>.</p> +<p class="menu"><a href="../mod/">Modules</a> | <a href="../mod/directives.html">Directives</a> | <a href="http://wiki.apache.org/httpd/FAQ">FAQ</a> | <a href="../glossary.html">Glossary</a> | <a href="../sitemap.html">Sitemap</a></p></div><script type="text/javascript"><!--//--><![CDATA[//><!-- +if (typeof(prettyPrint) !== 'undefined') { + prettyPrint(); +} +//--><!]]></script> +</body></html>
\ No newline at end of file diff --git a/docs/manual/developer/index.html b/docs/manual/developer/index.html new file mode 100644 index 0000000..d79f31b --- /dev/null +++ b/docs/manual/developer/index.html @@ -0,0 +1,9 @@ +# GENERATED FROM XML -- DO NOT EDIT + +URI: index.html.en +Content-Language: en +Content-type: text/html; charset=UTF-8 + +URI: index.html.zh-cn.utf8 +Content-Language: zh-cn +Content-type: text/html; charset=UTF-8 diff --git a/docs/manual/developer/index.html.en b/docs/manual/developer/index.html.en new file mode 100644 index 0000000..48b834d --- /dev/null +++ b/docs/manual/developer/index.html.en @@ -0,0 +1,89 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd"> +<html xmlns="http://www.w3.org/1999/xhtml" lang="en" xml:lang="en"><head> +<meta content="text/html; charset=UTF-8" http-equiv="Content-Type" /> +<!-- + XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX + This file is generated from xml source: DO NOT EDIT + XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX + --> +<title>Developer Documentation for the Apache HTTP Server 2.4 - Apache HTTP Server Version 2.4</title> +<link href="../style/css/manual.css" rel="stylesheet" media="all" type="text/css" title="Main stylesheet" /> +<link href="../style/css/manual-loose-100pc.css" rel="alternate stylesheet" media="all" type="text/css" title="No Sidebar - Default font size" /> +<link href="../style/css/manual-print.css" rel="stylesheet" media="print" type="text/css" /><link rel="stylesheet" type="text/css" href="../style/css/prettify.css" /> +<script src="../style/scripts/prettify.min.js" type="text/javascript"> +</script> + +<link href="../images/favicon.ico" rel="shortcut icon" /></head> +<body id="manual-page"><div id="page-header"> +<p class="menu"><a href="../mod/">Modules</a> | <a href="../mod/directives.html">Directives</a> | <a href="http://wiki.apache.org/httpd/FAQ">FAQ</a> | <a href="../glossary.html">Glossary</a> | <a href="../sitemap.html">Sitemap</a></p> +<p class="apache">Apache HTTP Server Version 2.4</p> +<img alt="" src="../images/feather.png" /></div> +<div class="up"><a href="../"><img title="<-" alt="<-" src="../images/left.gif" /></a></div> +<div id="path"> +<a href="http://www.apache.org/">Apache</a> > <a href="http://httpd.apache.org/">HTTP Server</a> > <a href="http://httpd.apache.org/docs/">Documentation</a> > <a href="../">Version 2.4</a></div><div id="page-content"><div id="preamble"><h1>Developer Documentation for the Apache HTTP Server 2.4</h1> +<div class="toplang"> +<p><span>Available Languages: </span><a href="../en/developer/" title="English"> en </a> | +<a href="../zh-cn/developer/" hreflang="zh-cn" rel="alternate" title="Simplified Chinese"> zh-cn </a></p> +</div> + + <div class="warning"><h3>Warning</h3> + <p>Many of the documents listed here are in need of update. + They are in different stages of progress. + Please be patient and follow <a href="https://httpd.apache.org/docs-project/">this link</a> + to propose a fix or point out any error/discrepancy.</p> + </div> +</div> +<div id="quickview"><a href="https://www.apache.org/foundation/contributing.html" class="badge"><img src="https://www.apache.org/images/SupportApache-small.png" alt="Support Apache!" /></a><ul id="toc"><li><img alt="" src="../images/down.gif" /> <a href="#developing">2.4 development documents</a></li> +<li><img alt="" src="../images/down.gif" /> <a href="#upgrading">Upgrading to 2.4</a></li> +<li><img alt="" src="../images/down.gif" /> <a href="#external">Other Resources</a></li> +</ul></div> +<div class="top"><a href="#page-header"><img alt="top" src="../images/up.gif" /></a></div> +<div class="section"> +<h2><a name="developing" id="developing">2.4 development documents</a></h2> + <ul> + <li><a href="modguide.html">Developing modules for the Apache HTTP Server 2.4</a></li> + <li><a href="hooks.html">Hook Functions in 2.4</a></li> + <li><a href="request.html">Request Processing in 2.4</a></li> + <li><a href="filters.html">How filters work in 2.4</a></li> + <li><a href="output-filters.html">Guidelines for output filters in 2.4</a></li> + <li><a href="documenting.html">Documenting code in 2.4</a></li> + <li><a href="thread_safety.html">Thread Safety Issues in 2.4</a></li> + </ul> +</div><div class="top"><a href="#page-header"><img alt="top" src="../images/up.gif" /></a></div> +<div class="section"> +<h2><a name="upgrading" id="upgrading">Upgrading to 2.4</a></h2> + <ul> + <li><a href="new_api_2_4.html">API changes in 2.3/2.4</a></li> + <li><a href="modules.html">Converting Modules from 1.3 to 2.x</a></li> + </ul> +</div><div class="top"><a href="#page-header"><img alt="top" src="../images/up.gif" /></a></div> +<div class="section"> +<h2><a name="external" id="external">Other Resources</a></h2> + <ul> + <li><a href="http://ci.apache.org/projects/httpd/trunk/doxygen/">Autogenerated Apache HTTP Server (trunk) code documentation</a> (the link is built by + this <a href="https://ci.apache.org/builders/httpd-doxygen-nightly">job</a>). + </li> + + <li>Developer articles at <a href="http://www.apachetutor.org/">apachetutor</a> include: + <ul> + <li><a href="http://www.apachetutor.org/dev/request">Request Processing</a></li> + <li><a href="http://www.apachetutor.org/dev/config">Configuration for Modules</a></li> + <li><a href="http://www.apachetutor.org/dev/pools">Resource Management</a></li> + <li><a href="http://www.apachetutor.org/dev/reslist">Connection Pooling</a></li> + <li><a href="http://www.apachetutor.org/dev/brigades">Introduction to Buckets and Brigades</a></li> + </ul></li> + <li><a href="https://bz.apache.org/bugzilla/enter_bug.cgi?product=Apache%20httpd-2">Report a bug or feature request</a></li> + </ul> +</div></div> +<div class="bottomlang"> +<p><span>Available Languages: </span><a href="../en/developer/" title="English"> en </a> | +<a href="../zh-cn/developer/" hreflang="zh-cn" rel="alternate" title="Simplified Chinese"> zh-cn </a></p> +</div><div id="footer"> +<p class="apache">Copyright 2023 The Apache Software Foundation.<br />Licensed under the <a href="http://www.apache.org/licenses/LICENSE-2.0">Apache License, Version 2.0</a>.</p> +<p class="menu"><a href="../mod/">Modules</a> | <a href="../mod/directives.html">Directives</a> | <a href="http://wiki.apache.org/httpd/FAQ">FAQ</a> | <a href="../glossary.html">Glossary</a> | <a href="../sitemap.html">Sitemap</a></p></div><script type="text/javascript"><!--//--><![CDATA[//><!-- +if (typeof(prettyPrint) !== 'undefined') { + prettyPrint(); +} +//--><!]]></script> +</body></html>
\ No newline at end of file diff --git a/docs/manual/developer/index.html.zh-cn.utf8 b/docs/manual/developer/index.html.zh-cn.utf8 new file mode 100644 index 0000000..b4e21ae --- /dev/null +++ b/docs/manual/developer/index.html.zh-cn.utf8 @@ -0,0 +1,88 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd"> +<html xmlns="http://www.w3.org/1999/xhtml" lang="zh-cn" xml:lang="zh-cn"><head> +<meta content="text/html; charset=UTF-8" http-equiv="Content-Type" /> +<!-- + XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX + This file is generated from xml source: DO NOT EDIT + XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX + --> +<title>Apache 2.0 开发者文档 - Apache HTTP 服务器 版本 2.4</title> +<link href="../style/css/manual.css" rel="stylesheet" media="all" type="text/css" title="Main stylesheet" /> +<link href="../style/css/manual-loose-100pc.css" rel="alternate stylesheet" media="all" type="text/css" title="No Sidebar - Default font size" /> +<link href="../style/css/manual-print.css" rel="stylesheet" media="print" type="text/css" /><link rel="stylesheet" type="text/css" href="../style/css/prettify.css" /> +<script src="../style/scripts/prettify.min.js" type="text/javascript"> +</script> + +<link href="../images/favicon.ico" rel="shortcut icon" /></head> +<body id="manual-page"><div id="page-header"> +<p class="menu"><a href="../mod/">模块</a> | <a href="../mod/directives.html">指令</a> | <a href="http://wiki.apache.org/httpd/FAQ">常见问题</a> | <a href="../glossary.html">术语</a> | <a href="../sitemap.html">网站导航</a></p> +<p class="apache">Apache HTTP 服务器版本 2.4</p> +<img alt="" src="../images/feather.png" /></div> +<div class="up"><a href="../"><img title="<-" alt="<-" src="../images/left.gif" /></a></div> +<div id="path"> +<a href="http://www.apache.org/">Apache</a> > <a href="http://httpd.apache.org/">HTTP 服务器</a> > <a href="http://httpd.apache.org/docs/">文档</a> > <a href="../">版本 2.4</a></div><div id="page-content"><div id="preamble"><h1>Apache 2.0 开发者文档</h1> +<div class="toplang"> +<p><span>可用语言: </span><a href="../en/developer/" hreflang="en" rel="alternate" title="English"> en </a> | +<a href="../zh-cn/developer/" title="Simplified Chinese"> zh-cn </a></p> +</div> +<div class="outofdate">此翻译可能过期。要了解最近的更改,请阅读英文版。</div> + + <p>开发者页面的许多文档都来自于 Apache 1.3。当更新到 Apache 2 + 时,它们可能位于不同的阶段。请耐心等待,或者直接向 + <a href="http://httpd.apache.org/lists.html#http-dev">dev@httpd.apache.org</a> 邮件列表报告开发者页面的差异或错误。</p> +</div> +<div id="quickview"><a href="https://www.apache.org/foundation/contributing.html" class="badge"><img src="https://www.apache.org/images/SupportApache-small.png" alt="Support Apache!" /></a><ul id="toc"><li><img alt="" src="../images/down.gif" /> <a href="#topics">主题</a></li> +<li><img alt="" src="../images/down.gif" /> <a href="#external">外部资源</a></li> +</ul></div> +<div class="top"><a href="#page-header"><img alt="top" src="../images/up.gif" /></a></div> +<div class="section"> +<h2><a name="topics" id="topics">主题</a></h2> + <ul> + <li><a href="API.html">Apache 1.3 API 说明</a></li> + <li><a href="new_api_2_4.html">在 Apache 2.3/2.4 中的 API 改变</a></li> + <li><a href="hooks.html">Apache 2.x 钩子函数</a></li> + <li><a href="request.html">Apache 2.x 中的请求处理</a></li> + <li><a href="filters.html">Apache 2.x 中的过滤器</a></li> + <li><a href="output-filters.html">Apache 2.x 中的输出过滤器指南</a></li> + <li><a href="modules.html">将模块从 Apache 1.3 移植到 Apache 2.x</a></li> + <li><a href="debugging.html">在 APR 中调试内存分配</a></li> + <li><a href="documenting.html">Apache 2.x 文档</a></li> + <li><a href="thread_safety.html">Apache 2.x 的线程安全问题</a></li> + </ul> +</div><div class="top"><a href="#page-header"><img alt="top" src="../images/up.gif" /></a></div> +<div class="section"> +<h2><a name="external" id="external">外部资源</a></h2> + <ul> + <li><a href="http://ci.apache.org/projects/httpd/trunk/doxygen/">自动生成的 Apache HTTP 服务器 (trunk) 代码文档</a></li> + + <li>Kevin O'Donnell 的模块开发教程 + <ul> + <li><a href="http://threebit.net/tutorials/apache2_modules/tut1/tutorial1.html">集成模块到 Apache 构建系统</a></li> + + <li><a href="http://threebit.net/tutorials/apache2_modules/tut2/tutorial2.html">处理配置指令</a></li> + </ul></li> + + <li><a href="http://www.onlamp.com/pub/ct/38">Ryan Bloom 对 Apache 模块开发的说明</a></li> + + <li>位于 <a href="http://www.apachetutor.org/">apachetutor</a> 的开发者文章: + <ul> + <li><a href="http://www.apachetutor.org/dev/request">Apache 中的请求处理</a></li> + <li><a href="http://www.apachetutor.org/dev/config">模块的配置</a></li> + <li><a href="http://www.apachetutor.org/dev/pools">Apache 中的资源管理</a></li> + <li><a href="http://www.apachetutor.org/dev/reslist">Apache 中的连接池</a></li> + <li><a href="http://www.apachetutor.org/dev/brigades">桶与队列简介</a></li> + </ul></li> + </ul> +</div></div> +<div class="bottomlang"> +<p><span>可用语言: </span><a href="../en/developer/" hreflang="en" rel="alternate" title="English"> en </a> | +<a href="../zh-cn/developer/" title="Simplified Chinese"> zh-cn </a></p> +</div><div id="footer"> +<p class="apache">Copyright 2023 The Apache Software Foundation.<br />基于 <a href="http://www.apache.org/licenses/LICENSE-2.0">Apache License, Version 2.0</a> 许可证.</p> +<p class="menu"><a href="../mod/">模块</a> | <a href="../mod/directives.html">指令</a> | <a href="http://wiki.apache.org/httpd/FAQ">常见问题</a> | <a href="../glossary.html">术语</a> | <a href="../sitemap.html">网站导航</a></p></div><script type="text/javascript"><!--//--><![CDATA[//><!-- +if (typeof(prettyPrint) !== 'undefined') { + prettyPrint(); +} +//--><!]]></script> +</body></html>
\ No newline at end of file diff --git a/docs/manual/developer/modguide.html b/docs/manual/developer/modguide.html new file mode 100644 index 0000000..3e5c834 --- /dev/null +++ b/docs/manual/developer/modguide.html @@ -0,0 +1,5 @@ +# GENERATED FROM XML -- DO NOT EDIT + +URI: modguide.html.en +Content-Language: en +Content-type: text/html; charset=UTF-8 diff --git a/docs/manual/developer/modguide.html.en b/docs/manual/developer/modguide.html.en new file mode 100644 index 0000000..3ac127e --- /dev/null +++ b/docs/manual/developer/modguide.html.en @@ -0,0 +1,1739 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd"> +<html xmlns="http://www.w3.org/1999/xhtml" lang="en" xml:lang="en"><head> +<meta content="text/html; charset=UTF-8" http-equiv="Content-Type" /> +<!-- + XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX + This file is generated from xml source: DO NOT EDIT + XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX + --> +<title>Developing modules for the Apache HTTP Server 2.4 - Apache HTTP Server Version 2.4</title> +<link href="../style/css/manual.css" rel="stylesheet" media="all" type="text/css" title="Main stylesheet" /> +<link href="../style/css/manual-loose-100pc.css" rel="alternate stylesheet" media="all" type="text/css" title="No Sidebar - Default font size" /> +<link href="../style/css/manual-print.css" rel="stylesheet" media="print" type="text/css" /><link rel="stylesheet" type="text/css" href="../style/css/prettify.css" /> +<script src="../style/scripts/prettify.min.js" type="text/javascript"> +</script> + +<link href="../images/favicon.ico" rel="shortcut icon" /></head> +<body id="manual-page"><div id="page-header"> +<p class="menu"><a href="../mod/">Modules</a> | <a href="../mod/directives.html">Directives</a> | <a href="http://wiki.apache.org/httpd/FAQ">FAQ</a> | <a href="../glossary.html">Glossary</a> | <a href="../sitemap.html">Sitemap</a></p> +<p class="apache">Apache HTTP Server Version 2.4</p> +<img alt="" src="../images/feather.png" /></div> +<div class="up"><a href="./"><img title="<-" alt="<-" src="../images/left.gif" /></a></div> +<div id="path"> +<a href="http://www.apache.org/">Apache</a> > <a href="http://httpd.apache.org/">HTTP Server</a> > <a href="http://httpd.apache.org/docs/">Documentation</a> > <a href="../">Version 2.4</a> > <a href="./">Developer</a></div><div id="page-content"><div id="preamble"><h1>Developing modules for the Apache HTTP Server 2.4</h1> +<div class="toplang"> +<p><span>Available Languages: </span><a href="../en/developer/modguide.html" title="English"> en </a></p> +</div> + +<p>This document explains how you can develop modules for the Apache HTTP +Server 2.4</p> +</div> +<div id="quickview"><a href="https://www.apache.org/foundation/contributing.html" class="badge"><img src="https://www.apache.org/images/SupportApache-small.png" alt="Support Apache!" /></a><ul id="toc"><li><img alt="" src="../images/down.gif" /> <a href="#introduction">Introduction</a></li> +<li><img alt="" src="../images/down.gif" /> <a href="#basics">Defining a module</a></li> +<li><img alt="" src="../images/down.gif" /> <a href="#hooking">Getting started: Hooking into the server</a></li> +<li><img alt="" src="../images/down.gif" /> <a href="#handling">Building a handler</a></li> +<li><img alt="" src="../images/down.gif" /> <a href="#configuration">Adding configuration options</a></li> +<li><img alt="" src="../images/down.gif" /> <a href="#context">Context aware configurations</a></li> +<li><img alt="" src="../images/down.gif" /> <a href="#summary">Summing up</a></li> +<li><img alt="" src="../images/down.gif" /> <a href="#snippets">Some useful snippets of code</a></li> +</ul><h3>See also</h3><ul class="seealso"><li><a href="request.html">Request Processing in Apache 2.4</a></li><li><a href="hooks.html">Apache 2.x Hook Functions</a></li><li><a href="#comments_section">Comments</a></li></ul></div> +<div class="top"><a href="#page-header"><img alt="top" src="../images/up.gif" /></a></div> +<div class="section"> +<h2><a name="introduction" id="introduction">Introduction</a></h2> +<h3><a name="what" id="what">What we will be discussing in this document</a></h3> +<p> +This document will discuss how you can create modules for the Apache +HTTP Server 2.4, by exploring an example module called +<code>mod_example</code>. In the first part of this document, the purpose +of this module will be to calculate and print out various digest values for +existing files on your web server, whenever we access the URL <code> +http://hostname/filename.sum</code>. For instance, if we want to know the +MD5 digest value of the file located at <code> +http://www.example.com/index.html</code>, we would visit <code> +http://www.example.com/index.html.sum</code>. +</p> + +<p> +In the second part of this document, which deals with configuration +directive and context awareness, we will be looking at a module that simply +writes out its own configuration to the client. +</p> + + +<h3><a name="prerequisites" id="prerequisites">Prerequisites</a></h3> +<p> +First and foremost, you are expected to have a basic knowledge of how the C +programming language works. In most cases, we will try to be as pedagogical +as possible and link to documents describing the functions used in the +examples, but there are also many cases where it is necessary to either +just assume that "it works" or do some digging yourself into what the hows +and whys of various function calls. +</p> +<p> +Lastly, you will need to have a basic understanding of how modules are +loaded and configured in the Apache HTTP Server, as well as how to get the headers for +Apache if you do not have them already, as these are needed for compiling +new modules. +</p> + +<h3><a name="compiling" id="compiling">Compiling your module</a></h3> +<p> +To compile the source code we are building in this document, we will be +using <a href="../programs/apxs.html">APXS</a>. Assuming your source file +is called mod_example.c, compiling, installing and activating the module is +as simple as: +</p> +<div class="example"><pre>apxs -i -a -c mod_example.c</pre></div> + + +</div><div class="top"><a href="#page-header"><img alt="top" src="../images/up.gif" /></a></div> +<div class="section"> +<h2><a name="basics" id="basics">Defining a module</a></h2> +<p> +<img src="../images/build_a_mod_3.png" alt="Module name tags" /><br /> +Every module starts with the same declaration, or name tag if you will, +that defines a module as <em>a separate entity within Apache</em>:</p> + + + +<pre class="prettyprint lang-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 */ + create_svr_conf, /* Per-server configuration handler */ + merge_svr_conf, /* Merge handler for per-server configurations */ + directives, /* Any directives we may have for httpd */ + register_hooks /* Our hook registering function */ +};</pre> + + + +<p> +This bit of code lets the server know that we have now registered a new module +in the system, and that its name is <code>example_module</code>. The name +of the module is used primarily for two things:<br /> +</p> +<ul> +<li>Letting the server know how to load the module using the LoadModule</li> +<li>Setting up a namespace for the module to use in configurations</li> +</ul> +<p> +For now, we're only concerned with the first purpose of the module name, +which comes into play when we need to load the module: +</p> +<pre class="prettyprint lang-config">LoadModule example_module modules/mod_example.so</pre> + +<p> +In essence, this tells the server to open up <code>mod_example.so</code> and look for a module +called <code>example_module</code>. +</p> +<p> +Within this name tag of ours is also a bunch of references to how we would +like to handle things: Which directives do we respond to in a configuration +file or .htaccess, how do we operate within specific contexts, and what +handlers are we interested in registering with the Apache HTTP service. We'll +return to all these elements later in this document. +</p> +</div><div class="top"><a href="#page-header"><img alt="top" src="../images/up.gif" /></a></div> +<div class="section"> +<h2><a name="hooking" id="hooking">Getting started: Hooking into the server</a></h2> +<h3><a name="hook_intro" id="hook_intro">An introduction to hooks</a></h3> +<p> +When handling requests in Apache HTTP Server 2.4, the first thing you will need to do is +create a hook into the request handling process. A hook is essentially a +message telling the server that you are willing to either serve or at least +take a glance at certain requests given by clients. All handlers, whether +it's mod_rewrite, mod_authn_*, mod_proxy and so on, are hooked into +specific parts of the request process. As you are probably aware, modules +serve different purposes; Some are authentication/authorization handlers, +others are file or script handlers while some third modules rewrite URIs or +proxies content. Furthermore, in the end, it is up to the user of the server +how and when each module will come into place. Thus, the server itself does not +presume to know which module is responsible for handling a specific +request, and will ask each module whether they have an interest in a given +request or not. It is then up to each module to either gently decline +serving a request, accept serving it or flat out deny the request from +being served, as authentication/authorization modules do: <br /> +<img src="../images/build_a_mod_2.png" alt="Hook handling in httpd" /><br /> +To make it a bit easier for handlers such as our mod_example to know +whether the client is requesting content we should handle or not, the server +has directives for hinting to modules whether their assistance is needed or +not. Two of these are <code class="directive"><a href="../mod/mod_mime.html#addhandler">AddHandler</a></code> +and <code class="directive"><a href="../mod/core.html#sethandler">SetHandler</a></code>. Let's take a look at +an example using <code class="directive"><a href="../mod/mod_mime.html#addhandler">AddHandler</a></code>. In +our example case, we want every request ending with .sum to be served by +<code>mod_example</code>, so we'll add a configuration directive that tells +the server to do just that: +</p> +<pre class="prettyprint lang-config">AddHandler example-handler .sum</pre> + +<p> +What this tells the server is the following: <em>Whenever we receive a request +for a URI ending in .sum, we are to let all modules know that we are +looking for whoever goes by the name of "example-handler" </em>. +Thus, when a request is being served that ends in .sum, the server will let all +modules know, that this request should be served by "example-handler +". As you will see later, when we start building mod_example, we will +check for this handler tag relayed by <code>AddHandler</code> and reply to +the server based on the value of this tag. +</p> + +<h3><a name="hook_declaration" id="hook_declaration">Hooking into httpd</a></h3> +<p> +To begin with, we only want to create a simple handler that replies to the +client browser when a specific URL is requested, so we won't bother setting +up configuration handlers and directives just yet. Our initial module +definition will look like this:</p> + + + +<pre class="prettyprint lang-c">module AP_MODULE_DECLARE_DATA example_module = +{ + STANDARD20_MODULE_STUFF, + NULL, + NULL, + NULL, + NULL, + NULL, + register_hooks /* Our hook registering function */ +};</pre> + + + + +<p>This lets the server know that we are not interested in anything fancy, we +just want to hook onto the requests and possibly handle some of them. </p> + +<p> The reference in our example declaration, <code>register_hooks</code> +is the name of a function we will create to manage how we hook onto the +request process. In this example module, the function has just one purpose; +To create a simple hook that gets called after all the rewrites, access +control etc has been handled. Thus, we will let the server know that we want +to hook into its process as one of the last modules: +</p> + + +<pre class="prettyprint lang-c">static void register_hooks(apr_pool_t *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); +}</pre> + + + +<p> +The <code>example_handler</code> reference is the function that will handle +the request. We will discuss how to create a handler in the next chapter. +</p> + +<h3><a name="hook_others" id="hook_others">Other useful hooks</a></h3> +<p> +Hooking into the request handling phase is but one of many hooks that you +can create. Some other ways of hooking are: +</p> +<ul> +<li><code>ap_hook_child_init</code>: Place a hook that executes when a child process is spawned (commonly used for initializing modules after the server has forked)</li> +<li><code>ap_hook_pre_config</code>: Place a hook that executes before any configuration data has been read (very early hook)</li> +<li><code>ap_hook_post_config</code>: Place a hook that executes after configuration has been parsed, but before the server has forked</li> +<li><code>ap_hook_pre_translate_name</code>: Place a hook that executes when a URI needs to be translated into a filename on the server, before decoding</li> +<li><code>ap_hook_translate_name</code>: Place a hook that executes when a URI needs to be translated into a filename on the server (think <code>mod_rewrite</code>)</li> +<li><code>ap_hook_quick_handler</code>: Similar to <code>ap_hook_handler</code>, except it is run before any other request hooks (translation, auth, fixups etc)</li> +<li><code>ap_hook_log_transaction</code>: Place a hook that executes when the server is about to add a log entry of the current request</li> +</ul> + + +</div><div class="top"><a href="#page-header"><img alt="top" src="../images/up.gif" /></a></div> +<div class="section"> +<h2><a name="handling" id="handling">Building a handler</a></h2> +<p> +A handler is essentially a function that receives a callback when a request +to the server is made. It is passed a record of the current request (how it was +made, which headers and requests were passed along, who's giving the +request and so on), and is put in charge of either telling the server that it's +not interested in the request or handle the request with the tools provided. +</p> +<h3><a name="simple_handler" id="simple_handler">A simple "Hello, world!" +handler</a></h3> +<p>Let's start off by making a very simple request handler +that does the following: +</p> +<ol> +<li>Check that this is a request that should be served by "example-handler"</li> +<li>Set the content type of our output to <code>text/html</code></li> +<li>Write "Hello, world!" back to the client browser</li> +<li>Let the server know that we took care of this request and everything went fine</li> +</ol> +<p> +In C code, our example handler will now look like this: +</p> + + +<pre class="prettyprint lang-c">static int example_handler(request_rec *r) +{ + /* First off, we need to check if this is a call for the "example-handler" handler. + * If it is, we accept it and do our things, if not, we simply return DECLINED, + * and the server will try somewhere else. + */ + if (!r->handler || strcmp(r->handler, "example-handler")) return (DECLINED); + + /* Now that we are handling this request, we'll write out "Hello, world!" to the client. + * To do so, we must first set the appropriate content type, followed by our output. + */ + ap_set_content_type(r, "text/html"); + ap_rprintf(r, "Hello, world!"); + + /* Lastly, we must tell the server that we took care of this request and everything went fine. + * We do so by simply returning the value OK to the server. + */ + return OK; +}</pre> + + + +<p> +Now, we put all we have learned together and end up with a program that +looks like +<a href="http://people.apache.org/~humbedooh/mods/examples/mod_example_1.c">mod_example_1.c</a> +. The functions used in this example will be explained later in the section +<a href="#functions">"Some useful functions you should know"</a>. +</p> + +<h3><a name="request_rec" id="request_rec">The request_rec structure</a></h3> +<p>The most essential part of any request is the <em>request record +</em>. In a call to a handler function, this is represented by the <code> +request_rec* </code> structure passed along with every call that is made. +This struct, typically just referred to as <code>r</code> in modules, +contains all the information you need for your module to fully process any +HTTP request and respond accordingly.</p> <p>Some key elements of the <code> +request_rec </code> structure are: +</p> +<ul> +<li><code>r->handler (char*):</code> Contains the name of the handler the server is currently asking to do the handling of this request</li> +<li><code>r->method (char*):</code> Contains the HTTP method being used, f.x. GET or POST</li> +<li><code>r->filename (char*):</code> Contains the translated filename the client is requesting</li> +<li><code>r->args (char*):</code> Contains the query string of the request, if any</li> +<li><code>r->headers_in (apr_table_t*):</code> Contains all the headers sent by the client</li> +<li><code>r->connection (conn_rec*):</code> A record containing information about the current connection</li> +<li><code>r->user (char*):</code> If the URI requires authentication, this is set to the username provided</li> +<li><code>r->useragent_ip (char*):</code> The IP address of the client connecting to us</li> +<li><code>r->pool (apr_pool_t*)</code>: The memory pool of this request. We'll discuss this in the +"<a href="#memory">Memory management</a>" chapter.</li> +</ul> +<p> +A complete list of all the values contained within the <code>request_rec</code> structure can be found in +the <a href="http://svn.apache.org/repos/asf/httpd/httpd/trunk/include/httpd.h"><code>httpd.h</code></a> header +file or at <a href="http://ci.apache.org/projects/httpd/trunk/doxygen/structrequest__rec.html">http://ci.apache.org/projects/httpd/trunk/doxygen/structrequest__rec.html</a>. +</p> + + +<p> +Let's try out some of these variables in another example handler:<br /> +</p> + + +<pre class="prettyprint lang-c">static int example_handler(request_rec *r) +{ + /* Set the appropriate content type */ + ap_set_content_type(r, "text/html"); + + /* Print out the IP address of the client connecting to us: */ + ap_rprintf(r, "<h2>Hello, %s!</h2>", r->useragent_ip); + + /* If we were reached through a GET or a POST request, be happy, else sad. */ + if ( !strcmp(r->method, "POST") || !strcmp(r->method, "GET") ) { + ap_rputs("You used a GET or a POST method, that makes us happy!<br/>", r); + } + else { + ap_rputs("You did not use POST or GET, that makes us sad :(<br/>", r); + } + + /* Lastly, if there was a query string, let's print that too! */ + if (r->args) { + ap_rprintf(r, "Your query string was: %s", r->args); + } + return OK; +}</pre> + + + + + +<h3><a name="return_value" id="return_value">Return values</a></h3> +<p> +Apache relies on return values from handlers to signify whether a request +was handled or not, and if so, whether the request went well or not. If a +module is not interested in handling a specific request, it should always +return the value <code>DECLINED</code>. If it is handling a request, it +should either return the generic value <code>OK</code>, or a specific HTTP +status code, for example: +</p> + + +<pre class="prettyprint lang-c">static int example_handler(request_rec *r) +{ + /* Return 404: Not found */ + return HTTP_NOT_FOUND; +}</pre> + + + +<p> +Returning <code>OK</code> or a HTTP status code does not necessarily mean +that the request will end. The server may still have other handlers that are +interested in this request, for instance the logging modules which, upon a +successful request, will write down a summary of what was requested and how +it went. To do a full stop and prevent any further processing after your +module is done, you can return the value <code>DONE</code> to let the server +know that it should cease all activity on this request and carry on with +the next, without informing other handlers. +<br /> +<strong>General response codes:</strong> +</p> +<ul> +<li><code>DECLINED</code>: We are not handling this request</li> +<li><code>OK</code>: We handled this request and it went well</li> +<li><code>DONE</code>: We handled this request and the server should just close this thread without further processing</li> +</ul> +<p> +<strong>HTTP specific return codes (excerpt):</strong> +</p> +<ul> +<li><code>HTTP_OK (200)</code>: Request was okay</li> +<li><code>HTTP_MOVED_PERMANENTLY (301)</code>: The resource has moved to a new URL</li> +<li><code>HTTP_UNAUTHORIZED (401)</code>: Client is not authorized to visit this page</li> +<li><code>HTTP_FORBIDDEN (403)</code>: Permission denied</li> +<li><code>HTTP_NOT_FOUND (404)</code>: File not found</li> +<li><code>HTTP_INTERNAL_SERVER_ERROR (500)</code>: Internal server error (self explanatory)</li> +</ul> + + +<h3><a name="functions" id="functions">Some useful functions you should know</a></h3> + +<ul> +<li> + <code>ap_rputs(const char *string, request_rec *r)</code>: <br /> + Sends a string of text to the client. This is a shorthand version of <a href="http://ci.apache.org/projects/httpd/trunk/doxygen/group__APACHE__CORE__PROTO.html#gac827cd0537d2b6213a7c06d7c26cc36e"> + ap_rwrite</a>. + + + +<pre class="prettyprint lang-c">ap_rputs("Hello, world!", r);</pre> + + + + +</li> +<li> + <code> + <a href="http://ci.apache.org/projects/httpd/trunk/doxygen/group__APACHE__CORE__PROTO.html#ga5e91eb6ca777c9a427b2e82bf1eeb81d">ap_rprintf</a></code>: <br /> + This function works just like <code>printf</code>, except it sends the result to the client. + + + +<pre class="prettyprint lang-c">ap_rprintf(r, "Hello, %s!", r->useragent_ip);</pre> + + + +</li> +<li> + <code> + <a href="http://ci.apache.org/projects/httpd/trunk/doxygen/group__APACHE__CORE__PROTO.html#gaa2f8412c400197338ec509f4a45e4579">ap_set_content_type</a>(request_rec *r, const char *type)</code>: <br /> + Sets the content type of the output you are sending. + + + +<pre class="prettyprint lang-c">ap_set_content_type(r, "text/plain"); /* force a raw text output */</pre> + + + +</li> + + +</ul> + + +<h3><a name="memory" id="memory">Memory management</a></h3> +<p> +Managing your resources in Apache HTTP Server 2.4 is quite easy, thanks to the memory pool +system. In essence, each server, connection and request have their own +memory pool that gets cleaned up when its scope ends, e.g. when a request +is done or when a server process shuts down. All your module needs to do is +latch onto this memory pool, and you won't have to worry about having to +clean up after yourself - pretty neat, huh? +</p> + +<p> +In our module, we will primarily be allocating memory for each request, so +it's appropriate to use the <code>r->pool</code> +reference when creating new objects. A few of the functions for allocating +memory within a pool are: +</p> +<ul> +<li><code>void* <a href="http://apr.apache.org/docs/apr/1.4/group__apr__pools.html#ga85f1e193c31d109affda72f9a92c6915">apr_palloc</a>( +apr_pool_t *p, apr_size_t size)</code>: Allocates <code>size</code> number of bytes in the pool for you</li> +<li><code>void* <a href="http://apr.apache.org/docs/apr/1.4/group__apr__pools.html#gaf61c098ad258069d64cdf8c0a9369f9e">apr_pcalloc</a>( +apr_pool_t *p, apr_size_t size)</code>: Allocates <code>size</code> number of bytes in the pool for you and sets all bytes to 0</li> +<li><code>char* <a href="http://apr.apache.org/docs/apr/1.4/group__apr__strings.html#gabc79e99ff19abbd7cfd18308c5f85d47">apr_pstrdup</a>( +apr_pool_t *p, const char *s)</code>: Creates a duplicate of the string <code>s</code>. This is useful for copying constant values so you can edit them</li> +<li><code>char* <a href="http://apr.apache.org/docs/apr/1.4/group__apr__strings.html#ga3eca76b8d293c5c3f8021e45eda813d8">apr_psprintf</a>( +apr_pool_t *p, const char *fmt, ...)</code>: Similar to <code>sprintf</code>, except the server supplies you with an appropriately allocated target variable</li> +</ul> + +<p>Let's put these functions into an example handler:</p> + + + +<pre class="prettyprint lang-c">static int example_handler(request_rec *r) +{ + const char *original = "You can't edit this!"; + char *copy; + int *integers; + + /* Allocate space for 10 integer values and set them all to zero. */ + integers = apr_pcalloc(r->pool, sizeof(int)*10); + + /* Create a copy of the 'original' variable that we can edit. */ + copy = apr_pstrdup(r->pool, original); + return OK; +}</pre> + + + +<p> +This is all well and good for our module, which won't need any +pre-initialized variables or structures. However, if we wanted to +initialize something early on, before the requests come rolling in, we +could simply add a call to a function in our <code>register_hooks</code> +function to sort it out: +</p> + + +<pre class="prettyprint lang-c">static 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); +}</pre> + + + +<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> + + +<h3><a name="parsing" id="parsing">Parsing request data</a></h3> +<p> +In our example module, we would like to add a feature, that checks which +type of digest, MD5 or SHA1 the client would like to see. This could be +solved by adding a query string to the request. A query string is typically +comprised of several keys and values put together in a string, for instance +<code>valueA=yes&valueB=no&valueC=maybe</code>. It is up to the +module itself to parse these and get the data it requires. In our example, +we'll be looking for a key called <code>digest</code>, and if set to <code> +md5</code>, we'll produce an MD5 digest, otherwise we'll produce a SHA1 +digest. +</p> +<p> +Since the introduction of Apache 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> + + + +<pre class="prettyprint lang-c"> +<a href="http://ci.apache.org/projects/httpd/trunk/doxygen/group__apr__tables.html#gad7ea82d6608a4a633fc3775694ab71e4">apr_table_t</a> *GET; <em> +</em><a href="http://ci.apache.org/projects/httpd/trunk/doxygen/structapr__array__header__t.html">apr_array_header_t</a>*POST; +<em> +</em> +<a href="http://ci.apache.org/projects/httpd/trunk/doxygen/group__APACHE__CORE__SCRIPT.html#gaed25877b529623a4d8f99f819ba1b7bd"> +ap_args_to_table</a>(r, &GET); <em> +</em><a href="http://ci.apache.org/projects/httpd/trunk/doxygen/group__APACHE__CORE__DAEMON.html#ga9d426b6382b49754d4f87c55f65af202"> +ap_parse_form_data</a>(r, NULL, &POST, -1, 8192);</pre> + + + +<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> + + + +<pre class="prettyprint lang-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";</pre> + + + +<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> + + +<h3><a name="advanced_handler" id="advanced_handler">Making an advanced handler</a></h3> +<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> + + + +<pre class="prettyprint lang-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 "example-handler" handler is being called. */ + if (!r->handler || strcmp(r->handler, "example-handler")) return (DECLINED); + + /* Figure out which file is being requested by removing the .sum from it */ + filename = apr_pstrdup(r->pool, r->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(&finfo, filename, APR_FINFO_MIN, r->pool); + if (rc == APR_SUCCESS) { + exists = + ( + (finfo.filetype != APR_NOFILE) + && !(finfo.filetype & 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, &GET); + ap_parse_form_data(r, NULL, &POST, -1, 8192); + + /* Set the appropriate content type */ + ap_set_content_type(r, "text/html"); + + /* Print a title and some general information */ + ap_rprintf(r, "<h2>Information on %s:</h2>", filename); + ap_rprintf(r, "<b>Size:</b> %u bytes<br/>", finfo.size); + + /* Get the digest type the client wants to see */ + digestType = apr_table_get(GET, "digest"); + if (!digestType) digestType = "MD5"; + + + rc = apr_file_open(&file, filename, APR_READ, APR_OS_DEFAULT, r->pool); + if (rc == APR_SUCCESS) { + + /* Are we trying to calculate the MD5 or the SHA1 digest? */ + if (!strcasecmp(digestType, "md5")) { + /* Calculate the MD5 sum of the file */ + union { + char chr[16]; + uint32_t num[4]; + } digest; + apr_md5_ctx_t md5; + apr_md5_init(&md5); + readBytes = 256; + while ( apr_file_read(file, buffer, &readBytes) == APR_SUCCESS ) { + apr_md5_update(&md5, buffer, readBytes); + } + apr_md5_final(digest.chr, &md5); + + /* Print out the MD5 digest */ + ap_rputs("<b>MD5: </b><code>", r); + for (n = 0; n < APR_MD5_DIGESTSIZE/4; n++) { + ap_rprintf(r, "%08x", digest.num[n]); + } + ap_rputs("</code>", r); + /* Print a link to the SHA1 version */ + ap_rputs("<br/><a href='?digest=sha1'>View the SHA1 hash instead</a>", 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(&sha1); + readBytes = 256; + while ( apr_file_read(file, buffer, &readBytes) == APR_SUCCESS ) { + apr_sha1_update(&sha1, buffer, readBytes); + } + apr_sha1_final(digest.chr, &sha1); + + /* Print out the SHA1 digest */ + ap_rputs("<b>SHA1: </b><code>", r); + for (n = 0; n < APR_SHA1_DIGESTSIZE/4; n++) { + ap_rprintf(r, "%08x", digest.num[n]); + } + ap_rputs("</code>", r); + + /* Print a link to the MD5 version */ + ap_rputs("<br/><a href='?digest=md5'>View the MD5 hash instead</a>", r); + } + apr_file_close(file); + + } + /* Let the server know that we responded to this request. */ + return OK; +}</pre> + + + +<p> +This version in its entirety can be found here: +<a href="http://people.apache.org/~humbedooh/mods/examples/mod_example_2.c">mod_example_2.c</a>. +</p> + + +</div><div class="top"><a href="#page-header"><img alt="top" src="../images/up.gif" /></a></div> +<div class="section"> +<h2><a name="configuration" id="configuration">Adding configuration options</a></h2> +<p> +In this next segment of this document, we will turn our eyes away from the +digest module and create a new example module, whose only function is to +write out its own configuration. The purpose of this is to examine how +the server works with configuration, and what happens when you start writing +advanced configurations +for your modules. +</p> +<h3><a name="config_intro" id="config_intro">An introduction to configuration +directives</a></h3> +<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> +<pre class="prettyprint lang-config">RewriteEngine On +RewriteCond "%{REQUEST_URI}" "^/foo/bar" +RewriteRule "^/foo/bar/(.*)$" "/foobar?page=$1"</pre> + +<p> +Each of these configuration directives are handled by a separate function, +that parses the parameters given and sets up a configuration accordingly. +</p> + +<h3><a name="config_simple" id="config_simple">Making an example configuration</a></h3> +<p>To begin with, we'll create a basic configuration in C-space:</p> + + + +<pre class="prettyprint lang-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;</pre> + + + +<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> + + +<pre class="prettyprint lang-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->handler || strcmp(r->handler, "example-handler")) return(DECLINED); + ap_set_content_type(r, "text/plain"); + ap_rprintf(r, "Enabled: %u\n", config.enabled); + ap_rprintf(r, "Path: %s\n", config.path); + ap_rprintf(r, "TypeOfAction: %x\n", config.typeOfAction); + return OK; +} + +static void register_hooks(apr_pool_t *pool) +{ + config.enabled = 1; + config.path = "/foo/bar"; + 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 */ +};</pre> + + + +<p> +So far so good. To access our new handler, we could add the following to +our configuration: +</p> +<pre class="prettyprint lang-config"><Location "/example"> + SetHandler example-handler +</Location></pre> + +<p> +When we visit, we'll see our current configuration being spit out by our +module. +</p> + + +<h3><a name="register_directive" id="register_directive">Registering directives with the server</a></h3> +<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> + + +<pre class="prettyprint lang-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 */ +};</pre> + + + +<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> + + +<pre class="prettyprint lang-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 } +};</pre> + + + +<p> +<img src="../images/build_a_mod_4.png" 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> + +<h3><a name="directive_handler" id="directive_handler">The directive handler function</a></h3> +<p> +Now that we have 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> + + +<pre class="prettyprint lang-c">/* Handler for the "exampleEnabled" 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; +}</pre> + + + + + +<h3><a name="directive_complete" id="directive_complete">Putting it all together</a></h3> +<p> +Now that we have our directives set up, and handlers configured for them, +we can assemble our module into one big file: +</p> + + +<pre class="prettyprint lang-c">/* mod_example_config_simple.c: */ +#include <stdio.h> +#include "apr_hash.h" +#include "ap_config.h" +#include "ap_provider.h" +#include "httpd.h" +#include "http_core.h" +#include "http_config.h" +#include "http_log.h" +#include "http_protocol.h" +#include "http_request.h" + +/* + ============================================================================== + 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 "exampleEnabled" 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; +} + +/* + ============================================================================== + The directive structure for our name tag: + ============================================================================== + */ +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 } +}; +/* + ============================================================================== + Our module handler: + ============================================================================== + */ +static int example_handler(request_rec *r) +{ + if(!r->handler || strcmp(r->handler, "example-handler")) return(DECLINED); + ap_set_content_type(r, "text/plain"); + ap_rprintf(r, "Enabled: %u\n", config.enabled); + ap_rprintf(r, "Path: %s\n", config.path); + ap_rprintf(r, "TypeOfAction: %x\n", 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 = "/foo/bar"; + 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 */ +};</pre> + + + + +<p> +In our httpd.conf file, we can now change the hard-coded configuration by +adding a few lines: +</p> +<pre class="prettyprint lang-config">ExampleEnabled On +ExamplePath "/usr/bin/foo" +ExampleAction file allow</pre> + +<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> + + + +</div><div class="top"><a href="#page-header"><img alt="top" src="../images/up.gif" /></a></div> +<div class="section"> +<h2><a name="context" id="context">Context aware configurations</a></h2> +<h3><a name="context_intro" id="context_intro">Introduction to context aware configurations</a></h3> +<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> +<pre class="prettyprint lang-config"><Directory "/var/www"> + RewriteCond "%{HTTP_HOST}" "^example.com$" + RewriteRule "(.*)" "http://www.example.com/$1" +</Directory> +<Directory "/var/www/sub"> + RewriteRule "^foobar$" "index.php?foobar=true" +</Directory></pre> + +<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> + + +<pre class="prettyprint lang-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->per_dir_config, &example_module);</pre> + + + +<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> + + +<h3><a name="context_base" id="context_base">Our basic configuration setup</a></h3> +<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> + +<pre class="prettyprint lang-c">typedef struct { + char context[256]; + char path[256]; + int typeOfAction; + int enabled; +} example_config;</pre> + + + +<p>Our handler for requests will also be modified, yet still very simple:</p> + + + +<pre class="prettyprint lang-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, &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; +}</pre> + + + + + +<h3><a name="context_which" id="context_which">Choosing a context</a></h3> +<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> + + + +<pre class="prettyprint lang-c">AP_INIT_TAKE1("exampleEnabled", example_set_enabled, NULL, RSRC_CONF, "Enable or disable mod_example"),</pre> + + + + +<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 <Directory> and <Location> blocks. For more +control over the placement of your directives, you can combine the following +restrictions together to form a specific rule: +</p> +<ul> +<li><code>RSRC_CONF</code>: Allow in .conf files (not .htaccess) outside <Directory> or <Location></li> +<li><code>ACCESS_CONF</code>: Allow in .conf files (not .htaccess) inside <Directory> or <Location></li> +<li><code>OR_OPTIONS</code>: Allow in .conf files and .htaccess when <code>AllowOverride Options</code> is set</li> +<li><code>OR_FILEINFO</code>: Allow in .conf files and .htaccess when <code>AllowOverride FileInfo</code> is set</li> +<li><code>OR_AUTHCFG</code>: Allow in .conf files and .htaccess when <code>AllowOverride AuthConfig</code> is set</li> +<li><code>OR_INDEXES</code>: Allow in .conf files and .htaccess when <code>AllowOverride Indexes</code> is set</li> +<li><code>OR_ALL</code>: Allow anywhere in .conf files and .htaccess</li> +</ul> + + +<h3><a name="context_pool" id="context_pool">Using the server to allocate configuration slots</a></h3> +<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> + + +<pre class="prettyprint lang-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 */ +};</pre> + + + + + + + +<h3><a name="context_new" id="context_new">Creating new context configurations</a></h3> +<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> + +<pre class="prettyprint lang-c">void *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, context); + cfg->enabled = 0; + cfg->path = "/foo/bar"; + cfg->typeOfAction = 0x11; + } + return cfg; +}</pre> + + + + + + +<h3><a name="context_merge" id="context_merge">Merging configurations</a></h3> +<p> +Our next step in creating a context aware configuration is merging +configurations. This part of the process particularly applies to scenarios +where you have a parent configuration and a child, such as the following: +</p> +<pre class="prettyprint lang-config"><Directory "/var/www"> + ExampleEnabled On + ExamplePath "/foo/bar" + ExampleAction file allow +</Directory> +<Directory "/var/www/subdir"> + ExampleAction file deny +</Directory></pre> + +<p> +In this example, it is natural to assume that the directory <code> +/var/www/subdir</code> should inherit the values set for the <code>/var/www +</code> directory, as we did not specify an <code>ExampleEnabled</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> + + + +<pre class="prettyprint lang-c">void *merge_dir_conf(apr_pool_t *pool, void *BASE, void *ADD) { + example_config *base = (example_config *) BASE ; /* This is what was set in the parent context */ + example_config *add = (example_config *) ADD ; /* This is what is set in the new context */ + example_config *conf = (example_config *) create_dir_conf(pool, "Merged configuration"); /* This will be the merged configuration */ + + /* Merge configurations */ + 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 ; +}</pre> + + + + + + +<h3><a name="context_example" id="context_example">Trying out our new context aware configurations</a></h3> +<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> +<pre class="prettyprint lang-config"><Location "/a"> + SetHandler example-handler + ExampleEnabled on + ExamplePath "/foo/bar" + ExampleAction file allow +</Location> + +<Location "/a/b"> + ExampleAction file deny + ExampleEnabled off +</Location> + +<Location "/a/b/c"> + ExampleAction db deny + ExamplePath "/foo/bar/baz" + ExampleEnabled on +</Location></pre> + +<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> + + +<pre class="prettyprint lang-c">/*$6 + +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ + * mod_example_config.c + +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ + */ + + +#include <stdio.h> +#include "apr_hash.h" +#include "ap_config.h" +#include "ap_provider.h" +#include "httpd.h" +#include "http_core.h" +#include "http_config.h" +#include "http_log.h" +#include "http_protocol.h" +#include "http_request.h" + +/*$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("exampleEnabled", example_set_enabled, NULL, ACCESS_CONF, "Enable or disable mod_example"), + AP_INIT_TAKE1("examplePath", example_set_path, NULL, ACCESS_CONF, "The path to whatever"), + AP_INIT_TAKE2("exampleAction", example_set_action, NULL, ACCESS_CONF, "Special action value!"), + { 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->handler || strcmp(r->handler, "example-handler")) return(DECLINED); + + /*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/ + example_config *config = (example_config *) ap_get_module_config(r->per_dir_config, &example_module); + /*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/ + + ap_set_content_type(r, "text/plain"); + ap_rprintf(r, "Enabled: %u\n", config->enabled); + ap_rprintf(r, "Path: %s\n", config->path); + ap_rprintf(r, "TypeOfAction: %x\n", config->typeOfAction); + ap_rprintf(r, "Context: %s\n", config->context); + return OK; +} + +/* + ======================================================================================================================= + Handler for the "exampleEnabled" 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, "on")) + conf->enabled = 1; + else + conf->enabled = 0; + } + + return NULL; +} + +/* + ======================================================================================================================= + Handler for the "examplePath" directive + ======================================================================================================================= + */ +const char *example_set_path(cmd_parms *cmd, void *cfg, const char *arg) +{ + /*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/ + example_config *conf = (example_config *) cfg; + /*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/ + + if(conf) + { + strcpy(conf->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) +{ + /*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/ + example_config *conf = (example_config *) cfg; + /*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/ + + if(conf) + { + { + if(!strcasecmp(arg1, "file")) + conf->typeOfAction = 0x01; + else + conf->typeOfAction = 0x02; + if(!strcasecmp(arg2, "deny")) + conf->typeOfAction += 0x10; + else + conf->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 : "Newly created configuration"; + + /*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/ + example_config *cfg = apr_pcalloc(pool, sizeof(example_config)); + /*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/ + + if(cfg) + { + { + /* Set some default values */ + strcpy(cfg->context, context); + cfg->enabled = 0; + memset(cfg->path, 0, 256); + cfg->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, "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; +}</pre> + + + + + + + +</div><div class="top"><a href="#page-header"><img alt="top" src="../images/up.gif" /></a></div> +<div class="section"> +<h2><a name="summary" id="summary">Summing up</a></h2> +<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> +</div><div class="top"><a href="#page-header"><img alt="top" src="../images/up.gif" /></a></div> +<div class="section"> +<h2><a name="snippets" id="snippets">Some useful snippets of code</a></h2> + +<h3><a name="get_post" id="get_post">Retrieve variables from POST form data</a></h3> + + + +<pre class="prettyprint lang-c">typedef struct { + const char *key; + const char *value; +} keyValuePair; + +keyValuePair *readPost(request_rec *r) { + apr_array_header_t *pairs = NULL; + apr_off_t len; + apr_size_t size; + int res; + int i = 0; + char *buffer; + keyValuePair *kvp; + + res = ap_parse_form_data(r, NULL, &pairs, -1, HUGE_STRING_LEN); + if (res != OK || !pairs) return NULL; /* Return NULL if we failed or if there are is no POST data */ + kvp = apr_pcalloc(r->pool, sizeof(keyValuePair) * (pairs->nelts + 1)); + while (pairs && !apr_is_empty_array(pairs)) { + ap_form_pair_t *pair = (ap_form_pair_t *) apr_array_pop(pairs); + apr_brigade_length(pair->value, 1, &len); + size = (apr_size_t) len; + buffer = apr_palloc(r->pool, size + 1); + apr_brigade_flatten(pair->value, buffer, &size); + buffer[len] = 0; + kvp[i].key = apr_pstrdup(r->pool, pair->name); + kvp[i].value = buffer; + i++; + } + return kvp; +} + +static int example_handler(request_rec *r) +{ + /*~~~~~~~~~~~~~~~~~~~~~~*/ + keyValuePair *formData; + /*~~~~~~~~~~~~~~~~~~~~~~*/ + + formData = readPost(r); + if (formData) { + int i; + for (i = 0; &formData[i]; i++) { + if (formData[i].key && formData[i].value) { + ap_rprintf(r, "%s = %s\n", formData[i].key, formData[i].value); + } else if (formData[i].key) { + ap_rprintf(r, "%s\n", formData[i].key); + } else if (formData[i].value) { + ap_rprintf(r, "= %s\n", formData[i].value); + } else { + break; + } + } + } + return OK; +}</pre> + + + + + + + <h3><a name="headers_out" id="headers_out">Printing out every HTTP header received</a></h3> + + + +<pre class="prettyprint lang-c">static int example_handler(request_rec *r) +{ + /*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/ + const apr_array_header_t *fields; + int i; + apr_table_entry_t *e = 0; + /*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/ + + fields = apr_table_elts(r->headers_in); + e = (apr_table_entry_t *) fields->elts; + for(i = 0; i < fields->nelts; i++) { + ap_rprintf(r, "%s: %s\n", e[i].key, e[i].val); + } + return OK; +}</pre> + + + + + + + <h3><a name="request_body" id="request_body">Reading the request body into memory</a></h3> + + + +<pre class="prettyprint lang-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->remaining; + /*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/ + + *rbuf = (const char *) apr_pcalloc(r->pool, (apr_size_t) (length + 1)); + *size = length; + while((len_read = ap_get_client_block(r, argsbuffer, sizeof(argsbuffer))) > 0) { + if((rpos + len_read) > 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_rec *r) +{ + /*~~~~~~~~~~~~~~~~*/ + apr_off_t size; + const char *buffer; + /*~~~~~~~~~~~~~~~~*/ + + if(util_read(r, &buffer, &size) == OK) { + ap_rprintf(r, "We read a request body that was %" APR_OFF_T_FMT " bytes long", size); + } + return OK; +}</pre> + + + + + + + +</div></div> +<div class="bottomlang"> +<p><span>Available Languages: </span><a href="../en/developer/modguide.html" title="English"> en </a></p> +</div><div class="top"><a href="#page-header"><img src="../images/up.gif" alt="top" /></a></div><div class="section"><h2><a id="comments_section" name="comments_section">Comments</a></h2><div class="warning"><strong>Notice:</strong><br />This is not a Q&A section. Comments placed here should be pointed towards suggestions on improving the documentation or server, and may be removed by our moderators if they are either implemented or considered invalid/off-topic. Questions on how to manage the Apache HTTP Server should be directed at either our IRC channel, #httpd, on Libera.chat, or sent to our <a href="https://httpd.apache.org/lists.html">mailing lists</a>.</div> +<script type="text/javascript"><!--//--><![CDATA[//><!-- +var comments_shortname = 'httpd'; +var comments_identifier = 'http://httpd.apache.org/docs/2.4/developer/modguide.html'; +(function(w, d) { + if (w.location.hostname.toLowerCase() == "httpd.apache.org") { + d.write('<div id="comments_thread"><\/div>'); + var s = d.createElement('script'); + s.type = 'text/javascript'; + s.async = true; + s.src = 'https://comments.apache.org/show_comments.lua?site=' + comments_shortname + '&page=' + comments_identifier; + (d.getElementsByTagName('head')[0] || d.getElementsByTagName('body')[0]).appendChild(s); + } + else { + d.write('<div id="comments_thread">Comments are disabled for this page at the moment.<\/div>'); + } +})(window, document); +//--><!]]></script></div><div id="footer"> +<p class="apache">Copyright 2023 The Apache Software Foundation.<br />Licensed under the <a href="http://www.apache.org/licenses/LICENSE-2.0">Apache License, Version 2.0</a>.</p> +<p class="menu"><a href="../mod/">Modules</a> | <a href="../mod/directives.html">Directives</a> | <a href="http://wiki.apache.org/httpd/FAQ">FAQ</a> | <a href="../glossary.html">Glossary</a> | <a href="../sitemap.html">Sitemap</a></p></div><script type="text/javascript"><!--//--><![CDATA[//><!-- +if (typeof(prettyPrint) !== 'undefined') { + prettyPrint(); +} +//--><!]]></script> +</body></html>
\ No newline at end of file diff --git a/docs/manual/developer/modules.html b/docs/manual/developer/modules.html new file mode 100644 index 0000000..ebc705b --- /dev/null +++ b/docs/manual/developer/modules.html @@ -0,0 +1,9 @@ +# GENERATED FROM XML -- DO NOT EDIT + +URI: modules.html.en +Content-Language: en +Content-type: text/html; charset=UTF-8 + +URI: modules.html.ja.utf8 +Content-Language: ja +Content-type: text/html; charset=UTF-8 diff --git a/docs/manual/developer/modules.html.en b/docs/manual/developer/modules.html.en new file mode 100644 index 0000000..fb7ccef --- /dev/null +++ b/docs/manual/developer/modules.html.en @@ -0,0 +1,306 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd"> +<html xmlns="http://www.w3.org/1999/xhtml" lang="en" xml:lang="en"><head> +<meta content="text/html; charset=UTF-8" http-equiv="Content-Type" /> +<!-- + XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX + This file is generated from xml source: DO NOT EDIT + XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX + --> +<title>Converting Modules from Apache 1.3 to Apache 2.0 - Apache HTTP Server Version 2.4</title> +<link href="../style/css/manual.css" rel="stylesheet" media="all" type="text/css" title="Main stylesheet" /> +<link href="../style/css/manual-loose-100pc.css" rel="alternate stylesheet" media="all" type="text/css" title="No Sidebar - Default font size" /> +<link href="../style/css/manual-print.css" rel="stylesheet" media="print" type="text/css" /><link rel="stylesheet" type="text/css" href="../style/css/prettify.css" /> +<script src="../style/scripts/prettify.min.js" type="text/javascript"> +</script> + +<link href="../images/favicon.ico" rel="shortcut icon" /></head> +<body id="manual-page"><div id="page-header"> +<p class="menu"><a href="../mod/">Modules</a> | <a href="../mod/directives.html">Directives</a> | <a href="http://wiki.apache.org/httpd/FAQ">FAQ</a> | <a href="../glossary.html">Glossary</a> | <a href="../sitemap.html">Sitemap</a></p> +<p class="apache">Apache HTTP Server Version 2.4</p> +<img alt="" src="../images/feather.png" /></div> +<div class="up"><a href="./"><img title="<-" alt="<-" src="../images/left.gif" /></a></div> +<div id="path"> +<a href="http://www.apache.org/">Apache</a> > <a href="http://httpd.apache.org/">HTTP Server</a> > <a href="http://httpd.apache.org/docs/">Documentation</a> > <a href="../">Version 2.4</a> > <a href="./">Developer Documentation</a></div><div id="page-content"><div id="preamble"><h1>Converting Modules from Apache 1.3 to Apache 2.0</h1> +<div class="toplang"> +<p><span>Available Languages: </span><a href="../en/developer/modules.html" title="English"> en </a> | +<a href="../ja/developer/modules.html" hreflang="ja" rel="alternate" title="Japanese"> ja </a></p> +</div> + + <p>This is a first attempt at writing the lessons I learned + when trying to convert the <code>mod_mmap_static</code> module to Apache + 2.0. It's by no means definitive and probably won't even be + correct in some ways, but it's a start.</p> +</div> +<div id="quickview"><a href="https://www.apache.org/foundation/contributing.html" class="badge"><img src="https://www.apache.org/images/SupportApache-small.png" alt="Support Apache!" /></a><ul id="toc"><li><img alt="" src="../images/down.gif" /> <a href="#easy">The easier changes ...</a></li> +<li><img alt="" src="../images/down.gif" /> <a href="#messy">The messier changes...</a></li> +</ul><h3>See also</h3><ul class="seealso"><li><a href="#comments_section">Comments</a></li></ul></div> +<div class="top"><a href="#page-header"><img alt="top" src="../images/up.gif" /></a></div> +<div class="section"> +<h2><a name="easy" id="easy">The easier changes ...</a></h2> + + <h3><a name="cleanup" id="cleanup">Cleanup Routines</a></h3> + <p>These now need to be of type <code>apr_status_t</code> and return a + value of that type. Normally the return value will be + <code>APR_SUCCESS</code> unless there is some need to signal an error in + the cleanup. Be aware that even though you signal an error not all code + yet checks and acts upon the error.</p> + + + <h3><a name="init" id="init">Initialisation Routines</a></h3> + <p>These should now be renamed to better signify where they sit + in the overall process. So the name gets a small change from + <code>mmap_init</code> to <code>mmap_post_config</code>. The arguments + passed have undergone a radical change and now look like</p> + + <ul> + <li><code>apr_pool_t *p</code></li> + <li><code>apr_pool_t *plog</code></li> + <li><code>apr_pool_t *ptemp</code></li> + <li><code>server_rec *s</code></li> + </ul> + + + <h3><a name="datatypes" id="datatypes">Data Types</a></h3> + <p>A lot of the data types have been moved into the <a href="http://apr.apache.org/">APR</a>. 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> + <li><code>pool</code> becomes <code>apr_pool_t</code></li> + <li><code>table</code> becomes <code>apr_table_t</code></li> + </ul> + +</div><div class="top"><a href="#page-header"><img alt="top" src="../images/up.gif" /></a></div> +<div class="section"> +<h2><a name="messy" id="messy">The messier changes...</a></h2> + + <h3><a name="register-hooks" id="register-hooks">Register Hooks</a></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, <code>static void register_hooks(void)</code>. + 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 <code>mod_mmap_static</code>:</p> + <div class="example"><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></div> + + <p>This registers 2 functions that need to be called, one in + the <code>post_config</code> stage (virtually every module will need this + one) and one for the <code>translate_name</code> phase. note that while + there are different function names the format of each is + identical. So what is the format?</p> + + <div class="example"><p><code> + ap_hook_<var>phase_name</var>(<var>function_name</var>, + <var>predecessors</var>, <var>successors</var>, <var>position</var>); + </code></p></div> + + <p>There are 3 hook positions defined...</p> + + <ul> + <li><code>HOOK_FIRST</code></li> + <li><code>HOOK_MIDDLE</code></li> + <li><code>HOOK_LAST</code></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 <code>mod_mmap_static</code> case I didn't care about the + <code>post_config</code> stage, but the <code>mmap_static_xlat</code> + <strong>must</strong> be called after the core module had done its name + translation, hence the use of the aszPre to define a modifier to the + position <code>HOOK_LAST</code>.</p> + + + <h3><a name="moddef" id="moddef">Module Definition</a></h3> + <p>There are now a lot fewer stages to worry about when + creating your module definition. The old definition looked + like</p> + + <div class="example"><pre>module MODULE_VAR_EXPORT <var>module_name</var>_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></div> + + <p>The new structure is a great deal simpler...</p> + <div class="example"><pre>module MODULE_VAR_EXPORT <var>module_name</var>_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></div> + + <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> + + <dl> + <dt><code>/* dir config creater */</code></dt> + <dd><code>/* create per-directory config structures */</code></dd> + + <dt><code>/* server config */</code></dt> + <dd><code>/* create per-server config structures */</code></dd> + + <dt><code>/* dir merger */</code></dt> + <dd><code>/* merge per-directory config structures */</code></dd> + + <dt><code>/* merge server config */</code></dt> + <dd><code>/* merge per-server config structures */</code></dd> + + <dt><code>/* command table */</code></dt> + <dd><code>/* command apr_table_t */</code></dd> + + <dt><code>/* handlers */</code></dt> + <dd><code>/* handlers */</code></dd> + </dl> + + <p>The remainder of the old functions should be registered as + hooks. There are the following hook stages defined so + far...</p> + + <dl> + <dt><code>ap_hook_pre_config</code></dt> + <dd>do any setup required prior to processing configuration + directives</dd> + + <dt><code>ap_hook_check_config</code></dt> + <dd>review configuration directive interdependencies</dd> + + <dt><code>ap_hook_test_config</code></dt> + <dd>executes only with <code>-t</code> option</dd> + + <dt><code>ap_hook_open_logs</code></dt> + <dd>open any specified logs</dd> + + <dt><code>ap_hook_post_config</code></dt> + <dd>this is where the old <code>_init</code> routines get + registered</dd> + + <dt><code>ap_hook_http_method</code></dt> + <dd>retrieve the http method from a request. (legacy)</dd> + + <dt><code>ap_hook_auth_checker</code></dt> + <dd>check if the resource requires authorization</dd> + + <dt><code>ap_hook_access_checker</code></dt> + <dd>check for module-specific restrictions</dd> + + <dt><code>ap_hook_check_user_id</code></dt> + <dd>check the user-id and password</dd> + + <dt><code>ap_hook_default_port</code></dt> + <dd>retrieve the default port for the server</dd> + + <dt><code>ap_hook_pre_connection</code></dt> + <dd>do any setup required just before processing, but after + accepting</dd> + + <dt><code>ap_hook_process_connection</code></dt> + <dd>run the correct protocol</dd> + + <dt><code>ap_hook_child_init</code></dt> + <dd>call as soon as the child is started</dd> + + <dt><code>ap_hook_create_request</code></dt> + <dd>??</dd> + + <dt><code>ap_hook_fixups</code></dt> + <dd>last chance to modify things before generating content</dd> + + <dt><code>ap_hook_handler</code></dt> + <dd>generate the content</dd> + + <dt><code>ap_hook_header_parser</code></dt> + <dd>lets modules look at the headers, not used by most modules, because + they use <code>post_read_request</code> for this</dd> + + <dt><code>ap_hook_insert_filter</code></dt> + <dd>to insert filters into the filter chain</dd> + + <dt><code>ap_hook_log_transaction</code></dt> + <dd>log information about the request</dd> + + <dt><code>ap_hook_optional_fn_retrieve</code></dt> + <dd>retrieve any functions registered as optional</dd> + + <dt><code>ap_hook_post_read_request</code></dt> + <dd>called after reading the request, before any other phase</dd> + + <dt><code>ap_hook_quick_handler</code></dt> + <dd>called before any request processing, used by cache modules.</dd> + + <dt><code>ap_hook_translate_name</code></dt> + <dd>translate the URI into a filename</dd> + + <dt><code>ap_hook_type_checker</code></dt> + <dd>determine and/or set the doc type</dd> + </dl> + +</div></div> +<div class="bottomlang"> +<p><span>Available Languages: </span><a href="../en/developer/modules.html" title="English"> en </a> | +<a href="../ja/developer/modules.html" hreflang="ja" rel="alternate" title="Japanese"> ja </a></p> +</div><div class="top"><a href="#page-header"><img src="../images/up.gif" alt="top" /></a></div><div class="section"><h2><a id="comments_section" name="comments_section">Comments</a></h2><div class="warning"><strong>Notice:</strong><br />This is not a Q&A section. Comments placed here should be pointed towards suggestions on improving the documentation or server, and may be removed by our moderators if they are either implemented or considered invalid/off-topic. Questions on how to manage the Apache HTTP Server should be directed at either our IRC channel, #httpd, on Libera.chat, or sent to our <a href="https://httpd.apache.org/lists.html">mailing lists</a>.</div> +<script type="text/javascript"><!--//--><![CDATA[//><!-- +var comments_shortname = 'httpd'; +var comments_identifier = 'http://httpd.apache.org/docs/2.4/developer/modules.html'; +(function(w, d) { + if (w.location.hostname.toLowerCase() == "httpd.apache.org") { + d.write('<div id="comments_thread"><\/div>'); + var s = d.createElement('script'); + s.type = 'text/javascript'; + s.async = true; + s.src = 'https://comments.apache.org/show_comments.lua?site=' + comments_shortname + '&page=' + comments_identifier; + (d.getElementsByTagName('head')[0] || d.getElementsByTagName('body')[0]).appendChild(s); + } + else { + d.write('<div id="comments_thread">Comments are disabled for this page at the moment.<\/div>'); + } +})(window, document); +//--><!]]></script></div><div id="footer"> +<p class="apache">Copyright 2023 The Apache Software Foundation.<br />Licensed under the <a href="http://www.apache.org/licenses/LICENSE-2.0">Apache License, Version 2.0</a>.</p> +<p class="menu"><a href="../mod/">Modules</a> | <a href="../mod/directives.html">Directives</a> | <a href="http://wiki.apache.org/httpd/FAQ">FAQ</a> | <a href="../glossary.html">Glossary</a> | <a href="../sitemap.html">Sitemap</a></p></div><script type="text/javascript"><!--//--><![CDATA[//><!-- +if (typeof(prettyPrint) !== 'undefined') { + prettyPrint(); +} +//--><!]]></script> +</body></html>
\ No newline at end of file diff --git a/docs/manual/developer/modules.html.ja.utf8 b/docs/manual/developer/modules.html.ja.utf8 new file mode 100644 index 0000000..097e6bc --- /dev/null +++ b/docs/manual/developer/modules.html.ja.utf8 @@ -0,0 +1,301 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd"> +<html xmlns="http://www.w3.org/1999/xhtml" lang="ja" xml:lang="ja"><head> +<meta content="text/html; charset=UTF-8" http-equiv="Content-Type" /> +<!-- + XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX + This file is generated from xml source: DO NOT EDIT + XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX + --> +<title>モジュールの Apache 1.3 から Apache 2.0 への移植 - Apache HTTP サーバ バージョン 2.4</title> +<link href="../style/css/manual.css" rel="stylesheet" media="all" type="text/css" title="Main stylesheet" /> +<link href="../style/css/manual-loose-100pc.css" rel="alternate stylesheet" media="all" type="text/css" title="No Sidebar - Default font size" /> +<link href="../style/css/manual-print.css" rel="stylesheet" media="print" type="text/css" /><link rel="stylesheet" type="text/css" href="../style/css/prettify.css" /> +<script src="../style/scripts/prettify.min.js" type="text/javascript"> +</script> + +<link href="../images/favicon.ico" rel="shortcut icon" /></head> +<body id="manual-page"><div id="page-header"> +<p class="menu"><a href="../mod/">モジュール</a> | <a href="../mod/directives.html">ディレクティブ</a> | <a href="http://wiki.apache.org/httpd/FAQ">FAQ</a> | <a href="../glossary.html">用語</a> | <a href="../sitemap.html">サイトマップ</a></p> +<p class="apache">Apache HTTP サーバ バージョン 2.4</p> +<img alt="" src="../images/feather.png" /></div> +<div class="up"><a href="./"><img title="<-" alt="<-" src="../images/left.gif" /></a></div> +<div id="path"> +<a href="http://www.apache.org/">Apache</a> > <a href="http://httpd.apache.org/">HTTP サーバ</a> > <a href="http://httpd.apache.org/docs/">ドキュメンテーション</a> > <a href="../">バージョン 2.4</a> > <a href="./">Developer Documentation</a></div><div id="page-content"><div id="preamble"><h1>モジュールの Apache 1.3 から Apache 2.0 への移植</h1> +<div class="toplang"> +<p><span>翻訳済み言語: </span><a href="../en/developer/modules.html" hreflang="en" rel="alternate" title="English"> en </a> | +<a href="../ja/developer/modules.html" title="Japanese"> ja </a></p> +</div> +<div class="outofdate">この日本語訳はすでに古くなっている + 可能性があります。 + 最近更新された内容を見るには英語版をご覧下さい。 + </div> + + <p>この文書は <code>mod_mmap_static</code> モジュールを Apache 2.0 用に移植した時に + 学んだ経験をもとに書いた、最初の手引き書です。まだまだ完全じゃないし、 + ひょっとすると間違っている部分もあるかもしれませんが、 + 取っ掛りにはなるでしょう。</p> +</div> +<div id="quickview"><a href="https://www.apache.org/foundation/contributing.html" class="badge"><img src="https://www.apache.org/images/SupportApache-small.png" alt="Support Apache!" /></a><ul id="toc"><li><img alt="" src="../images/down.gif" /> <a href="#easy">簡単な変更点</a></li> +<li><img alt="" src="../images/down.gif" /> <a href="#messy">もっと厄介な変更点…</a></li> +</ul><h3>参照</h3><ul class="seealso"><li><a href="#comments_section">コメント</a></li></ul></div> +<div class="top"><a href="#page-header"><img alt="top" src="../images/up.gif" /></a></div> +<div class="section"> +<h2><a name="easy" id="easy">簡単な変更点</a></h2> + + <h3><a name="cleanup" id="cleanup">クリーンナップ ルーチン</a></h3> + <p>クリーンナップルーチンは <code>apr_status_t</code> 型である必要があります。 + そして、apr_status_t 型の値を返さなくてはなりません。 + クリーンナップ中のエラーを通知する必要がなければ、返り値は普通、 + <code>ARP_SUCCESS</code> です。たとえエラーを通知したとしても、 + すべてのコードがその通知をチェックしたり、 + エラーに応じた動作をするわけではないことに気をつけてください。</p> + + + + <h3><a name="init" id="init">初期化ルーチン</a></h3> + + <p>初期化ルーチンは処理全体から見てしっくりくるような意味を表すように、 + 名前が変更されました。ですから、<code>mmap_init</code> から <code>mmap_post_config</code> + のようにちょっと変更されました。 + 渡される引数は大幅に変更され、次のようになりました。</p> + + <ul> + <li><code>apr_pool_t *p</code></li> + <li><code>apr_pool_t *plog</code></li> + <li><code>apr_pool_t *ptemp</code></li> + <li><code>server_rec *s</code></li> + </ul> + + + <h3><a name="datatypes" id="datatypes">データ型</a></h3> + <p>データ型のほとんどは <a href="http://apr.apache.org/">APR</a> に移されました。つまり、 + いくつかの名前が前述のように変更されています。 + 施すべき変更点の簡単な一覧を以下に示します。</p> + + <ul> + <li><code>pool</code> becomes <code>apr_pool_t</code></li> + <li><code>table</code> becomes <code>apr_table_t</code></li> + </ul> + +</div><div class="top"><a href="#page-header"><img alt="top" src="../images/up.gif" /></a></div> +<div class="section"> +<h2><a name="messy" id="messy">もっと厄介な変更点…</a></h2> + + <h3><a name="register-hooks" id="register-hooks">フックの登録</a></h3> + <p>新しいアーキテクチャでは作成した関数を呼び出すのに + 一連のフックを使用します。このフックは、新しい関数 + <code>static void register_hooks(void)</code> を使って登録するよう、 + モジュールに書き足さなくてはなりません。 + この関数は、なにをすべきか一旦理解してしまえば、 + 十分にわかりやすいものです。 + リクエストの処理のあるステージで呼び出さなくてはならない + 関数は登録する必要があります。ハンドラは登録する必要はありません。 + 関数を登録できるフェーズはたくさんあります。 + それぞれのフェーズで、関数を呼び出す相対的な順番は、 + かなりの程度制御できます。</p> + + <p>以下は、<code>mod_mmap_static</code> に追加したコードです:</p> + + <div class="example"><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></div> + + <p>ここでは呼びだすべき二つの関数を登録しています。一つは + <code>post_config</code> ステージ用 (ほとんどすべてのモジュール + はこれが必要です) で、もう一つは <code>translate_name</code> フェーズ用です。 + それぞれの関数は名前は違うけれども形式は同じであることに注意してください。 + それでは、形式はどのようになっているでしょうか?</p> + + <div class="example"><p><code> + ap_hook_<var>phase_name</var>(<var>function_name</var>, + <var>predecessors</var>, <var>successors</var>, <var>position</var>); + </code></p></div> + + <p>三つの位置が定義されています…</p> + + <ul> + <li><code>HOOK_FIRST</code></li> + <li><code>HOOK_MIDDLE</code></li> + <li><code>HOOK_LAST</code></li> + </ul> + + <p>位置を定義するには、上記の「位置」を指定し、 + 修飾子である「先行」と「後行」で手を加えます。 + 「先行」「後行」は、呼ばれるべき関数のリストです。 + 「先行」は関数の実行前に呼ばれるもので、 + 「後行」は実行後に呼ばれるものです。</p> + + <p><code>mod_mmap_static</code> の場合、<code>post_config</code> + ステージでは必要ありませんが、 + <code>mmap_static_xlat</code> が core モジュールが名前の変換を実行した後に + <strong>呼ばれなければなりません</strong>。 + そこで aszPre を使って <code>HOOK_LAST</code> の修飾子を定義しています。</p> + + + <h3><a name="moddef" id="moddef">モジュールの定義</a></h3> + <p>モジュールの定義を作成する際に注意しなければならない + ステージの数は激減しています。古い定義は次のようになっていました。</p> + + <div class="example"><pre>module MODULE_VAR_EXPORT <var>module_name</var>_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></div> + + <p>新しい構造体はとってもシンプルです…</p> + <div class="example"><pre>module MODULE_VAR_EXPORT <var>module_name</var>_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></div> + + <p>このうちのいくつかは古いものから新しいものに直接読み替えられるもので、 + いくつかはそうではありません。どうすればいいのかを要約してみます。</p> + + <p>直接読み替えられるステージ:</p> + + <dl> + <dt><code>/* ディレクトリ設定作成関数 */</code></dt> + <dd><code>/* ディレクトリ毎設定構造体作成 */</code></dd> + + <dt><code>/* サーバ設定作成関数 */</code></dt> + <dd><code>/* サーバ毎設定構造体作成 */</code></dd> + + <dt><code>/* ディレクトリ設定マージ関数 */</code></dt> + <dd><code>/* ディレクトリ毎設定構造体マージ */</code></dd> + + <dt><code>/* サーバ設定マージ関数 */</code></dt> + <dd><code>/* サーバ毎設定構造体作成マージ */</code></dd> + + <dt><code>/* コマンド・テーブル */</code></dt> + <dd><code>/* コマンド apr_table_t */</code></dd> + + <dt><code>/* ハンドラ */</code></dt> + <dd><code>/* ハンドラ */</code></dd> + </dl> + + <p>古い関数の残りのものはフックとして登録されるべきです。 + 現時点で次のようなフック・ステージが定義されています…</p> + + <dl> + <dt><code>ap_hook_post_config</code></dt> + <dd>(以前の <code>_init</code> ルーチンが登録されるべき場所です)</dd> + + <dt><code>ap_hook_http_method</code></dt> + <dd>(リクエストから HTTP メソッドを取得します (互換用))</dd> + + <dt><code>ap_hook_open_logs</code></dt> + <dd>(特定のログのオープン)</dd> + + <dt><code>ap_hook_auth_checker</code></dt> + <dd>(リソースが権限を必要とするかどうかの確認)</dd> + + <dt><code>ap_hook_access_checker</code></dt> + <dd>(モジュール固有の制約の確認)</dd> + + <dt><code>ap_hook_check_user_id</code></dt> + <dd>(ユーザ ID とパスワードの確認)</dd> + + <dt><code>ap_hook_default_port</code></dt> + <dd>(サーバのデフォルト・ポートの取得)</dd> + + <dt><code>ap_hook_pre_connection</code></dt> + <dd>(処理の直前に必要なことを実行。ただし accept 直後に呼ばれる)</dd> + + <dt><code>ap_hook_process_connection</code></dt> + <dd>(プロトコルの処理)</dd> + + <dt><code>ap_hook_child_init</code></dt> + <dd>(子プロセル起動直後)</dd> + + <dt><code>ap_hook_create_request</code></dt> + <dd>(??)</dd> + + <dt><code>ap_hook_fixups</code></dt> + <dd>(応答内容の生成を変更するラスト・チャンス)</dd> + + <dt><code>ap_hook_handler</code></dt> + <dd>(応答内容の生成)</dd> + + <dt><code>ap_hook_header_parser</code></dt> + <dd>(モジュールにヘッダの照会をさせる。ほとんどのモジュールでは使われません。post_read_request を使います)</dd> + + <dt><code>ap_hook_insert_filter</code></dt> + <dd>(フィルタ・チェインにフィルタを挿入)</dd> + + <dt><code>ap_hook_log_transaction</code></dt> + <dd>(リクエストについての情報を記録する)</dd> + + <dt><code>ap_hook_optional_fn_retrieve</code></dt> + <dd>(オプションとして登録された関数の取得)</dd> + + <dt><code>ap_hook_post_read_request</code></dt> + <dd>(リクエストを読みこんだ後、他のフェーズの前に呼ばれる)</dd> + + <dt><code>ap_hook_quick_handler</code></dt> + <dd>リクエストの処理が始まる前に呼ばれる。キャッシュモジュールが + 使用している</dd> + + <dt><code>ap_hook_translate_name</code></dt> + <dd>(URI をファイル名に変換する)</dd> + + <dt><code>ap_hook_type_checker</code></dt> + <dd>(文書型の決定と設定。あるいはその片方)</dd> + </dl> + +</div></div> +<div class="bottomlang"> +<p><span>翻訳済み言語: </span><a href="../en/developer/modules.html" hreflang="en" rel="alternate" title="English"> en </a> | +<a href="../ja/developer/modules.html" title="Japanese"> ja </a></p> +</div><div class="top"><a href="#page-header"><img src="../images/up.gif" alt="top" /></a></div><div class="section"><h2><a id="comments_section" name="comments_section">コメント</a></h2><div class="warning"><strong>Notice:</strong><br />This is not a Q&A section. Comments placed here should be pointed towards suggestions on improving the documentation or server, and may be removed by our moderators if they are either implemented or considered invalid/off-topic. Questions on how to manage the Apache HTTP Server should be directed at either our IRC channel, #httpd, on Libera.chat, or sent to our <a href="https://httpd.apache.org/lists.html">mailing lists</a>.</div> +<script type="text/javascript"><!--//--><![CDATA[//><!-- +var comments_shortname = 'httpd'; +var comments_identifier = 'http://httpd.apache.org/docs/2.4/developer/modules.html'; +(function(w, d) { + if (w.location.hostname.toLowerCase() == "httpd.apache.org") { + d.write('<div id="comments_thread"><\/div>'); + var s = d.createElement('script'); + s.type = 'text/javascript'; + s.async = true; + s.src = 'https://comments.apache.org/show_comments.lua?site=' + comments_shortname + '&page=' + comments_identifier; + (d.getElementsByTagName('head')[0] || d.getElementsByTagName('body')[0]).appendChild(s); + } + else { + d.write('<div id="comments_thread">Comments are disabled for this page at the moment.<\/div>'); + } +})(window, document); +//--><!]]></script></div><div id="footer"> +<p class="apache">Copyright 2023 The Apache Software Foundation.<br />この文書は <a href="http://www.apache.org/licenses/LICENSE-2.0">Apache License, Version 2.0</a> のライセンスで提供されています。.</p> +<p class="menu"><a href="../mod/">モジュール</a> | <a href="../mod/directives.html">ディレクティブ</a> | <a href="http://wiki.apache.org/httpd/FAQ">FAQ</a> | <a href="../glossary.html">用語</a> | <a href="../sitemap.html">サイトマップ</a></p></div><script type="text/javascript"><!--//--><![CDATA[//><!-- +if (typeof(prettyPrint) !== 'undefined') { + prettyPrint(); +} +//--><!]]></script> +</body></html>
\ No newline at end of file diff --git a/docs/manual/developer/new_api_2_4.html b/docs/manual/developer/new_api_2_4.html new file mode 100644 index 0000000..e79fd3c --- /dev/null +++ b/docs/manual/developer/new_api_2_4.html @@ -0,0 +1,5 @@ +# GENERATED FROM XML -- DO NOT EDIT + +URI: new_api_2_4.html.en +Content-Language: en +Content-type: text/html; charset=UTF-8 diff --git a/docs/manual/developer/new_api_2_4.html.en b/docs/manual/developer/new_api_2_4.html.en new file mode 100644 index 0000000..6354e85 --- /dev/null +++ b/docs/manual/developer/new_api_2_4.html.en @@ -0,0 +1,601 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd"> +<html xmlns="http://www.w3.org/1999/xhtml" lang="en" xml:lang="en"><head> +<meta content="text/html; charset=UTF-8" http-equiv="Content-Type" /> +<!-- + XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX + This file is generated from xml source: DO NOT EDIT + XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX + --> +<title>API Changes in Apache HTTP Server 2.4 since 2.2 - Apache HTTP Server Version 2.4</title> +<link href="../style/css/manual.css" rel="stylesheet" media="all" type="text/css" title="Main stylesheet" /> +<link href="../style/css/manual-loose-100pc.css" rel="alternate stylesheet" media="all" type="text/css" title="No Sidebar - Default font size" /> +<link href="../style/css/manual-print.css" rel="stylesheet" media="print" type="text/css" /><link rel="stylesheet" type="text/css" href="../style/css/prettify.css" /> +<script src="../style/scripts/prettify.min.js" type="text/javascript"> +</script> + +<link href="../images/favicon.ico" rel="shortcut icon" /></head> +<body id="manual-page"><div id="page-header"> +<p class="menu"><a href="../mod/">Modules</a> | <a href="../mod/directives.html">Directives</a> | <a href="http://wiki.apache.org/httpd/FAQ">FAQ</a> | <a href="../glossary.html">Glossary</a> | <a href="../sitemap.html">Sitemap</a></p> +<p class="apache">Apache HTTP Server Version 2.4</p> +<img alt="" src="../images/feather.png" /></div> +<div class="up"><a href="./"><img title="<-" alt="<-" src="../images/left.gif" /></a></div> +<div id="path"> +<a href="http://www.apache.org/">Apache</a> > <a href="http://httpd.apache.org/">HTTP Server</a> > <a href="http://httpd.apache.org/docs/">Documentation</a> > <a href="../">Version 2.4</a></div><div id="page-content"><div id="preamble"><h1>API Changes in Apache HTTP Server 2.4 since 2.2</h1> +<div class="toplang"> +<p><span>Available Languages: </span><a href="../en/developer/new_api_2_4.html" title="English"> en </a></p> +</div> + + <p>This document describes changes to the Apache HTTPD API from + version 2.2 to 2.4, that may be of interest to module/application + developers and core hacks. As of the first GA release of the + 2.4 branch API compatibility is preserved for the life of the + 2.4 branch. (The + <a href="http://svn.apache.org/repos/asf/httpd/httpd/branches/2.4.x/VERSIONING">VERSIONING</a> + description for the 2.4 release provides more information about API + compatibility.)</p> + + <p>API changes fall into two categories: APIs that are altogether new, + and existing APIs that are expanded or changed. The latter are + further divided into those where all changes are backwards-compatible + (so existing modules can ignore them), and those that might + require attention by maintainers. As with the transition from + HTTPD 2.0 to 2.2, existing modules and applications will require + recompiling and may call for some attention, but most should not + require any substantial updating (although some may be able to + take advantage of API changes to offer significant improvements).</p> + <p>For the purpose of this document, the API is split according + to the public header files. These headers are themselves the + reference documentation, and can be used to generate a browsable + HTML reference with <code>make docs</code>.</p> +</div> +<div id="quickview"><a href="https://www.apache.org/foundation/contributing.html" class="badge"><img src="https://www.apache.org/images/SupportApache-small.png" alt="Support Apache!" /></a><ul id="toc"><li><img alt="" src="../images/down.gif" /> <a href="#api_changes">Changed APIs</a></li> +<li><img alt="" src="../images/down.gif" /> <a href="#upgrading">Specific information on upgrading modules from 2.2</a></li> +</ul><h3>See also</h3><ul class="seealso"><li><a href="#comments_section">Comments</a></li></ul></div> +<div class="top"><a href="#page-header"><img alt="top" src="../images/up.gif" /></a></div> +<div class="section"> +<h2><a name="api_changes" id="api_changes">Changed APIs</a></h2> + + + <h3><a name="ap_expr" id="ap_expr">ap_expr (NEW!)</a></h3> + + <p>Introduces a new API to parse and evaluate boolean and algebraic + expressions, including provision for a standard syntax and + customised variants.</p> + + + <h3><a name="ap_listen" id="ap_listen">ap_listen (changed; backwards-compatible)</a></h3> + + <p>Introduces a new API to enable httpd child processes to serve + different purposes.</p> + + + <h3><a name="ap_mpm" id="ap_mpm">ap_mpm (changed)</a></h3> + + <p><code>ap_mpm_run</code> is replaced by a new <code>mpm</code> hook. + Also <code>ap_graceful_stop_signalled</code> is lost, and + <code>ap_mpm_register_timed_callback</code> is new.</p> + + + <h3><a name="ap_regex" id="ap_regex">ap_regex (changed)</a></h3> + + <p>In addition to the existing regexp wrapper, a new higher-level API + <code>ap_rxplus</code> is now provided. This provides the capability to + compile Perl-style expressions like <code>s/regexp/replacement/flags</code> + and to execute them against arbitrary strings. Support for regexp + backreferences is also added.</p> + + + <h3><a name="ap_slotmem" id="ap_slotmem">ap_slotmem (NEW!)</a></h3> + + <p>Introduces an API for modules to allocate and manage memory slots, + most commonly for shared memory.</p> + + + <h3><a name="ap_socache" id="ap_socache">ap_socache (NEW!)</a></h3> + + <p>API to manage a shared object cache.</p> + + + <h3><a name="heartbeat" id="heartbeat">heartbeat (NEW!)</a></h3> + + <p>common structures for heartbeat modules</p> + + + <h3><a name="ap_parse_htaccess" id="ap_parse_htaccess">ap_parse_htaccess (changed)</a></h3> + + <p>The function signature for <code>ap_parse_htaccess</code> has been + changed. A <code>apr_table_t</code> of individual directives allowed + for override must now be passed (override remains).</p> + + + <h3><a name="http_config" id="http_config">http_config (changed)</a></h3> + + <ul> + <li>Introduces per-module, per-directory loglevels, including macro wrappers.</li> + <li>New <code>AP_DECLARE_MODULE</code> macro to declare all modules.</li> + <li>New <code>APLOG_USE_MODULE</code> macro necessary for per-module loglevels in + multi-file modules.</li> + <li>New API to retain data across module unload/load</li> + <li>New <code>check_config</code> hook</li> + <li>New <code>ap_process_fnmatch_configs()</code> function to process wildcards</li> + <li>Change <code>ap_configfile_t</code>, <code>ap_cfg_getline()</code>, + <code>ap_cfg_getc()</code> to return error codes, and add + <code>ap_pcfg_strerror()</code> for retrieving an error description.</li> + <li>Any config directive permitted in ACCESS_CONF context must now + correctly handle being called from an .htaccess file via the new + <code class="directive"><a href="../mod/core.html#allowoverridelist">AllowOverrideList</a></code> directive. + ap_check_cmd_context() accepts a new flag NOT_IN_HTACCESS to detect + this case.</li> + </ul> + + + <h3><a name="http_core" id="http_core">http_core (changed)</a></h3> + + <ul> + <li>REMOVED <code>ap_default_type</code>, <code>ap_requires</code>, all + 2.2 authnz API</li> + <li>Introduces Optional Functions for logio and authnz</li> + <li>New function <code>ap_get_server_name_for_url</code> to support IPv6 + literals.</li> + <li>New function <code>ap_register_errorlog_handler</code> to register error log + format string handlers.</li> + <li>Arguments of <code>error_log</code> hook have changed. Declaration has moved to + <code>http_core.h</code>.</li> + <li>New function <code>ap_state_query</code> to determine if the server is in the + initial configuration preflight phase or not. This is both easier to + use and more correct than the old method of creating a pool userdata + entry in the process pool.</li> + <li>New function <code>ap_get_conn_socket</code> to get the socket descriptor for a + connection. This should be used instead of accessing the core + connection config directly.</li> + </ul> + + + <h3><a name="httpd" id="httpd">httpd (changed)</a></h3> + + <ul> + <li>Introduce per-directory, per-module loglevel</li> + <li>New loglevels <code>APLOG_TRACEn</code></li> + <li>Introduce errorlog ids for requests and connections</li> + <li>Support for mod_request kept_body</li> + <li>Support buffering filter data for async requests</li> + <li>New <code>CONN_STATE</code> values</li> + <li>Function changes: <code>ap_escape_html</code> updated; + <code>ap_unescape_all</code>, <code>ap_escape_path_segment_buffer</code></li> + <li>Modules that load other modules later than the <code>EXEC_ON_READ</code> config + reading stage need to call <code>ap_reserve_module_slots()</code> or + <code>ap_reserve_module_slots_directive()</code> in their + <code>pre_config hook</code>.</li> + <li>The useragent IP address per request can now be tracked + independently of the client IP address of the connection, for + support of deployments with load balancers.</li> + </ul> + + + <h3><a name="http_log" id="http_log">http_log (changed)</a></h3> + + <ul> + <li>Introduce per-directory, per-module loglevel</li> + <li>New loglevels <code>APLOG_TRACEn</code></li> + <li><code>ap_log_*error</code> become macro wrappers (backwards-compatible if + <code>APLOG_MARK</code> macro is used, except that is no longer possible to + use <code>#ifdef</code> inside the argument list)</li> + <li>piped logging revamped</li> + <li><code>module_index</code> added to error_log hook</li> + <li>new function: <code>ap_log_command_line</code></li> + </ul> + + + <h3><a name="http_request" id="http_request">http_request (changed)</a></h3> + + <ul> + <li>New auth_internal API and auth_provider API</li> + <li>New <code>EOR</code> bucket type</li> + <li>New function <code>ap_process_async_request</code></li> + <li>New flags <code>AP_AUTH_INTERNAL_PER_CONF</code> and + <code>AP_AUTH_INTERNAL_PER_URI</code></li> + <li>New <code>access_checker_ex</code> hook to apply additional access control + and/or bypass authentication.</li> + <li>New functions <code>ap_hook_check_access_ex</code>, + <code>ap_hook_check_access</code>, <code>ap_hook_check_authn</code>, + <code>ap_hook_check_authz</code> which accept + <code>AP_AUTH_INTERNAL_PER_*</code> flags</li> + <li>DEPRECATED direct use of <code>ap_hook_access_checker</code>, + <code>access_checker_ex</code>, <code>ap_hook_check_user_id</code>, + <code>ap_hook_auth_checker</code></li> + </ul> + <p>When possible, registering all access control hooks (including + authentication and authorization hooks) using <code>AP_AUTH_INTERNAL_PER_CONF</code> + is recommended. If all modules' access control hooks are registered + with this flag, then whenever the server handles an internal + sub-request that matches the same set of access control configuration + directives as the initial request (which is the common case), it can + avoid invoking the access control hooks another time.</p> + <p>If your module requires the old behavior and must perform access + control checks on every sub-request with a different URI from the + initial request, even if that URI matches the same set of access + control configuration directives, then use + <code>AP_AUTH_INTERNAL_PER_URI</code>.</p> + + + <h3><a name="mod_auth" id="mod_auth">mod_auth (NEW!)</a></h3> + + <p>Introduces the new provider framework for authn and authz</p> + + + <h3><a name="mod_cache" id="mod_cache">mod_cache (changed)</a></h3> + + <p>Introduces a <code>commit_entity()</code> function to the cache provider + interface, allowing atomic writes to cache. Add a <code>cache_status()</code> + hook to report the cache decision. All private structures and functions were + removed.</p> + + + <h3><a name="mod_core" id="mod_core">mod_core (NEW!)</a></h3> + + <p>This introduces low-level APIs to send arbitrary headers, + and exposes functions to handle HTTP OPTIONS and TRACE.</p> + + + <h3><a name="mod_cache_disk" id="mod_cache_disk">mod_cache_disk (changed)</a></h3> + + <p>Changes the disk format of the disk cache to support atomic cache + updates without locking. The device/inode pair of the body file is + embedded in the header file, allowing confirmation that the header + and body belong to one another.</p> + + + <h3><a name="mod_disk_cache" id="mod_disk_cache">mod_disk_cache (renamed)</a></h3> + + <p>The mod_disk_cache module has been renamed to mod_cache_disk in + order to be consistent with the naming of other modules within the + server.</p> + + + <h3><a name="mod_request" id="mod_request">mod_request (NEW!)</a></h3> + + <p>The API for <code class="module"><a href="../mod/mod_request.html">mod_request</a></code>, to make input data + available to multiple application/handler modules where required, + and to parse HTML form data.</p> + + + <h3><a name="mpm_common" id="mpm_common">mpm_common (changed)</a></h3> + + <ul> + <li>REMOVES: <code>accept</code>, <code>lockfile</code>, <code>lock_mech</code>, + <code>set_scoreboard</code> (locking uses the new ap_mutex API)</li> + <li>NEW API to drop privileges (delegates this platform-dependent + function to modules)</li> + <li>NEW Hooks: <code>mpm_query</code>, <code>timed_callback</code>, and + <code>get_name</code></li> + <li>CHANGED interfaces: <code>monitor</code> hook, + <code>ap_reclaim_child_processes</code>, + <code>ap_relieve_child_processes</code></li> + </ul> + + + <h3><a name="scoreboard" id="scoreboard">scoreboard (changed)</a></h3> + + <p><code>ap_get_scoreboard_worker</code> is made non-backwards-compatible + as an alternative version is introduced. Additional proxy_balancer + support. Child status stuff revamped.</p> + + + <h3><a name="util_cookies" id="util_cookies">util_cookies (NEW!)</a></h3> + + <p>Introduces a new API for managing HTTP Cookies.</p> + + + <h3><a name="util_ldap" id="util_ldap">util_ldap (changed)</a></h3> + + <p><em>no description available</em></p> + + + <h3><a name="util_mutex" id="util_mutex">util_mutex (NEW!)</a></h3> + + <p>A wrapper for APR proc and global mutexes in httpd, providing + common configuration for the underlying mechanism and location + of lock files.</p> + + + <h3><a name="util_script" id="util_script">util_script (changed)</a></h3> + + <p>NEW: <code>ap_args_to_table</code></p> + + + <h3><a name="util_time" id="util_time">util_time (changed)</a></h3> + + <p>NEW: <code>ap_recent_ctime_ex</code></p> + + +</div><div class="top"><a href="#page-header"><img alt="top" src="../images/up.gif" /></a></div> +<div class="section"> +<h2><a name="upgrading" id="upgrading">Specific information on upgrading modules from 2.2</a></h2> + + + <h3><a name="upgrading_logging" id="upgrading_logging">Logging</a></h3> + + <p>In order to take advantage of per-module loglevel configuration, any + source file that calls the <code>ap_log_*</code> functions should declare + which module it belongs to. If the module's module_struct is called + <code>foo_module</code>, the following code can be used to remain + backward compatible with HTTPD 2.0 and 2.2:</p> + <div class="example"><p><code> + #include <http_log.h><br /> + <br /> + #ifdef APLOG_USE_MODULE<br /> + APLOG_USE_MODULE(foo);<br /> + #endif + </code></p></div> + <p>Note: This is absolutely required for C++-language modules. It + can be skipped for C-language modules, though that breaks + module-specific log level support for files without it.</p> + <p>The number of parameters of the <code>ap_log_*</code> functions and the + definition of <code>APLOG_MARK</code> has changed. Normally, the change + is completely transparent. However, changes are required if a + module uses <code>APLOG_MARK</code> as a parameter to its own functions + or if a module calls <code>ap_log_*</code> without passing + <code>APLOG_MARK</code>. A module which uses wrappers + around <code>ap_log_*</code> typically uses both of these constructs.</p> + + <p>The easiest way to change code which passes <code>APLOG_MARK</code> to + its own functions is to define and use a different macro that expands to + the parameters required by those functions, as <code>APLOG_MARK</code> + should only be used when calling <code>ap_log_*</code> + directly. In this way, the code will remain compatible with HTTPD 2.0 + and 2.2.</p> + + <p>Code which calls <code>ap_log_*</code> without passing + <code>APLOG_MARK</code> will necessarily differ between 2.4 and earlier + releases, as 2.4 requires a new third argument, + <code>APLOG_MODULE_INDEX</code>.</p> + + <div class="example"><p><code> + /* code for httpd 2.0/2.2 */<br /> + ap_log_perror(file, line, APLOG_ERR, 0, p, "Failed to allocate dynamic lock structure");<br /> + <br /> + /* code for httpd 2.4 */<br /> + ap_log_perror(file, line, APLOG_MODULE_INDEX, APLOG_ERR, 0, p, "Failed to allocate dynamic lock structure");<br /> + <br /> + </code></p></div> + + <p><code>ap_log_*error</code> are now implemented as macros. This means + that it is no longer possible to use <code>#ifdef</code> inside the + argument list of <code>ap_log_*error</code>, as this would cause + undefined behavior according to C99.</p> + + <p>A <code>server_rec</code> pointer must be passed to + <code>ap_log_error()</code> when called after startup. This + was always appropriate, but there are even more limitations with + a <code>NULL</code> <code>server_rec</code> in 2.4 than in + previous releases. Beginning with 2.3.12, the global variable + <code>ap_server_conf</code> can always be used as + the <code>server_rec</code> parameter, as it will be + <code>NULL</code> only when it is valid to pass <code>NULL</code> + to <code>ap_log_error()</code>. <code>ap_server_conf</code> + should be used only when a more appropriate <code>server_rec</code> + is not available.</p> + + <p>Consider the following changes to take advantage of the new + <code>APLOG_TRACE1..8</code> log levels:</p> + <ul> + <li>Check current use of <code>APLOG_DEBUG</code> and + consider if one of the <code>APLOG_TRACEn</code> levels is + more appropriate.</li> + <li>If your module currently has a mechanism for configuring + the amount of debug logging which is performed, consider + eliminating that mechanism and relying on the use of + different <code>APLOG_TRACEn</code> levels. If expensive + trace processing needs to be bypassed depending on the + configured log level, use the <code>APLOGtrace<em>n</em></code> + and <code>APLOGrtrace<em>n</em></code> macros to first check + if tracing is enabled.</li> + </ul> + + <p>Modules sometimes add process id and/or thread id to their log + messages. These ids are now logged by default, so it may not + be necessary for the module to log them explicitly. (Users may + remove them from the error log format, but they can be + instructed to add it back if necessary for problem diagnosis.)</p> + + + <h3><a name="upgrading_byfunction" id="upgrading_byfunction">If your module uses these existing APIs...</a></h3> + + + <dl> + <dt><code>ap_default_type()</code></dt> + <dd>This is no longer available; Content-Type must be configured + explicitly or added by the application.</dd> + + <dt><code>ap_get_server_name()</code></dt> + <dd>If the returned server name is used in a URL, + use <code>ap_get_server_name_for_url()</code> instead. This new + function handles the odd case where the server name is an IPv6 + literal address.</dd> + + <dt><code>ap_get_server_version()</code></dt> + <dd>For logging purposes, where detailed information is + appropriate, use <code>ap_get_server_description()</code>. + When generating output, where the amount of information + should be configurable by ServerTokens, use + <code>ap_get_server_banner()</code>.</dd> + + <dt><code>ap_graceful_stop_signalled()</code></dt> + <dd>Replace with a call + to <code>ap_mpm_query(AP_MPMQ_MPM_STATE)</code> and checking for + state <code>AP_MPMQ_STOPPING</code>.</dd> + + <dt><code>ap_max_daemons_limit</code>, <code>ap_my_generation</code>, + and <code>ap_threads_per_child</code></dt> + <dd>Use <code>ap_mpm_query()</code> query codes + <code>AP_MPMQ_MAX_DAEMON_USED</code>, <code>AP_MPMQ_GENERATION</code>, + and <code>AP_MPMQ_MAX_THREADS</code>, respectively.</dd> + + <dt><code>ap_mpm_query()</code></dt> + <dd>Ensure that it is not used until after the register-hooks + hook has completed. Otherwise, an MPM built as a DSO + would not have had a chance to enable support for this + function.</dd> + + <dt><code>ap_requires()</code></dt> + <dd>The core server now provides better infrastructure for handling + <code class="directive"><a href="../mod/mod_authz_core.html#require">Require</a></code> configuration. + Register an auth provider function for each supported entity using + <code>ap_register_auth_provider()</code>. The function will be + called as necessary during <code class="directive">Require</code> + processing. (Consult bundled modules for detailed examples.)</dd> + + <dt><code>ap_server_conf->process->pool</code> + userdata</dt> + <dd> + Optional: + <ul> + <li>If your module uses this to determine which pass of the + startup hooks is being run, + use <code>ap_state_query(AP_SQ_MAIN_STATE)</code>.</li> + <li>If your module uses this to maintain data across the + unloading and reloading of your module, use + <code>ap_retained_data_create()</code> and + <code>ap_retained_data_get()</code>.</li> + </ul> + </dd> + + <dt><code>apr_global_mutex_create()</code>, + <code>apr_proc_mutex_create()</code></dt> + <dd>Optional: See <code>ap_mutex_register()</code>, + <code>ap_global_mutex_create()</code>, and + <code>ap_proc_mutex_create()</code>; these allow your + mutexes to be configurable with + the <code class="directive"><a href="../mod/core.html#mutex">Mutex</a></code> directive; + you can also remove any configuration mechanisms in your + module for such mutexes + </dd> + + <dt><code>CORE_PRIVATE</code></dt> + <dd>This is now unnecessary and ignored.</dd> + + <dt><code>dav_new_error()</code> + and <code>dav_new_error_tag()</code></dt> + <dd>Previously, these assumed that <code>errno</code> contained + information describing the failure. Now, + an <code>apr_status_t</code> parameter must be provided. Pass + 0/APR_SUCCESS if there is no such error information, or a valid + <code>apr_status_t</code> value otherwise.</dd> + + <dt><code>mpm_default.h</code>, <code>DEFAULT_LOCKFILE</code>, + <code>DEFAULT_THREAD_LIMIT</code>, <code>DEFAULT_PIDLOG</code>, + etc.</dt> + <dd>The header file and most of the default configuration + values set in it are no longer visible to modules. (Most can + still be overridden at build time.) <code>DEFAULT_PIDLOG</code> + and <code>DEFAULT_REL_RUNTIMEDIR</code> are now universally + available via <code>ap_config.h</code>.</dd> + + <dt><code>unixd_config</code></dt> + <dd>This has been renamed to ap_unixd_config.</dd> + + <dt><code>unixd_setup_child()</code></dt> + <dd>This has been renamed to ap_unixd_setup_child(), but most callers + should call the added ap_run_drop_privileges() hook.</dd> + + <dt><code>conn_rec->remote_ip</code> and + <code>conn_rec->remote_addr</code></dt> + <dd>These fields have been renamed in order to distinguish between + the client IP address of the connection and the useragent IP address + of the request (potentially overridden by a load balancer or proxy). + References to either of these fields must be updated with one of the + following options, as appropriate for the module: + <ul> + <li>When you require the IP address of the user agent, which + might be connected directly to the server, or might optionally be + separated from the server by a transparent load balancer or + proxy, use <code>request_rec->useragent_ip</code> and + <code>request_rec->useragent_addr</code>.</li> + <li>When you require the IP address of the client that is + connected directly to the server, which might be the useragent or + might be the load balancer or proxy itself, use + <code>conn_rec->client_ip</code> and + <code>conn_rec->client_addr</code>.</li> + </ul> + </dd> + </dl> + + + <h3><a name="upgrading_byfeature" id="upgrading_byfeature">If your module interfaces with this feature...</a></h3> + + <dl> + <dt>suEXEC</dt> + <dd>Optional: If your module logs an error + when <code>ap_unixd_config.suexec_enabled</code> is 0, + also log the value of the new + field <code>suexec_disabled_reason</code>, which contains an + explanation of why it is not available.</dd> + + <dt>Extended status data in the scoreboard</dt> + <dd>In previous releases, <code>ExtendedStatus</code> had to be + set to <code>On</code>, which in turn required that + mod_status was loaded. In 2.4, just + set <code>ap_extended_status</code> to <code>1</code> in a + pre-config hook and the extended status data will be + available.</dd> + </dl> + + + <h3><a name="upgrading_newfeatures" id="upgrading_newfeatures">Does your module...</a></h3> + + <dl> + <dt>Parse query args</dt> + <dd>Consider if <code>ap_args_to_table()</code> would be + helpful.</dd> + + <dt>Parse form data...</dt> + <dd>Use <code>ap_parse_form_data()</code>.</dd> + + <dt>Check for request header fields <code>Content-Length</code> + and <code>Transfer-Encoding</code> to see if a body was + specified</dt> + <dd>Use <code>ap_request_has_body()</code>.</dd> + + <dt>Implement cleanups which clear pointer variables</dt> + <dd>Use <code>ap_pool_cleanup_set_null()</code>.</dd> + + <dt>Create run-time files such as shared memory files, pid files, + etc.</dt> + <dd>Use <code>ap_runtime_dir_relative()</code> so that the global + configuration for the location of such files, either by the + <code>DEFAULT_REL_RUNTIMEDIR</code> compile setting or the + <code class="directive"><a href="../mod/core.html#defaultruntimedir">DefaultRuntimeDir</a></code> directive, + will be respected. <em>Apache httpd 2.4.2 and above.</em></dd> + + </dl> + + +</div></div> +<div class="bottomlang"> +<p><span>Available Languages: </span><a href="../en/developer/new_api_2_4.html" title="English"> en </a></p> +</div><div class="top"><a href="#page-header"><img src="../images/up.gif" alt="top" /></a></div><div class="section"><h2><a id="comments_section" name="comments_section">Comments</a></h2><div class="warning"><strong>Notice:</strong><br />This is not a Q&A section. Comments placed here should be pointed towards suggestions on improving the documentation or server, and may be removed by our moderators if they are either implemented or considered invalid/off-topic. Questions on how to manage the Apache HTTP Server should be directed at either our IRC channel, #httpd, on Libera.chat, or sent to our <a href="https://httpd.apache.org/lists.html">mailing lists</a>.</div> +<script type="text/javascript"><!--//--><![CDATA[//><!-- +var comments_shortname = 'httpd'; +var comments_identifier = 'http://httpd.apache.org/docs/2.4/developer/new_api_2_4.html'; +(function(w, d) { + if (w.location.hostname.toLowerCase() == "httpd.apache.org") { + d.write('<div id="comments_thread"><\/div>'); + var s = d.createElement('script'); + s.type = 'text/javascript'; + s.async = true; + s.src = 'https://comments.apache.org/show_comments.lua?site=' + comments_shortname + '&page=' + comments_identifier; + (d.getElementsByTagName('head')[0] || d.getElementsByTagName('body')[0]).appendChild(s); + } + else { + d.write('<div id="comments_thread">Comments are disabled for this page at the moment.<\/div>'); + } +})(window, document); +//--><!]]></script></div><div id="footer"> +<p class="apache">Copyright 2023 The Apache Software Foundation.<br />Licensed under the <a href="http://www.apache.org/licenses/LICENSE-2.0">Apache License, Version 2.0</a>.</p> +<p class="menu"><a href="../mod/">Modules</a> | <a href="../mod/directives.html">Directives</a> | <a href="http://wiki.apache.org/httpd/FAQ">FAQ</a> | <a href="../glossary.html">Glossary</a> | <a href="../sitemap.html">Sitemap</a></p></div><script type="text/javascript"><!--//--><![CDATA[//><!-- +if (typeof(prettyPrint) !== 'undefined') { + prettyPrint(); +} +//--><!]]></script> +</body></html>
\ No newline at end of file diff --git a/docs/manual/developer/output-filters.html b/docs/manual/developer/output-filters.html new file mode 100644 index 0000000..ee632a6 --- /dev/null +++ b/docs/manual/developer/output-filters.html @@ -0,0 +1,5 @@ +# GENERATED FROM XML -- DO NOT EDIT + +URI: output-filters.html.en +Content-Language: en +Content-type: text/html; charset=UTF-8 diff --git a/docs/manual/developer/output-filters.html.en b/docs/manual/developer/output-filters.html.en new file mode 100644 index 0000000..cd5cf8c --- /dev/null +++ b/docs/manual/developer/output-filters.html.en @@ -0,0 +1,585 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd"> +<html xmlns="http://www.w3.org/1999/xhtml" lang="en" xml:lang="en"><head> +<meta content="text/html; charset=UTF-8" http-equiv="Content-Type" /> +<!-- + XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX + This file is generated from xml source: DO NOT EDIT + XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX + --> +<title>Guide to writing output filters - Apache HTTP Server Version 2.4</title> +<link href="../style/css/manual.css" rel="stylesheet" media="all" type="text/css" title="Main stylesheet" /> +<link href="../style/css/manual-loose-100pc.css" rel="alternate stylesheet" media="all" type="text/css" title="No Sidebar - Default font size" /> +<link href="../style/css/manual-print.css" rel="stylesheet" media="print" type="text/css" /><link rel="stylesheet" type="text/css" href="../style/css/prettify.css" /> +<script src="../style/scripts/prettify.min.js" type="text/javascript"> +</script> + +<link href="../images/favicon.ico" rel="shortcut icon" /></head> +<body id="manual-page"><div id="page-header"> +<p class="menu"><a href="../mod/">Modules</a> | <a href="../mod/directives.html">Directives</a> | <a href="http://wiki.apache.org/httpd/FAQ">FAQ</a> | <a href="../glossary.html">Glossary</a> | <a href="../sitemap.html">Sitemap</a></p> +<p class="apache">Apache HTTP Server Version 2.4</p> +<img alt="" src="../images/feather.png" /></div> +<div class="up"><a href="./"><img title="<-" alt="<-" src="../images/left.gif" /></a></div> +<div id="path"> +<a href="http://www.apache.org/">Apache</a> > <a href="http://httpd.apache.org/">HTTP Server</a> > <a href="http://httpd.apache.org/docs/">Documentation</a> > <a href="../">Version 2.4</a> > <a href="./">Developer Documentation</a></div><div id="page-content"><div id="preamble"><h1>Guide to writing output filters</h1> +<div class="toplang"> +<p><span>Available Languages: </span><a href="../en/developer/output-filters.html" title="English"> en </a></p> +</div> + + <p>There are a number of common pitfalls encountered when writing + output filters; this page aims to document best practice for + authors of new or existing filters.</p> + + <p>This document is applicable to both version 2.0 and version 2.2 + of the Apache HTTP Server; it specifically targets + <code>RESOURCE</code>-level or <code>CONTENT_SET</code>-level + filters though some advice is generic to all types of filter.</p> + </div> +<div id="quickview"><a href="https://www.apache.org/foundation/contributing.html" class="badge"><img src="https://www.apache.org/images/SupportApache-small.png" alt="Support Apache!" /></a><ul id="toc"><li><img alt="" src="../images/down.gif" /> <a href="#basics">Filters and bucket brigades</a></li> +<li><img alt="" src="../images/down.gif" /> <a href="#invocation">Filter invocation</a></li> +<li><img alt="" src="../images/down.gif" /> <a href="#brigade">Brigade structure</a></li> +<li><img alt="" src="../images/down.gif" /> <a href="#buckets">Processing buckets</a></li> +<li><img alt="" src="../images/down.gif" /> <a href="#filtering">Filtering brigades</a></li> +<li><img alt="" src="../images/down.gif" /> <a href="#state">Maintaining state</a></li> +<li><img alt="" src="../images/down.gif" /> <a href="#buffer">Buffering buckets</a></li> +<li><img alt="" src="../images/down.gif" /> <a href="#nonblock">Non-blocking bucket reads</a></li> +<li><img alt="" src="../images/down.gif" /> <a href="#rules">Ten rules for output filters</a></li> +<li><img alt="" src="../images/down.gif" /> <a href="#usecase1">Use case: buffering in mod_ratelimit</a></li> +</ul><h3>See also</h3><ul class="seealso"><li><a href="#comments_section">Comments</a></li></ul></div> +<div class="top"><a href="#page-header"><img alt="top" src="../images/up.gif" /></a></div> +<div class="section"> +<h2><a name="basics" id="basics">Filters and bucket brigades</a></h2> + + + <p>Each time a filter is invoked, it is passed a <em>bucket + brigade</em>, containing a sequence of <em>buckets</em> which + represent both data content and metadata. Every bucket has a + <em>bucket type</em>; a number of bucket types are defined and + used by the <code>httpd</code> core modules (and the + <code>apr-util</code> library which provides the bucket brigade + interface), but modules are free to define their own types.</p> + + <div class="note">Output filters must be prepared to process + buckets of non-standard types; with a few exceptions, a filter + need not care about the types of buckets being filtered.</div> + + <p>A filter can tell whether a bucket represents either data or + metadata using the <code>APR_BUCKET_IS_METADATA</code> macro. + Generally, all metadata buckets should be passed down the filter + chain by an output filter. Filters may transform, delete, and + insert data buckets as appropriate.</p> + + <p>There are two metadata bucket types which all filters must pay + attention to: the <code>EOS</code> bucket type, and the + <code>FLUSH</code> bucket type. An <code>EOS</code> bucket + indicates that the end of the response has been reached and no + further buckets need be processed. A <code>FLUSH</code> bucket + indicates that the filter should flush any buffered buckets (if + applicable) down the filter chain immediately.</p> + + <div class="note"><code>FLUSH</code> buckets are sent when the + content generator (or an upstream filter) knows that there may be + a delay before more content can be sent. By passing + <code>FLUSH</code> buckets down the filter chain immediately, + filters ensure that the client is not kept waiting for pending + data longer than necessary.</div> + + <p>Filters can create <code>FLUSH</code> buckets and pass these + down the filter chain if desired. Generating <code>FLUSH</code> + buckets unnecessarily, or too frequently, can harm network + utilisation since it may force large numbers of small packets to + be sent, rather than a small number of larger packets. The + section on <a href="#nonblock">Non-blocking bucket reads</a> + covers a case where filters are encouraged to generate + <code>FLUSH</code> buckets.</p> + + <div class="example"><h3>Example bucket brigade</h3><p><code> + HEAP FLUSH FILE EOS</code></p></div> + + <p>This shows a bucket brigade which may be passed to a filter; it + contains two metadata buckets (<code>FLUSH</code> and + <code>EOS</code>), and two data buckets (<code>HEAP</code> and + <code>FILE</code>).</p> + + </div><div class="top"><a href="#page-header"><img alt="top" src="../images/up.gif" /></a></div> +<div class="section"> +<h2><a name="invocation" id="invocation">Filter invocation</a></h2> + + + <p>For any given request, an output filter might be invoked only + once and be given a single brigade representing the entire response. + It is also possible that the number of times a filter is invoked + for a single response is proportional to the size of the content + being filtered, with the filter being passed a brigade containing + a single bucket each time. Filters must operate correctly in + either case.</p> + + <div class="warning">An output filter which allocates long-lived + memory every time it is invoked may consume memory proportional to + response size. Output filters which need to allocate memory + should do so once per response; see <a href="#state">Maintaining + state</a> below.</div> + + <p>An output filter can distinguish the final invocation for a + given response by the presence of an <code>EOS</code> bucket in + the brigade. Any buckets in the brigade after an EOS should be + ignored.</p> + + <p>An output filter should never pass an empty brigade down the + filter chain. To be defensive, filters should be prepared to + accept an empty brigade, and should return success without passing + this brigade on down the filter chain. The handling of an empty + brigade should have no side effects (such as changing any state + private to the filter).</p> + + <div class="example"><h3>How to handle an empty brigade</h3><pre class="prettyprint lang-c">apr_status_t dummy_filter(ap_filter_t *f, apr_bucket_brigade *bb) +{ + if (APR_BRIGADE_EMPTY(bb)) { + return APR_SUCCESS; + } + ...</pre> +</div> + + </div><div class="top"><a href="#page-header"><img alt="top" src="../images/up.gif" /></a></div> +<div class="section"> +<h2><a name="brigade" id="brigade">Brigade structure</a></h2> + + + <p>A bucket brigade is a doubly-linked list of buckets. The list + is terminated (at both ends) by a <em>sentinel</em> which can be + distinguished from a normal bucket by comparing it with the + pointer returned by <code>APR_BRIGADE_SENTINEL</code>. The list + sentinel is in fact not a valid bucket structure; any attempt to + call normal bucket functions (such as + <code>apr_bucket_read</code>) on the sentinel will have undefined + behaviour (i.e. will crash the process).</p> + + <p>There are a variety of functions and macros for traversing and + manipulating bucket brigades; see the <a href="http://apr.apache.org/docs/apr-util/trunk/group___a_p_r___util___bucket___brigades.html">apr_buckets.h</a> + header for complete coverage. Commonly used macros include:</p> + + <dl> + <dt><code>APR_BRIGADE_FIRST(bb)</code></dt> + <dd>returns the first bucket in brigade bb</dd> + + <dt><code>APR_BRIGADE_LAST(bb)</code></dt> + <dd>returns the last bucket in brigade bb</dd> + + <dt><code>APR_BUCKET_NEXT(e)</code></dt> + <dd>gives the next bucket after bucket e</dd> + + <dt><code>APR_BUCKET_PREV(e)</code></dt> + <dd>gives the bucket before bucket e</dd> + + </dl> + + <p>The <code>apr_bucket_brigade</code> structure itself is + allocated out of a pool, so if a filter creates a new brigade, it + must ensure that memory use is correctly bounded. A filter which + allocates a new brigade out of the request pool + (<code>r->pool</code>) on every invocation, for example, will fall + foul of the <a href="#invocation">warning above</a> concerning + memory use. Such a filter should instead create a brigade on the + first invocation per request, and store that brigade in its <a href="#state">state structure</a>.</p> + + <div class="warning"><p>It is generally never advisable to use + <code>apr_brigade_destroy</code> to "destroy" a brigade unless + you know for certain that the brigade will never be used + again, even then, it should be used rarely. The + memory used by the brigade structure will not be released by + calling this function (since it comes from a pool), but the + associated pool cleanup is unregistered. Using + <code>apr_brigade_destroy</code> can in fact cause memory leaks; + if a "destroyed" brigade contains buckets when its + containing pool is destroyed, those buckets will <em>not</em> be + immediately destroyed.</p> + + <p>In general, filters should use <code>apr_brigade_cleanup</code> + in preference to <code>apr_brigade_destroy</code>.</p></div> + + </div><div class="top"><a href="#page-header"><img alt="top" src="../images/up.gif" /></a></div> +<div class="section"> +<h2><a name="buckets" id="buckets">Processing buckets</a></h2> + + + + <p>When dealing with non-metadata buckets, it is important to + understand that the "<code>apr_bucket *</code>" object is an + abstract <em>representation</em> of data:</p> + + <ol> + <li>The amount of data represented by the bucket may or may not + have a determinate length; for a bucket which represents data of + indeterminate length, the <code>->length</code> field is set to + the value <code>(apr_size_t)-1</code>. For example, buckets of + the <code>PIPE</code> bucket type have an indeterminate length; + they represent the output from a pipe.</li> + + <li>The data represented by a bucket may or may not be mapped + into memory. The <code>FILE</code> bucket type, for example, + represents data stored in a file on disk.</li> + </ol> + + <p>Filters read the data from a bucket using the + <code>apr_bucket_read</code> function. When this function is + invoked, the bucket may <em>morph</em> into a different bucket + type, and may also insert a new bucket into the bucket brigade. + This must happen for buckets which represent data not mapped into + memory.</p> + + <p>To give an example; consider a bucket brigade containing a + single <code>FILE</code> bucket representing an entire file, 24 + kilobytes in size:</p> + + <div class="example"><p><code>FILE(0K-24K)</code></p></div> + + <p>When this bucket is read, it will read a block of data from the + file, morph into a <code>HEAP</code> bucket to represent that + data, and return the data to the caller. It also inserts a new + <code>FILE</code> bucket representing the remainder of the file; + after the <code>apr_bucket_read</code> call, the brigade looks + like:</p> + + <div class="example"><p><code>HEAP(8K) FILE(8K-24K)</code></p></div> + + </div><div class="top"><a href="#page-header"><img alt="top" src="../images/up.gif" /></a></div> +<div class="section"> +<h2><a name="filtering" id="filtering">Filtering brigades</a></h2> + + + <p>The basic function of any output filter will be to iterate + through the passed-in brigade and transform (or simply examine) + the content in some manner. The implementation of the iteration + loop is critical to producing a well-behaved output filter.</p> + + <p>Taking an example which loops through the entire brigade as + follows:</p> + + <div class="example"><h3>Bad output filter -- do not imitate!</h3><pre class="prettyprint lang-c">apr_bucket *e = APR_BRIGADE_FIRST(bb); +const char *data; +apr_size_t length; + +while (e != APR_BRIGADE_SENTINEL(bb)) { + apr_bucket_read(e, &data, &length, APR_BLOCK_READ); + e = APR_BUCKET_NEXT(e); +} + +return ap_pass_brigade(bb);</pre> +</div> + + <p>The above implementation would consume memory proportional to + content size. If passed a <code>FILE</code> bucket, for example, + the entire file contents would be read into memory as each + <code>apr_bucket_read</code> call morphed a <code>FILE</code> + bucket into a <code>HEAP</code> bucket.</p> + + <p>In contrast, the implementation below will consume a fixed + amount of memory to filter any brigade; a temporary brigade is + needed and must be allocated only once per response, see the <a href="#state">Maintaining state</a> section.</p> + + <div class="example"><h3>Better output filter</h3><pre class="prettyprint lang-c">apr_bucket *e; +const char *data; +apr_size_t length; + +while ((e = APR_BRIGADE_FIRST(bb)) != APR_BRIGADE_SENTINEL(bb)) { + rv = apr_bucket_read(e, &data, &length, APR_BLOCK_READ); + if (rv) ...; + /* Remove bucket e from bb. */ + APR_BUCKET_REMOVE(e); + /* Insert it into temporary brigade. */ + APR_BRIGADE_INSERT_HEAD(tmpbb, e); + /* Pass brigade downstream. */ + rv = ap_pass_brigade(f->next, tmpbb); + if (rv) ...; + apr_brigade_cleanup(tmpbb); +}</pre> +</div> + + </div><div class="top"><a href="#page-header"><img alt="top" src="../images/up.gif" /></a></div> +<div class="section"> +<h2><a name="state" id="state">Maintaining state</a></h2> + + + + <p>A filter which needs to maintain state over multiple + invocations per response can use the <code>->ctx</code> field of + its <code>ap_filter_t</code> structure. It is typical to store a + temporary brigade in such a structure, to avoid having to allocate + a new brigade per invocation as described in the <a href="#brigade">Brigade structure</a> section.</p> + + <div class="example"><h3>Example code to maintain filter state</h3><pre class="prettyprint lang-c">struct dummy_state { + apr_bucket_brigade *tmpbb; + int filter_state; + ... +}; + +apr_status_t dummy_filter(ap_filter_t *f, apr_bucket_brigade *bb) +{ + struct dummy_state *state; + + state = f->ctx; + if (state == NULL) { + + /* First invocation for this response: initialise state structure. + */ + f->ctx = state = apr_palloc(f->r->pool, sizeof *state); + + state->tmpbb = apr_brigade_create(f->r->pool, f->c->bucket_alloc); + state->filter_state = ...; + } + ...</pre> +</div> + + </div><div class="top"><a href="#page-header"><img alt="top" src="../images/up.gif" /></a></div> +<div class="section"> +<h2><a name="buffer" id="buffer">Buffering buckets</a></h2> + + + <p>If a filter decides to store buckets beyond the duration of a + single filter function invocation (for example storing them in its + <code>->ctx</code> state structure), those buckets must be <em>set + aside</em>. This is necessary because some bucket types provide + buckets which represent temporary resources (such as stack memory) + which will fall out of scope as soon as the filter chain completes + processing the brigade.</p> + + <p>To setaside a bucket, the <code>apr_bucket_setaside</code> + function can be called. Not all bucket types can be setaside, but + if successful, the bucket will have morphed to ensure it has a + lifetime at least as long as the pool given as an argument to the + <code>apr_bucket_setaside</code> function.</p> + + <p>Alternatively, the <code>ap_save_brigade</code> function can be + used, which will move all the buckets into a separate brigade + containing buckets with a lifetime as long as the given pool + argument. This function must be used with care, taking into + account the following points:</p> + + <ol> + <li>On return, <code>ap_save_brigade</code> guarantees that all + the buckets in the returned brigade will represent data mapped + into memory. If given an input brigade containing, for example, + a <code>PIPE</code> bucket, <code>ap_save_brigade</code> will + consume an arbitrary amount of memory to store the entire output + of the pipe.</li> + + <li>When <code>ap_save_brigade</code> reads from buckets which + cannot be setaside, it will always perform blocking reads, + removing the opportunity to use <a href="#nonblock">Non-blocking + bucket reads</a>.</li> + + <li>If <code>ap_save_brigade</code> is used without passing a + non-NULL "<code>saveto</code>" (destination) brigade parameter, + the function will create a new brigade, which may cause memory + use to be proportional to content size as described in the <a href="#brigade">Brigade structure</a> section.</li> + </ol> + + <div class="warning">Filters must ensure that any buffered data is + processed and passed down the filter chain during the last + invocation for a given response (a brigade containing an EOS + bucket). Otherwise such data will be lost.</div> + + </div><div class="top"><a href="#page-header"><img alt="top" src="../images/up.gif" /></a></div> +<div class="section"> +<h2><a name="nonblock" id="nonblock">Non-blocking bucket reads</a></h2> + + + <p>The <code>apr_bucket_read</code> function takes an + <code>apr_read_type_e</code> argument which determines whether a + <em>blocking</em> or <em>non-blocking</em> read will be performed + from the data source. A good filter will first attempt to read + from every data bucket using a non-blocking read; if that fails + with <code>APR_EAGAIN</code>, then send a <code>FLUSH</code> + bucket down the filter chain, and retry using a blocking read.</p> + + <p>This mode of operation ensures that any filters further down the + filter chain will flush any buffered buckets if a slow content + source is being used.</p> + + <p>A CGI script is an example of a slow content source which is + implemented as a bucket type. <code class="module"><a href="../mod/mod_cgi.html">mod_cgi</a></code> will send + <code>PIPE</code> buckets which represent the output from a CGI + script; reading from such a bucket will block when waiting for the + CGI script to produce more output.</p> + + <div class="example"><h3>Example code using non-blocking bucket reads</h3><pre class="prettyprint lang-c">apr_bucket *e; +apr_read_type_e mode = APR_NONBLOCK_READ; + +while ((e = APR_BRIGADE_FIRST(bb)) != APR_BRIGADE_SENTINEL(bb)) { + apr_status_t rv; + + rv = apr_bucket_read(e, &data, &length, mode); + if (rv == APR_EAGAIN && mode == APR_NONBLOCK_READ) { + + /* Pass down a brigade containing a flush bucket: */ + APR_BRIGADE_INSERT_TAIL(tmpbb, apr_bucket_flush_create(...)); + rv = ap_pass_brigade(f->next, tmpbb); + apr_brigade_cleanup(tmpbb); + if (rv != APR_SUCCESS) return rv; + + /* Retry, using a blocking read. */ + mode = APR_BLOCK_READ; + continue; + } + else if (rv != APR_SUCCESS) { + /* handle errors */ + } + + /* Next time, try a non-blocking read first. */ + mode = APR_NONBLOCK_READ; + ... +}</pre> +</div> + + </div><div class="top"><a href="#page-header"><img alt="top" src="../images/up.gif" /></a></div> +<div class="section"> +<h2><a name="rules" id="rules">Ten rules for output filters</a></h2> + + + <p>In summary, here is a set of rules for all output filters to + follow:</p> + + <ol> + <li>Output filters should not pass empty brigades down the filter + chain, but should be tolerant of being passed empty + brigades.</li> + + <li>Output filters must pass all metadata buckets down the filter + chain; <code>FLUSH</code> buckets should be respected by passing + any pending or buffered buckets down the filter chain.</li> + + <li>Output filters should ignore any buckets following an + <code>EOS</code> bucket.</li> + + <li>Output filters must process a fixed amount of data at a + time, to ensure that memory consumption is not proportional to + the size of the content being filtered.</li> + + <li>Output filters should be agnostic with respect to bucket + types, and must be able to process buckets of unfamiliar + type.</li> + + <li>After calling <code>ap_pass_brigade</code> to pass a brigade + down the filter chain, output filters should call + <code>apr_brigade_cleanup</code> to ensure the brigade is empty + before reusing that brigade structure; output filters should + never use <code>apr_brigade_destroy</code> to "destroy" + brigades.</li> + + <li>Output filters must <em>setaside</em> any buckets which are + preserved beyond the duration of the filter function.</li> + + <li>Output filters must not ignore the return value of + <code>ap_pass_brigade</code>, and must return appropriate errors + back up the filter chain.</li> + + <li>Output filters must only create a fixed number of bucket + brigades for each response, rather than one per invocation.</li> + + <li>Output filters should first attempt non-blocking reads from + each data bucket, and send a <code>FLUSH</code> bucket down the + filter chain if the read blocks, before retrying with a blocking + read.</li> + + </ol> + + </div><div class="top"><a href="#page-header"><img alt="top" src="../images/up.gif" /></a></div> +<div class="section"> +<h2><a name="usecase1" id="usecase1">Use case: buffering in mod_ratelimit</a></h2> + + <p>The <a href="http://svn.apache.org/r1833875">r1833875</a> change is a good + example to show what buffering and keeping state means in the context of an + output filter. In this use case, a user asked on the users' mailing list a + interesting question about why <code class="module"><a href="../mod/mod_ratelimit.html">mod_ratelimit</a></code> seemed not to + honor its setting with proxied content (either rate limiting at a different + speed or simply not doing it at all). Before diving deep into the solution, + it is better to explain on a high level how <code class="module"><a href="../mod/mod_ratelimit.html">mod_ratelimit</a></code> works. + The trick is really simple: take the rate limit settings and calculate a + chunk size of data to flush every 200ms to the client. For example, let's imagine + that to set <code>rate-limit 60</code> in our config, these are the high level + steps to find the chunk size:</p> + <pre class="prettyprint lang-c">/* milliseconds to wait between each flush of data */ +RATE_INTERVAL_MS = 200; +/* rate limit speed in b/s */ +speed = 60 * 1024; +/* final chunk size is 12228 bytes */ +chunk_size = (speed / (1000 / RATE_INTERVAL_MS));</pre> + + <p>If we apply this calculation to a bucket brigade carrying 38400 bytes, it means + that the filter will try to do the following:</p> + <ol> + <li>Split the 38400 bytes in chunks of maximum 12228 bytes each.</li> + <li>Flush the first 12228 chunk of bytes and sleep 200ms.</li> + <li>Flush the second 12228 chunk of bytes and sleep 200ms.</li> + <li>Flush the third 12228 chunk of bytes and sleep 200ms.</li> + <li>Flush the remaining 1716 bytes.</li> + </ol> + <p>The above pseudo code works fine if the output filter handles only one brigade + for each response, but it might happen that it needs to be called multiple times + with different brigade sizes as well. The former use case is for example when + httpd directly serves some content, like a static file: the bucket brigade + abstraction takes care of handling the whole content, and rate limiting + works nicely. But if the same static content is served via mod_proxy_http (for + example a backend is serving it rather than httpd) then the content generator + (in this case mod_proxy_http) may use a maximum buffer size and then send data + as bucket brigades to the output filters chain regularly, triggering of course + multiple calls to <code class="module"><a href="../mod/mod_ratelimit.html">mod_ratelimit</a></code>. If the reader tries to execute the pseudo code + assuming multiple calls to the output filter, each one requiring to process + a bucket brigade of 38400 bytes, then it is easy to spot some + anomalies:</p> + <ol> + <li>Between the last flush of a brigade and the first one of the next, + there is no sleep.</li> + <li>Even if the sleep was forced after the last flush, then that chunk size + would not be the ideal size (1716 bytes instead of 12228) and the final client's speed + would quickly become different than what set in the httpd's config.</li> + </ol> + <p>In this case, two things might help:</p> + <ol> + <li>Use the ctx internal data structure, initialized by <code class="module"><a href="../mod/mod_ratelimit.html">mod_ratelimit</a></code> + for each response handling cycle, to "remember" when the last sleep was + performed across multiple invocations, and act accordingly.</li> + <li>If a bucket brigade is not splittable into a finite number of chunk_size + blocks, store the remaining bytes (located in the tail of the bucket brigade) + in a temporary holding area (namely another bucket brigade) and then use + <code>ap_save_brigade</code> to set them aside. + These bytes will be prepended to the next bucket brigade that will be handled + in the subsequent invocation.</li> + <li>Avoid the previous logic if the bucket brigade that is currently being + processed contains the end of stream bucket (EOS). There is no need to sleep + or buffering data if the end of stream is reached.</li> + </ol> + <p>The commit linked in the beginning of the section contains also a bit of code + refactoring so it is not trivial to read during the first pass, but the overall + idea is basically what written up to now. The goal of this section is not to + cause a headache to the reader trying to read C code, but to put him/her into + the right mindset needed to use efficiently the tools offered by the httpd's + filter chain toolset.</p> + </div></div> +<div class="bottomlang"> +<p><span>Available Languages: </span><a href="../en/developer/output-filters.html" title="English"> en </a></p> +</div><div class="top"><a href="#page-header"><img src="../images/up.gif" alt="top" /></a></div><div class="section"><h2><a id="comments_section" name="comments_section">Comments</a></h2><div class="warning"><strong>Notice:</strong><br />This is not a Q&A section. Comments placed here should be pointed towards suggestions on improving the documentation or server, and may be removed by our moderators if they are either implemented or considered invalid/off-topic. Questions on how to manage the Apache HTTP Server should be directed at either our IRC channel, #httpd, on Libera.chat, or sent to our <a href="https://httpd.apache.org/lists.html">mailing lists</a>.</div> +<script type="text/javascript"><!--//--><![CDATA[//><!-- +var comments_shortname = 'httpd'; +var comments_identifier = 'http://httpd.apache.org/docs/2.4/developer/output-filters.html'; +(function(w, d) { + if (w.location.hostname.toLowerCase() == "httpd.apache.org") { + d.write('<div id="comments_thread"><\/div>'); + var s = d.createElement('script'); + s.type = 'text/javascript'; + s.async = true; + s.src = 'https://comments.apache.org/show_comments.lua?site=' + comments_shortname + '&page=' + comments_identifier; + (d.getElementsByTagName('head')[0] || d.getElementsByTagName('body')[0]).appendChild(s); + } + else { + d.write('<div id="comments_thread">Comments are disabled for this page at the moment.<\/div>'); + } +})(window, document); +//--><!]]></script></div><div id="footer"> +<p class="apache">Copyright 2023 The Apache Software Foundation.<br />Licensed under the <a href="http://www.apache.org/licenses/LICENSE-2.0">Apache License, Version 2.0</a>.</p> +<p class="menu"><a href="../mod/">Modules</a> | <a href="../mod/directives.html">Directives</a> | <a href="http://wiki.apache.org/httpd/FAQ">FAQ</a> | <a href="../glossary.html">Glossary</a> | <a href="../sitemap.html">Sitemap</a></p></div><script type="text/javascript"><!--//--><![CDATA[//><!-- +if (typeof(prettyPrint) !== 'undefined') { + prettyPrint(); +} +//--><!]]></script> +</body></html>
\ No newline at end of file diff --git a/docs/manual/developer/request.html b/docs/manual/developer/request.html new file mode 100644 index 0000000..92c1bee --- /dev/null +++ b/docs/manual/developer/request.html @@ -0,0 +1,5 @@ +# GENERATED FROM XML -- DO NOT EDIT + +URI: request.html.en +Content-Language: en +Content-type: text/html; charset=UTF-8 diff --git a/docs/manual/developer/request.html.en b/docs/manual/developer/request.html.en new file mode 100644 index 0000000..2ea780d --- /dev/null +++ b/docs/manual/developer/request.html.en @@ -0,0 +1,248 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd"> +<html xmlns="http://www.w3.org/1999/xhtml" lang="en" xml:lang="en"><head> +<meta content="text/html; charset=UTF-8" http-equiv="Content-Type" /> +<!-- + XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX + This file is generated from xml source: DO NOT EDIT + XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX + --> +<title>Request Processing in the Apache HTTP Server 2.x - Apache HTTP Server Version 2.4</title> +<link href="../style/css/manual.css" rel="stylesheet" media="all" type="text/css" title="Main stylesheet" /> +<link href="../style/css/manual-loose-100pc.css" rel="alternate stylesheet" media="all" type="text/css" title="No Sidebar - Default font size" /> +<link href="../style/css/manual-print.css" rel="stylesheet" media="print" type="text/css" /><link rel="stylesheet" type="text/css" href="../style/css/prettify.css" /> +<script src="../style/scripts/prettify.min.js" type="text/javascript"> +</script> + +<link href="../images/favicon.ico" rel="shortcut icon" /></head> +<body id="manual-page"><div id="page-header"> +<p class="menu"><a href="../mod/">Modules</a> | <a href="../mod/directives.html">Directives</a> | <a href="http://wiki.apache.org/httpd/FAQ">FAQ</a> | <a href="../glossary.html">Glossary</a> | <a href="../sitemap.html">Sitemap</a></p> +<p class="apache">Apache HTTP Server Version 2.4</p> +<img alt="" src="../images/feather.png" /></div> +<div class="up"><a href="./"><img title="<-" alt="<-" src="../images/left.gif" /></a></div> +<div id="path"> +<a href="http://www.apache.org/">Apache</a> > <a href="http://httpd.apache.org/">HTTP Server</a> > <a href="http://httpd.apache.org/docs/">Documentation</a> > <a href="../">Version 2.4</a> > <a href="./">Developer Documentation</a></div><div id="page-content"><div id="preamble"><h1>Request Processing in the Apache HTTP Server 2.x</h1> +<div class="toplang"> +<p><span>Available Languages: </span><a href="../en/developer/request.html" title="English"> en </a></p> +</div> + + <div class="warning"><h3>Warning</h3> + <p>Warning - this is a first (fast) draft that needs further + revision!</p> + </div> + + <p>Several changes in 2.0 and above affect the internal request + processing mechanics. Module authors need to be aware of these + changes so they may take advantage of the optimizations and + security enhancements.</p> + + <p>The first major change is to the subrequest and redirect + mechanisms. There were a number of different code paths in + the Apache HTTP Server 1.3 to attempt to optimize subrequest + or redirect behavior. As patches were introduced to 2.0, these + optimizations (and the server behavior) were quickly broken due + to this duplication of code. All duplicate code has been folded + back into <code>ap_process_request_internal()</code> to prevent + the code from falling out of sync again.</p> + + <p>This means that much of the existing code was 'unoptimized'. + It is the Apache HTTP Project's first goal to create a robust + and correct implementation of the HTTP server RFC. Additional + goals include security, scalability and optimization. New + methods were sought to optimize the server (beyond the + performance of 1.3) without introducing fragile or + insecure code.</p> +</div> +<div id="quickview"><a href="https://www.apache.org/foundation/contributing.html" class="badge"><img src="https://www.apache.org/images/SupportApache-small.png" alt="Support Apache!" /></a><ul id="toc"><li><img alt="" src="../images/down.gif" /> <a href="#processing">The Request Processing Cycle</a></li> +<li><img alt="" src="../images/down.gif" /> <a href="#parsing">The Request Parsing Phase</a></li> +<li><img alt="" src="../images/down.gif" /> <a href="#security">The Security Phase</a></li> +<li><img alt="" src="../images/down.gif" /> <a href="#preparation">The Preparation Phase</a></li> +<li><img alt="" src="../images/down.gif" /> <a href="#handler">The Handler Phase</a></li> +</ul><h3>See also</h3><ul class="seealso"><li><a href="#comments_section">Comments</a></li></ul></div> +<div class="top"><a href="#page-header"><img alt="top" src="../images/up.gif" /></a></div> +<div class="section"> +<h2><a name="processing" id="processing">The Request Processing Cycle</a></h2> + <p>All requests pass through <code>ap_process_request_internal()</code> + in <code>server/request.c</code>, including subrequests and redirects. If a module + doesn't pass generated requests through this code, the author is cautioned + that the module may be broken by future changes to request + processing.</p> + + <p>To streamline requests, the module author can take advantage + of the <a href="./modguide.html#hooking">hooks offered</a> to drop + out of the request cycle early, or to bypass core hooks which are + irrelevant (and costly in terms of CPU.)</p> +</div><div class="top"><a href="#page-header"><img alt="top" src="../images/up.gif" /></a></div> +<div class="section"> +<h2><a name="parsing" id="parsing">The Request Parsing Phase</a></h2> + <h3><a name="unescape" id="unescape">Unescapes the URL</a></h3> + <p>The request's <code>parsed_uri</code> path is unescaped, once and only + once, at the beginning of internal request processing.</p> + + <p>This step is bypassed if the proxyreq flag is set, or the + <code>parsed_uri.path</code> element is unset. The module has no further + control of this one-time unescape operation, either failing to + unescape or multiply unescaping the URL leads to security + repercussions.</p> + + + <h3><a name="strip" id="strip">Strips Parent and This Elements from the + URI</a></h3> + <p>All <code>/../</code> and <code>/./</code> elements are + removed by <code>ap_getparents()</code>, as well as any trailing + <code>/.</code> or <code>/..</code> element. This helps to ensure + the path is (nearly) absolute before the request processing + continues. (See RFC 1808 section 4 for further discussion.)</p> + + <p>This step cannot be bypassed.</p> + + + <h3><a name="inital-location-walk" id="inital-location-walk">Initial URI Location Walk</a></h3> + <p>Every request is subject to an + <code>ap_location_walk()</code> call. This ensures that + <code class="directive"><a href="../mod/core.html#location"><Location></a></code> sections + are consistently enforced for all requests. If the request is an internal + redirect or a sub-request, it may borrow some or all of the processing + from the previous or parent request's ap_location_walk, so this step + is generally very efficient after processing the main request.</p> + + + <h3><a name="translate_name" id="translate_name">translate_name</a></h3> + <p>Modules can determine the file name, or alter the given URI + in this step. For example, <code class="module"><a href="../mod/mod_vhost_alias.html">mod_vhost_alias</a></code> will + translate the URI's path into the configured virtual host, + <code class="module"><a href="../mod/mod_alias.html">mod_alias</a></code> will translate the path to an alias path, + and if the request falls back on the core, the <code class="directive"><a href="../mod/core.html#documentroot">DocumentRoot</a></code> is prepended to the request resource.</p> + + <p>If all modules <code>DECLINE</code> this phase, an error 500 is + returned to the browser, and a "couldn't translate name" error is logged + automatically.</p> + + + <h3><a name="map_to_storage" id="map_to_storage">Hook: map_to_storage</a></h3> + <p>After the file or correct URI was determined, the + appropriate per-dir configurations are merged together. For + example, <code class="module"><a href="../mod/mod_proxy.html">mod_proxy</a></code> compares and merges the appropriate + <code class="directive"><a href="../mod/mod_proxy.html#proxy"><Proxy></a></code> sections. + If the URI is nothing more than a local (non-proxy) <code>TRACE</code> + request, the core handles the request and returns <code>DONE</code>. + If no module answers this hook with <code>OK</code> or <code>DONE</code>, + the core will run the request filename against the <code class="directive"><a href="../mod/core.html#directory"><Directory></a></code> and <code class="directive"><a href="../mod/core.html#files"><Files></a></code> sections. If the request + 'filename' isn't an absolute, legal filename, a note is set for + later termination.</p> + + + <h3><a name="location-walk" id="location-walk">URI Location Walk</a></h3> + <p>Every request is hardened by a second + <code>ap_location_walk()</code> call. This reassures that a + translated request is still subjected to the configured + <code class="directive"><a href="../mod/core.html#location"><Location></a></code> sections. + The request again borrows some or all of the processing from its previous + <code>location_walk</code> above, so this step is almost always very + efficient unless the translated URI mapped to a substantially different + path or Virtual Host.</p> + + + <h3><a name="header_parser" id="header_parser">Hook: header_parser</a></h3> + <p>The main request then parses the client's headers. This + prepares the remaining request processing steps to better serve + the client's request.</p> + +</div><div class="top"><a href="#page-header"><img alt="top" src="../images/up.gif" /></a></div> +<div class="section"> +<h2><a name="security" id="security">The Security Phase</a></h2> + <p>Needs Documentation. Code is:</p> + + <pre class="prettyprint lang-c">if ((access_status = ap_run_access_checker(r)) != 0) { + return decl_die(access_status, "check access", r); +} + +if ((access_status = ap_run_check_user_id(r)) != 0) { + return decl_die(access_status, "check user", r); +} + +if ((access_status = ap_run_auth_checker(r)) != 0) { + return decl_die(access_status, "check authorization", r); +}</pre> + +</div><div class="top"><a href="#page-header"><img alt="top" src="../images/up.gif" /></a></div> +<div class="section"> +<h2><a name="preparation" id="preparation">The Preparation Phase</a></h2> + <h3><a name="type_checker" id="type_checker">Hook: type_checker</a></h3> + <p>The modules have an opportunity to test the URI or filename + against the target resource, and set mime information for the + request. Both <code class="module"><a href="../mod/mod_mime.html">mod_mime</a></code> and + <code class="module"><a href="../mod/mod_mime_magic.html">mod_mime_magic</a></code> use this phase to compare the file + name or contents against the administrator's configuration and set the + content type, language, character set and request handler. Some modules + may set up their filters or other request handling parameters at this + time.</p> + + <p>If all modules <code>DECLINE</code> this phase, an error 500 is + returned to the browser, and a "couldn't find types" error is logged + automatically.</p> + + + <h3><a name="fixups" id="fixups">Hook: fixups</a></h3> + <p>Many modules are 'trounced' by some phase above. The fixups + phase is used by modules to 'reassert' their ownership or force + the request's fields to their appropriate values. It isn't + always the cleanest mechanism, but occasionally it's the only + option.</p> + +</div><div class="top"><a href="#page-header"><img alt="top" src="../images/up.gif" /></a></div> +<div class="section"> +<h2><a name="handler" id="handler">The Handler Phase</a></h2> + <p>This phase is <strong>not</strong> part of the processing in + <code>ap_process_request_internal()</code>. Many + modules prepare one or more subrequests prior to creating any + content at all. After the core, or a module calls + <code>ap_process_request_internal()</code> it then calls + <code>ap_invoke_handler()</code> to generate the request.</p> + + <h3><a name="insert_filter" id="insert_filter">Hook: insert_filter</a></h3> + <p>Modules that transform the content in some way can insert + their values and override existing filters, such that if the + user configured a more advanced filter out-of-order, then the + module can move its order as need be. There is no result code, + so actions in this hook better be trusted to always succeed.</p> + + + <h3><a name="hook_handler" id="hook_handler">Hook: handler</a></h3> + <p>The module finally has a chance to serve the request in its + handler hook. Note that not every prepared request is sent to + the handler hook. Many modules, such as <code class="module"><a href="../mod/mod_autoindex.html">mod_autoindex</a></code>, + will create subrequests for a given URI, and then never serve the + subrequest, but simply lists it for the user. Remember not to + put required teardown from the hooks above into this module, + but register pool cleanups against the request pool to free + resources as required.</p> + +</div></div> +<div class="bottomlang"> +<p><span>Available Languages: </span><a href="../en/developer/request.html" title="English"> en </a></p> +</div><div class="top"><a href="#page-header"><img src="../images/up.gif" alt="top" /></a></div><div class="section"><h2><a id="comments_section" name="comments_section">Comments</a></h2><div class="warning"><strong>Notice:</strong><br />This is not a Q&A section. Comments placed here should be pointed towards suggestions on improving the documentation or server, and may be removed by our moderators if they are either implemented or considered invalid/off-topic. Questions on how to manage the Apache HTTP Server should be directed at either our IRC channel, #httpd, on Libera.chat, or sent to our <a href="https://httpd.apache.org/lists.html">mailing lists</a>.</div> +<script type="text/javascript"><!--//--><![CDATA[//><!-- +var comments_shortname = 'httpd'; +var comments_identifier = 'http://httpd.apache.org/docs/2.4/developer/request.html'; +(function(w, d) { + if (w.location.hostname.toLowerCase() == "httpd.apache.org") { + d.write('<div id="comments_thread"><\/div>'); + var s = d.createElement('script'); + s.type = 'text/javascript'; + s.async = true; + s.src = 'https://comments.apache.org/show_comments.lua?site=' + comments_shortname + '&page=' + comments_identifier; + (d.getElementsByTagName('head')[0] || d.getElementsByTagName('body')[0]).appendChild(s); + } + else { + d.write('<div id="comments_thread">Comments are disabled for this page at the moment.<\/div>'); + } +})(window, document); +//--><!]]></script></div><div id="footer"> +<p class="apache">Copyright 2023 The Apache Software Foundation.<br />Licensed under the <a href="http://www.apache.org/licenses/LICENSE-2.0">Apache License, Version 2.0</a>.</p> +<p class="menu"><a href="../mod/">Modules</a> | <a href="../mod/directives.html">Directives</a> | <a href="http://wiki.apache.org/httpd/FAQ">FAQ</a> | <a href="../glossary.html">Glossary</a> | <a href="../sitemap.html">Sitemap</a></p></div><script type="text/javascript"><!--//--><![CDATA[//><!-- +if (typeof(prettyPrint) !== 'undefined') { + prettyPrint(); +} +//--><!]]></script> +</body></html>
\ No newline at end of file diff --git a/docs/manual/developer/thread_safety.html b/docs/manual/developer/thread_safety.html new file mode 100644 index 0000000..8196302 --- /dev/null +++ b/docs/manual/developer/thread_safety.html @@ -0,0 +1,5 @@ +# GENERATED FROM XML -- DO NOT EDIT + +URI: thread_safety.html.en +Content-Language: en +Content-type: text/html; charset=UTF-8 diff --git a/docs/manual/developer/thread_safety.html.en b/docs/manual/developer/thread_safety.html.en new file mode 100644 index 0000000..7e842d8 --- /dev/null +++ b/docs/manual/developer/thread_safety.html.en @@ -0,0 +1,307 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd"> +<html xmlns="http://www.w3.org/1999/xhtml" lang="en" xml:lang="en"><head> +<meta content="text/html; charset=UTF-8" http-equiv="Content-Type" /> +<!-- + XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX + This file is generated from xml source: DO NOT EDIT + XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX + --> +<title>Apache HTTP Server 2.x Thread Safety Issues - Apache HTTP Server Version 2.4</title> +<link href="../style/css/manual.css" rel="stylesheet" media="all" type="text/css" title="Main stylesheet" /> +<link href="../style/css/manual-loose-100pc.css" rel="alternate stylesheet" media="all" type="text/css" title="No Sidebar - Default font size" /> +<link href="../style/css/manual-print.css" rel="stylesheet" media="print" type="text/css" /><link rel="stylesheet" type="text/css" href="../style/css/prettify.css" /> +<script src="../style/scripts/prettify.min.js" type="text/javascript"> +</script> + +<link href="../images/favicon.ico" rel="shortcut icon" /></head> +<body id="manual-page"><div id="page-header"> +<p class="menu"><a href="../mod/">Modules</a> | <a href="../mod/directives.html">Directives</a> | <a href="http://wiki.apache.org/httpd/FAQ">FAQ</a> | <a href="../glossary.html">Glossary</a> | <a href="../sitemap.html">Sitemap</a></p> +<p class="apache">Apache HTTP Server Version 2.4</p> +<img alt="" src="../images/feather.png" /></div> +<div class="up"><a href="./"><img title="<-" alt="<-" src="../images/left.gif" /></a></div> +<div id="path"> +<a href="http://www.apache.org/">Apache</a> > <a href="http://httpd.apache.org/">HTTP Server</a> > <a href="http://httpd.apache.org/docs/">Documentation</a> > <a href="../">Version 2.4</a> > <a href="./">Developer Documentation</a></div><div id="page-content"><div id="preamble"><h1>Apache HTTP Server 2.x Thread Safety Issues</h1> +<div class="toplang"> +<p><span>Available Languages: </span><a href="../en/developer/thread_safety.html" title="English"> en </a></p> +</div> + + <p>When using any of the threaded mpms in the Apache HTTP Server 2.x it is important + that every function called from Apache be thread safe. When linking in 3rd + party extensions it can be difficult to determine whether the resulting + server will be thread safe. Casual testing generally won't tell you this + either as thread safety problems can lead to subtle race conditions that + may only show up in certain conditions under heavy load.</p> +</div> +<div id="quickview"><a href="https://www.apache.org/foundation/contributing.html" class="badge"><img src="https://www.apache.org/images/SupportApache-small.png" alt="Support Apache!" /></a><ul id="toc"><li><img alt="" src="../images/down.gif" /> <a href="#variables">Global and static variables</a></li> +<li><img alt="" src="../images/down.gif" /> <a href="#errno">errno</a></li> +<li><img alt="" src="../images/down.gif" /> <a href="#functions">Common standard troublesome functions</a></li> +<li><img alt="" src="../images/down.gif" /> <a href="#commonlibs">Common 3rd Party Libraries</a></li> +<li><img alt="" src="../images/down.gif" /> <a href="#liblist">Library List</a></li> +</ul><h3>See also</h3><ul class="seealso"><li><a href="#comments_section">Comments</a></li></ul></div> +<div class="top"><a href="#page-header"><img alt="top" src="../images/up.gif" /></a></div> +<div class="section"> +<h2><a name="variables" id="variables">Global and static variables</a></h2> + <p>When writing your module or when trying to determine if a module or + 3rd party library is thread safe there are some common things to keep in + mind.</p> + + <p>First, you need to recognize that in a threaded model each individual + thread has its own program counter, stack and registers. Local variables + live on the stack, so those are fine. You need to watch out for any + static or global variables. This doesn't mean that you are absolutely not + allowed to use static or global variables. There are times when you + actually want something to affect all threads, but generally you need to + avoid using them if you want your code to be thread safe.</p> + + <p>In the case where you have a global variable that needs to be global and + accessed by all threads, be very careful when you update it. If, for + example, it is an incrementing counter, you need to atomically increment + it to avoid race conditions with other threads. You do this using a mutex + (mutual exclusion). Lock the mutex, read the current value, increment it + and write it back and then unlock the mutex. Any other thread that wants + to modify the value has to first check the mutex and block until it is + cleared.</p> + + <p>If you are using <a href="http://apr.apache.org/">APR</a>, have a look + at the <code>apr_atomic_<var>*</var></code> functions and the + <code>apr_thread_mutex_<var>*</var></code> functions.</p> + +</div><div class="top"><a href="#page-header"><img alt="top" src="../images/up.gif" /></a></div> +<div class="section"> +<h2><a name="errno" id="errno">errno</a></h2> + <p>This is a common global variable that holds the error number of the + last error that occurred. If one thread calls a low-level function that + sets errno and then another thread checks it, we are bleeding error + numbers from one thread into another. To solve this, make sure your + module or library defines <code>_REENTRANT</code> or is compiled with + <code>-D_REENTRANT</code>. This will make errno a per-thread variable + and should hopefully be transparent to the code. It does this by doing + something like this:</p> + + <div class="example"><p><code> + #define errno (*(__errno_location())) + </code></p></div> + + <p>which means that accessing errno will call + <code>__errno_location()</code> which is provided by the libc. Setting + <code>_REENTRANT</code> also forces redefinition of some other functions + to their <code><var>*</var>_r</code> equivalents and sometimes changes + the common <code>getc</code>/<code>putc</code> macros into safer function + calls. Check your libc documentation for specifics. Instead of, or in + addition to <code>_REENTRANT</code> the symbols that may affect this are + <code>_POSIX_C_SOURCE</code>, <code>_THREAD_SAFE</code>, + <code>_SVID_SOURCE</code>, and <code>_BSD_SOURCE</code>.</p> +</div><div class="top"><a href="#page-header"><img alt="top" src="../images/up.gif" /></a></div> +<div class="section"> +<h2><a name="functions" id="functions">Common standard troublesome functions</a></h2> + <p>Not only do things have to be thread safe, but they also have to be + reentrant. <code>strtok()</code> is an obvious one. You call it the first + time with your delimiter which it then remembers and on each subsequent + call it returns the next token. Obviously if multiple threads are + calling it you will have a problem. Most systems have a reentrant version + of the function called <code>strtok_r()</code> where you pass in an + extra argument which contains an allocated <code>char *</code> which the + function will use instead of its own static storage for maintaining + the tokenizing state. If you are using <a href="http://apr.apache.org/">APR</a> you can use <code>apr_strtok()</code>.</p> + + <p><code>crypt()</code> is another function that tends to not be reentrant, + so if you run across calls to that function in a library, watch out. On + some systems it is reentrant though, so it is not always a problem. If + your system has <code>crypt_r()</code> chances are you should be using + that, or if possible simply avoid the whole mess by using md5 instead.</p> + +</div><div class="top"><a href="#page-header"><img alt="top" src="../images/up.gif" /></a></div> +<div class="section"> +<h2><a name="commonlibs" id="commonlibs">Common 3rd Party Libraries</a></h2> + <p>The following is a list of common libraries that are used by 3rd party + Apache modules. You can check to see if your module is using a potentially + unsafe library by using tools such as <code>ldd(1)</code> and + <code>nm(1)</code>. For <a href="http://www.php.net/">PHP</a>, for example, + try this:</p> + + <div class="example"><p><code> + % ldd libphp4.so<br /> + libsablot.so.0 => /usr/local/lib/libsablot.so.0 (0x401f6000)<br /> + libexpat.so.0 => /usr/lib/libexpat.so.0 (0x402da000)<br /> + libsnmp.so.0 => /usr/lib/libsnmp.so.0 (0x402f9000)<br /> + libpdf.so.1 => /usr/local/lib/libpdf.so.1 (0x40353000)<br /> + libz.so.1 => /usr/lib/libz.so.1 (0x403e2000)<br /> + libpng.so.2 => /usr/lib/libpng.so.2 (0x403f0000)<br /> + libmysqlclient.so.11 => /usr/lib/libmysqlclient.so.11 (0x40411000)<br /> + libming.so => /usr/lib/libming.so (0x40449000)<br /> + libm.so.6 => /lib/libm.so.6 (0x40487000)<br /> + libfreetype.so.6 => /usr/lib/libfreetype.so.6 (0x404a8000)<br /> + libjpeg.so.62 => /usr/lib/libjpeg.so.62 (0x404e7000)<br /> + libcrypt.so.1 => /lib/libcrypt.so.1 (0x40505000)<br /> + libssl.so.2 => /lib/libssl.so.2 (0x40532000)<br /> + libcrypto.so.2 => /lib/libcrypto.so.2 (0x40560000)<br /> + libresolv.so.2 => /lib/libresolv.so.2 (0x40624000)<br /> + libdl.so.2 => /lib/libdl.so.2 (0x40634000)<br /> + libnsl.so.1 => /lib/libnsl.so.1 (0x40637000)<br /> + libc.so.6 => /lib/libc.so.6 (0x4064b000)<br /> + /lib/ld-linux.so.2 => /lib/ld-linux.so.2 (0x80000000) + </code></p></div> + + <p>In addition to these libraries you will need to have a look at any + libraries linked statically into the module. You can use <code>nm(1)</code> + to look for individual symbols in the module.</p> +</div><div class="top"><a href="#page-header"><img alt="top" src="../images/up.gif" /></a></div> +<div class="section"> +<h2><a name="liblist" id="liblist">Library List</a></h2> + <p>Please drop a note to <a href="http://httpd.apache.org/lists.html#http-dev">dev@httpd.apache.org</a> + if you have additions or corrections to this list.</p> + + <table class="bordered"><tr class="header"><th>Library</th><th>Version</th><th>Thread Safe?</th><th>Notes</th></tr> +<tr><td><a href="http://aspell.sourceforge.net/">ASpell/PSpell</a></td> + <td> </td> + <td>?</td> + <td> </td></tr> +<tr class="odd"><td><a href="http://www.sleepycat.com/">Berkeley DB</a></td> + <td>3.x, 4.x</td> + <td>Yes</td> + <td>Be careful about sharing a connection across threads.</td></tr> +<tr><td><a href="http://sources.redhat.com/bzip2/index.html">bzip2</a></td> + <td> </td> + <td>Yes</td> + <td>Both low-level and high-level APIs are thread-safe. However, + high-level API requires thread-safe access to errno.</td></tr> +<tr class="odd"><td><a href="http://cr.yp.to/cdb.html">cdb</a></td> + <td> </td> + <td>?</td> + <td> </td></tr> +<tr><td><a href="http://www.washington.edu/imap/">C-Client</a></td> + <td> </td> + <td>Perhaps</td> + <td>c-client uses <code>strtok()</code> and + <code>gethostbyname()</code> which are not thread-safe on most C + library implementations. c-client's static data is meant to be shared + across threads. If <code>strtok()</code> and + <code>gethostbyname()</code> are thread-safe on your OS, c-client + <em>may</em> be thread-safe.</td></tr> +<tr class="odd"><td><a href="http://www.ijg.org/files/">libcrypt</a></td> + <td> </td> + <td>?</td> + <td> </td></tr> +<tr><td><a href="http://expat.sourceforge.net/">Expat</a></td> + <td> </td> + <td>Yes</td> + <td>Need a separate parser instance per thread</td></tr> +<tr class="odd"><td><a href="http://www.freetds.org/">FreeTDS</a></td> + <td> </td> + <td>?</td> + <td> </td></tr> +<tr><td><a href="http://www.freetype.org/">FreeType</a></td> + <td> </td> + <td>?</td> + <td> </td></tr> +<tr class="odd"><td><a href="http://www.boutell.com/gd/">GD 1.8.x</a></td> + <td> </td> + <td>?</td> + <td> </td></tr> +<tr><td><a href="http://www.boutell.com/gd/">GD 2.0.x</a></td> + <td> </td> + <td>?</td> + <td> </td></tr> +<tr class="odd"><td><a href="http://www.gnu.org/software/gdbm/gdbm.html">gdbm</a></td> + <td> </td> + <td>No</td> + <td>Errors returned via a static <code>gdbm_error</code> + variable</td></tr> +<tr><td><a href="http://www.imagemagick.org/">ImageMagick</a></td> + <td>5.2.2</td> + <td>Yes</td> + <td>ImageMagick docs claim it is thread safe since version 5.2.2 (see <a href="http://www.imagemagick.com/www/changelog.html">Change log</a>). + </td></tr> +<tr class="odd"><td><a href="http://www.enlightenment.org/p.php?p=about/efl&l=en">Imlib2</a></td> + <td> </td> + <td>?</td> + <td> </td></tr> +<tr><td><a href="http://www.ijg.org/files/">libjpeg</a></td> + <td>v6b</td> + <td>?</td> + <td> </td></tr> +<tr class="odd"><td><a href="http://mysql.com">libmysqlclient</a></td> + <td> </td> + <td>Yes</td> + <td>Use mysqlclient_r library variant to ensure thread-safety. For + more information, please read <a href="http://dev.mysql.com/doc/mysql/en/Threaded_clients.html">http://dev.mysql.com/doc/mysql/en/Threaded_clients.html</a>.</td></tr> +<tr><td><a href="http://www.opaque.net/ming/">Ming</a></td> + <td>0.2a</td> + <td>?</td> + <td> </td></tr> +<tr class="odd"><td><a href="http://net-snmp.sourceforge.net/">Net-SNMP</a></td> + <td>5.0.x</td> + <td>?</td> + <td> </td></tr> +<tr><td><a href="http://www.openldap.org/">OpenLDAP</a></td> + <td>2.1.x</td> + <td>Yes</td> + <td>Use <code>ldap_r</code> library variant to ensure + thread-safety.</td></tr> +<tr class="odd"><td><a href="http://www.openssl.org/">OpenSSL</a></td> + <td>0.9.6g</td> + <td>Yes</td> + <td>Requires proper usage of <code>CRYPTO_num_locks</code>, + <code>CRYPTO_set_locking_callback</code>, + <code>CRYPTO_set_id_callback</code></td></tr> +<tr><td><a href="http://www.oracle.com/">liboci8 (Oracle 8+)</a></td> + <td>8.x,9.x</td> + <td>?</td> + <td> </td></tr> +<tr class="odd"><td><a href="http://pdflib.com/">pdflib</a></td> + <td>5.0.x</td> + <td>Yes</td> + <td>PDFLib docs claim it is thread safe; changes.txt indicates it + has been partially thread-safe since V1.91: <a href="http://www.pdflib.com/products/pdflib-family/pdflib/">http://www.pdflib.com/products/pdflib-family/pdflib/</a>.</td></tr> +<tr><td><a href="http://www.libpng.org/pub/png/libpng.html">libpng</a></td> + <td>1.0.x</td> + <td>?</td> + <td> </td></tr> +<tr class="odd"><td><a href="http://www.libpng.org/pub/png/libpng.html">libpng</a></td> + <td>1.2.x</td> + <td>?</td> + <td> </td></tr> +<tr><td><a href="http://www.postgresql.org/docs/8.4/static/libpq-threading.html">libpq (PostgreSQL)</a></td> + <td>8.x</td> + <td>Yes</td> + <td>Don't share connections across threads and watch out for + <code>crypt()</code> calls</td></tr> +<tr class="odd"><td><a href="http://www.gingerall.com/charlie/ga/xml/p_sab.xml">Sablotron</a></td> + <td>0.95</td> + <td>?</td> + <td /></tr> +<tr><td><a href="http://www.gzip.org/zlib/">zlib</a></td> + <td>1.1.4</td> + <td>Yes</td> + <td>Relies upon thread-safe zalloc and zfree functions Default is to + use libc's calloc/free which are thread-safe.</td></tr> +</table> +</div></div> +<div class="bottomlang"> +<p><span>Available Languages: </span><a href="../en/developer/thread_safety.html" title="English"> en </a></p> +</div><div class="top"><a href="#page-header"><img src="../images/up.gif" alt="top" /></a></div><div class="section"><h2><a id="comments_section" name="comments_section">Comments</a></h2><div class="warning"><strong>Notice:</strong><br />This is not a Q&A section. Comments placed here should be pointed towards suggestions on improving the documentation or server, and may be removed by our moderators if they are either implemented or considered invalid/off-topic. Questions on how to manage the Apache HTTP Server should be directed at either our IRC channel, #httpd, on Libera.chat, or sent to our <a href="https://httpd.apache.org/lists.html">mailing lists</a>.</div> +<script type="text/javascript"><!--//--><![CDATA[//><!-- +var comments_shortname = 'httpd'; +var comments_identifier = 'http://httpd.apache.org/docs/2.4/developer/thread_safety.html'; +(function(w, d) { + if (w.location.hostname.toLowerCase() == "httpd.apache.org") { + d.write('<div id="comments_thread"><\/div>'); + var s = d.createElement('script'); + s.type = 'text/javascript'; + s.async = true; + s.src = 'https://comments.apache.org/show_comments.lua?site=' + comments_shortname + '&page=' + comments_identifier; + (d.getElementsByTagName('head')[0] || d.getElementsByTagName('body')[0]).appendChild(s); + } + else { + d.write('<div id="comments_thread">Comments are disabled for this page at the moment.<\/div>'); + } +})(window, document); +//--><!]]></script></div><div id="footer"> +<p class="apache">Copyright 2023 The Apache Software Foundation.<br />Licensed under the <a href="http://www.apache.org/licenses/LICENSE-2.0">Apache License, Version 2.0</a>.</p> +<p class="menu"><a href="../mod/">Modules</a> | <a href="../mod/directives.html">Directives</a> | <a href="http://wiki.apache.org/httpd/FAQ">FAQ</a> | <a href="../glossary.html">Glossary</a> | <a href="../sitemap.html">Sitemap</a></p></div><script type="text/javascript"><!--//--><![CDATA[//><!-- +if (typeof(prettyPrint) !== 'undefined') { + prettyPrint(); +} +//--><!]]></script> +</body></html>
\ No newline at end of file |