| <?xml version='1.0' encoding='UTF-8' ?> | |
| <!DOCTYPE manualpage SYSTEM "../style/manualpage.dtd"> | |
| <?xml-stylesheet type="text/xsl" href="../style/manual.en.xsl"?> | |
| <!-- $LastChangedRevision$ --> | |
| <!-- | |
| Licensed to the Apache Software Foundation (ASF) under one or more | |
| contributor license agreements. See the NOTICE file distributed with | |
| this work for additional information regarding copyright ownership. | |
| The ASF licenses this file to You under the Apache License, Version 2.0 | |
| (the "License"); you may not use this file except in compliance with | |
| the License. You may obtain a copy of the License at | |
| http://www.apache.org/licenses/LICENSE-2.0 | |
| Unless required by applicable law or agreed to in writing, software | |
| distributed under the License is distributed on an "AS IS" BASIS, | |
| WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | |
| See the License for the specific language governing permissions and | |
| limitations under the License. | |
| --> | |
| <manualpage metafile="modguide.xml.meta"> | |
| <parentdocument href="./">Developer</parentdocument> | |
| <title>Developing modules for the Apache HTTP Server 2.4</title> | |
| <summary> | |
| <p>This document explains how you can develop modules for the Apache HTTP | |
| Server 2.4</p> | |
| </summary> | |
| <seealso><a href="request.html">Request Processing in Apache 2.4</a></seealso> | |
| <seealso><a href="hooks.html">Apache 2.x Hook Functions</a></seealso> | |
| <section id="introduction"><title>Introduction</title> | |
| <section id="what"><title>What we will be discussing in this document</title> | |
| <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> | |
| </section> | |
| <section id="prerequisites"><title>Prerequisites</title> | |
| <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> | |
| </section> | |
| <section id="compiling"><title>Compiling your module</title> | |
| <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> | |
| <example><pre> | |
| apxs -i -a -c mod_example.c | |
| </pre></example> | |
| </section> | |
| </section> | |
| <section id="basics"><title>Defining a module</title> | |
| <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> | |
| <!-- BEGIN EXAMPLE CODE --> | |
| <highlight language="c"> | |
| AP_DECLARE_MODULE(example) = | |
| { | |
| 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 */ | |
| AP_MODULE_FLAG_NONE /* Flags */ | |
| }; | |
| </highlight> | |
| <!-- END EXAMPLE CODE --> | |
| <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 three 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> | |
| <li>Allowing the user to distinguish an origin of log messages</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> | |
| <highlight language="config"> | |
| LoadModule example_module "modules/mod_example.so" | |
| </highlight> | |
| <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> | |
| </section> | |
| <section id="hooking"><title>Getting started: Hooking into the server</title> | |
| <section id="hook_intro"><title>An introduction to hooks</title> | |
| <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 <directive module="mod_mime">AddHandler</directive> | |
| and <directive module="core">SetHandler</directive>. Let's take a look at | |
| an example using <directive module="mod_mime">AddHandler</directive>. 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> | |
| <highlight language="config"> | |
| AddHandler example-handler ".sum" | |
| </highlight> | |
| <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> | |
| </section> | |
| <section id="hook_declaration"><title>Hooking into httpd</title> | |
| <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> | |
| <!-- BEGIN EXAMPLE CODE --> | |
| <highlight language="c"> | |
| AP_DECLARE_MODULE(example) = | |
| { | |
| STANDARD20_MODULE_STUFF, | |
| NULL, | |
| NULL, | |
| NULL, | |
| NULL, | |
| NULL, | |
| register_hooks, /* Our hook registering function */ | |
| AP_MODULE_FLAG_NONE /* Flags */ | |
| }; | |
| </highlight> | |
| <!-- END EXAMPLE CODE --> | |
| <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> | |
| <!-- BEGIN EXAMPLE CODE --> | |
| <highlight language="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); | |
| } | |
| </highlight> | |
| <!-- END EXAMPLE CODE --> | |
| <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> | |
| </section> | |
| <section id="hook_others"><title>Other useful hooks</title> | |
| <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> | |
| </section> | |
| </section> | |
| <section id="handling"><title>Building a handler</title> | |
| <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> | |
| <section id="simple_handler"><title>A simple "Hello, world!" | |
| handler</title> | |
| <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> | |
| <!-- BEGIN EXAMPLE CODE --> | |
| <highlight language="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; | |
| } | |
| </highlight> | |
| <!-- END EXAMPLE CODE --> | |
| <p> | |
| Now, we put all we have learned together and end up with a program that | |
| looks like | |
| <a href="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> | |
| </section> | |
| <section id="request_rec"><title>The request_rec structure</title> | |
| <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> | |
| <!-- BEGIN EXAMPLE CODE --> | |
| <highlight language="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; | |
| } | |
| </highlight> | |
| <!-- END EXAMPLE CODE --> | |
| </section> | |
| <section id="return_value"><title>Return values</title> | |
| <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> | |
| <!-- BEGIN EXAMPLE CODE --> | |
| <highlight language="c"> | |
| static int example_handler(request_rec *r) | |
| { | |
| /* Return 404: Not found */ | |
| return HTTP_NOT_FOUND; | |
| } | |
| </highlight> | |
| <!-- END EXAMPLE CODE --> | |
| <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> | |
| </section> | |
| <section id="functions"><title>Some useful functions you should know</title> | |
| <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>. | |
| <!-- BEGIN EXAMPLE CODE --> | |
| <highlight language="c">ap_rputs("Hello, world!", r);</highlight> | |
| <!-- END EXAMPLE CODE --> | |
| </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. | |
| <!-- BEGIN EXAMPLE CODE --> | |
| <highlight language="c">ap_rprintf(r, "Hello, %s!", r->useragent_ip);</highlight> | |
| <!-- END EXAMPLE CODE --> | |
| </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. | |
| <!-- BEGIN EXAMPLE CODE --> | |
| <highlight language="c">ap_set_content_type(r, "text/plain"); /* force a raw text output */</highlight> | |
| <!-- END EXAMPLE CODE --> | |
| </li> | |
| </ul> | |
| </section> | |
| <section id="memory"><title>Memory management</title> | |
| <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> | |
| <!-- BEGIN EXAMPLE CODE --> | |
| <highlight language="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; | |
| } | |
| </highlight> | |
| <!-- END EXAMPLE CODE --> | |
| <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> | |
| <!-- BEGIN EXAMPLE CODE --> | |
| <highlight language="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); | |
| } | |
| </highlight> | |
| <!-- END EXAMPLE CODE --> | |
| <p> | |
| In this pre-request initialization function we would not be using the | |
| same pool as we did when allocating resources for request-based functions. | |
| Instead, we would use the pool given to us by the server for allocating memory | |
| on a per-process based level. | |
| </p> | |
| </section> | |
| <section id="parsing"><title>Parsing request data</title> | |
| <p> | |
| In our example module, we would like to add a feature, that checks which | |
| type of digest, MD5 or SHA1 the client would like to see. This could be | |
| solved by adding a query string to the request. A query string is typically | |
| comprised of several keys and values put together in a string, for instance | |
| <code>valueA=yes&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> | |
| <!-- BEGIN EXAMPLE CODE --> | |
| <highlight language="c"> | |
| <a href="http://ci.apache.org/projects/httpd/trunk/doxygen/group__apr__tables.html#gad7ea82d6608a4a633fc3775694ab71e4">apr_table_t</a> *GET; <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); | |
| </highlight> | |
| <!-- END EXAMPLE CODE --> | |
| <p> | |
| In our specific example module, we're looking for the <code>digest</code> | |
| value from the query string, which now resides inside a table called <code> | |
| GET</code>. To extract this value, we need only perform a simple operation: | |
| </p> | |
| <!-- BEGIN EXAMPLE CODE --> | |
| <highlight language="c"> | |
| /* Get the "digest" key from the query string, if any. */ | |
| const char *digestType = apr_table_get(GET, "digest"); | |
| /* If no key was returned, we will set a default value instead. */ | |
| if (!digestType) digestType = "sha1"; | |
| </highlight> | |
| <!-- END EXAMPLE CODE --> | |
| <p> | |
| The structures used for the POST and GET data are not exactly the same, so | |
| if we were to fetch a value from POST data instead of the query string, we | |
| would have to resort to a few more lines, as outlined in <a href="#get_post" | |
| >this example</a> in the last chapter of this document. | |
| </p> | |
| </section> | |
| <section id="advanced_handler"><title>Making an advanced handler</title> | |
| <p> | |
| Now that we have learned how to parse form data and manage our resources, | |
| we can move on to creating an advanced version of our module, that spits | |
| out the MD5 or SHA1 digest of files: | |
| </p> | |
| <!-- BEGIN EXAMPLE CODE --> | |
| <highlight language="c"> | |
| static int example_handler(request_rec *r) | |
| { | |
| int rc, exists; | |
| apr_finfo_t finfo; | |
| apr_file_t *file; | |
| char *filename; | |
| char buffer[256]; | |
| apr_size_t readBytes; | |
| int n; | |
| apr_table_t *GET; | |
| apr_array_header_t *POST; | |
| const char *digestType; | |
| /* Check that the "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; | |
| } | |
| </highlight> | |
| <!-- END EXAMPLE CODE --> | |
| <p> | |
| This version in its entirety can be found here: | |
| <a href="mod_example_2.c">mod_example_2.c</a>. | |
| </p> | |
| </section> | |
| </section> | |
| <section id="configuration"><title>Adding configuration options</title> | |
| <p> | |
| In this next segment of this document, we will turn our eyes away from the | |
| digest module and create a new example module, whose only function is to | |
| write out its own configuration. The purpose of this is to examine how | |
| the server works with configuration, and what happens when you start writing | |
| advanced configurations | |
| for your modules. | |
| </p> | |
| <section id="config_intro"><title>An introduction to configuration | |
| directives</title> | |
| <p> | |
| If you are reading this, then you probably already know | |
| what a configuration directive is. Simply put, a directive is a way of | |
| telling an individual module (or a set of modules) how to behave, such as | |
| these directives control how <code>mod_rewrite</code> works: | |
| </p> | |
| <highlight language="config"> | |
| RewriteEngine On | |
| RewriteCond "%{REQUEST_URI}" "^/foo/bar" | |
| RewriteRule "^/foo/bar/(.*)$" "/foobar?page=$1" | |
| </highlight> | |
| <p> | |
| Each of these configuration directives are handled by a separate function, | |
| that parses the parameters given and sets up a configuration accordingly. | |
| </p> | |
| </section> | |
| <section id="config_simple"><title>Making an example configuration</title> | |
| <p>To begin with, we'll create a basic configuration in C-space:</p> | |
| <!-- BEGIN EXAMPLE CODE --> | |
| <highlight language="c"> | |
| typedef struct { | |
| int enabled; /* Enable or disable our module */ | |
| const char *path; /* Some path to...something */ | |
| int typeOfAction; /* 1 means action A, 2 means action B and so on */ | |
| } example_config; | |
| </highlight> | |
| <!-- END EXAMPLE CODE --> | |
| <p> | |
| Now, let's put this into perspective by creating a very small module that | |
| just prints out a hard-coded configuration. You'll notice that we use the | |
| <code>register_hooks</code> function for initializing the configuration | |
| values to their defaults: | |
| </p> | |
| <!-- BEGIN EXAMPLE CODE --> | |
| <highlight language="c"> | |
| typedef struct { | |
| int enabled; /* Enable or disable our module */ | |
| const char *path; /* Some path to...something */ | |
| int typeOfAction; /* 1 means action A, 2 means action B and so on */ | |
| } example_config; | |
| static example_config config; | |
| static int example_handler(request_rec *r) | |
| { | |
| if (!r->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 */ | |
| AP_DECLARE_MODULE(example) = | |
| { | |
| 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 */ | |
| AP_MODULE_FLAG_NONE /* Flags */ | |
| }; | |
| </highlight> | |
| <!-- END EXAMPLE CODE --> | |
| <p> | |
| So far so good. To access our new handler, we could add the following to | |
| our configuration: | |
| </p> | |
| <highlight language="config"> | |
| <Location "/example"> | |
| SetHandler example-handler | |
| </Location> | |
| </highlight> | |
| <p> | |
| When we visit, we'll see our current configuration being spit out by our | |
| module. | |
| </p> | |
| </section> | |
| <section id="register_directive"><title>Registering directives with the server</title> | |
| <p> | |
| What if we want to change our configuration, not by hard-coding new values | |
| into the module, but by using either the httpd.conf file or possibly a | |
| .htaccess file? It's time to let the server know that we want this to be | |
| possible. To do so, we must first change our <em>name tag</em> to include a | |
| reference to the configuration directives we want to register with the server: | |
| </p> | |
| <!-- BEGIN EXAMPLE CODE --> | |
| <highlight language="c"> | |
| AP_DECLARE_MODULE(example) = | |
| { | |
| 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 */ | |
| AP_MODULE_FLAG_NONE /* Flags */ | |
| }; | |
| </highlight> | |
| <!-- END EXAMPLE CODE --> | |
| <p> | |
| This will tell the server that we are now accepting directives from the | |
| configuration files, and that the structure called <code>example_directives | |
| </code> holds information on what our directives are and how they work. | |
| Since we have three different variables in our module configuration, we | |
| will add a structure with three directives and a NULL at the end: | |
| </p> | |
| <!-- BEGIN EXAMPLE CODE --> | |
| <highlight language="c"> | |
| static const command_rec example_directives[] = | |
| { | |
| AP_INIT_TAKE1("exampleEnabled", example_set_enabled, NULL, RSRC_CONF, "Enable or disable mod_example"), | |
| AP_INIT_TAKE1("examplePath", example_set_path, NULL, RSRC_CONF, "The path to whatever"), | |
| AP_INIT_TAKE2("exampleAction", example_set_action, NULL, RSRC_CONF, "Special action value!"), | |
| { } | |
| }; | |
| </highlight> | |
| <!-- END EXAMPLE CODE --> | |
| <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> | |
| </section> | |
| <section id="directive_handler"><title>The directive handler function</title> | |
| <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> | |
| <!-- BEGIN EXAMPLE CODE --> | |
| <highlight language="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; | |
| } | |
| </highlight> | |
| <!-- END EXAMPLE CODE --> | |
| </section> | |
| <section id="directive_complete"><title>Putting it all together</title> | |
| <p> | |
| Now that we have our directives set up, and handlers configured for them, | |
| we can assemble our module into one big file: | |
| </p> | |
| <!-- BEGIN EXAMPLE CODE --> | |
| <highlight language="c"> | |
| /* mod_example_config_simple.c: */ | |
| #include <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!"), | |
| { } | |
| }; | |
| /* | |
| ============================================================================== | |
| 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: | |
| ============================================================================== | |
| */ | |
| AP_DECLARE_MODULE(example) = | |
| { | |
| 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 */ | |
| AP_MODULE_FLAG_NONE /* Flags */ | |
| }; | |
| </highlight> | |
| <!-- END EXAMPLE CODE --> | |
| <p> | |
| In our httpd.conf file, we can now change the hard-coded configuration by | |
| adding a few lines: | |
| </p> | |
| <highlight language="config"> | |
| ExampleEnabled On | |
| ExamplePath "/usr/bin/foo" | |
| ExampleAction file allow | |
| </highlight> | |
| <p> | |
| And thus we apply the configuration, visit <code>/example</code> on our | |
| web site, and we see the configuration has adapted to what we wrote in our | |
| configuration file. | |
| </p> | |
| </section> | |
| </section> | |
| <section id="context"><title>Context aware configurations</title> | |
| <section id="context_intro"><title>Introduction to context aware configurations</title> | |
| <p> | |
| In Apache HTTP Server 2.4, different URLs, virtual hosts, directories etc can have very | |
| different meanings to the user of the server, and thus different contexts | |
| within which modules must operate. For example, let's assume you have this | |
| configuration set up for mod_rewrite: | |
| </p> | |
| <highlight language="config"> | |
| <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> | |
| </highlight> | |
| <p> | |
| In this example, you will have set up two different contexts for | |
| mod_rewrite:</p> | |
| <ol> | |
| <li>Inside <code>/var/www</code>, all requests for <code>http://example.com</code> must go to <code>http://www.example.com</code></li> | |
| <li>Inside <code>/var/www/sub</code>, all requests for <code>foobar</code> must go to <code>index.php?foobar=true</code></li> | |
| </ol> | |
| <p> | |
| If mod_rewrite (or the entire server for that matter) wasn't context aware, then | |
| these rewrite rules would just apply to every and any request made, | |
| regardless of where and how they were made, but since the module can pull | |
| the context specific configuration straight from the server, it does not need | |
| to know itself, which of the directives are valid in this context, since | |
| the server takes care of this.</p> | |
| <p> | |
| So how does a module get the specific configuration for the server, | |
| directory or location in question? It does so by making one simple call: | |
| </p> | |
| <!-- BEGIN EXAMPLE CODE --> | |
| <highlight language="c"> | |
| example_config *config = (example_config*) <a href="http://ci.apache.org/projects/httpd/trunk/doxygen/group__APACHE__CORE__CONFIG.html#ga1093a5908a384eacc929b028c79f2a02">ap_get_module_config</a>(r->per_dir_config, &example_module); | |
| </highlight> | |
| <!-- END EXAMPLE CODE --> | |
| <p> | |
| That's it! Of course, a whole lot goes on behind the scenes, which we will | |
| discuss in this chapter, starting with how the server came to know what our | |
| configuration looks like, and how it came to be set up as it is in the | |
| specific context. | |
| </p> | |
| </section> | |
| <section id="context_base"><title>Our basic configuration setup</title> | |
| <p>In this chapter, we will be working with a slightly modified version of | |
| our previous context structure. We will set a <code>context</code> | |
| variable that we can use to track which context configuration is being | |
| used by the server in various places: | |
| </p> | |
| <!-- BEGIN EXAMPLE CODE --> | |
| <highlight language="c"> | |
| typedef struct { | |
| char context[256]; | |
| char path[256]; | |
| int typeOfAction; | |
| int enabled; | |
| } example_config; | |
| </highlight> | |
| <!-- END EXAMPLE CODE --> | |
| <p>Our handler for requests will also be modified, yet still very simple:</p> | |
| <!-- BEGIN EXAMPLE CODE --> | |
| <highlight language="c"> | |
| static int example_handler(request_rec *r) | |
| { | |
| if(!r->handler || strcmp(r->handler, "example-handler")) return(DECLINED); | |
| example_config *config = (example_config*) ap_get_module_config(r->per_dir_config, &example_module); | |
| ap_set_content_type(r, "text/plain"); | |
| ap_rprintf("Enabled: %u\n", config->enabled); | |
| ap_rprintf("Path: %s\n", config->path); | |
| ap_rprintf("TypeOfAction: %x\n", config->typeOfAction); | |
| ap_rprintf("Context: %s\n", config->context); | |
| return OK; | |
| } | |
| </highlight> | |
| <!-- END EXAMPLE CODE --> | |
| </section> | |
| <section id="context_which"><title>Choosing a context</title> | |
| <p> | |
| Before we can start making our module context aware, we must first define, | |
| which contexts we will accept. As we saw in the previous chapter, defining | |
| a directive required five elements be set:</p> | |
| <!-- BEGIN EXAMPLE CODE --> | |
| <highlight language="c"> | |
| AP_INIT_TAKE1("exampleEnabled", example_set_enabled, NULL, RSRC_CONF, "Enable or disable mod_example"), | |
| </highlight> | |
| <!-- END EXAMPLE CODE --> | |
| <p>The <code>RSRC_CONF</code> definition told the server that we would only allow | |
| this directive in a global server context, but since we are now trying out | |
| a context aware version of our module, we should set this to something | |
| more lenient, namely the value <code>ACCESS_CONF</code>, which lets us use | |
| the directive inside <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> | |
| </section> | |
| <section id="context_pool"><title>Using the server to allocate configuration slots</title> | |
| <p> A much smarter way to manage your configurations is by letting the server | |
| help you create them. To do so, we must first start off by changing our | |
| <em>name tag</em> to let the server know, that it should assist us in creating | |
| and managing our configurations. Since we have chosen the per-directory | |
| (or per-location) context for our module configurations, we'll add a | |
| per-directory creator and merger function reference in our tag:</p> | |
| <!-- BEGIN EXAMPLE CODE --> | |
| <highlight language="c"> | |
| AP_DECLARE_MODULE(example) = | |
| { | |
| 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 */ | |
| AP_MODULE_FLAG_NONE /* Flags */ | |
| }; | |
| </highlight> | |
| <!-- END EXAMPLE CODE --> | |
| </section> | |
| <section id="context_new"><title>Creating new context configurations</title> | |
| <p> | |
| Now that we have told the server to help us create and manage configurations, | |
| our first step is to make a function for creating new, blank | |
| configurations. We do so by creating the function we just referenced in | |
| our name tag as the Per-directory configuration handler:</p> | |
| <!-- BEGIN EXAMPLE CODE --> | |
| <highlight language="c"> | |
| void *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; | |
| } | |
| </highlight> | |
| <!-- END EXAMPLE CODE --> | |
| </section> | |
| <section id="context_merge"><title>Merging configurations</title> | |
| <p> | |
| Our next step in creating a context aware configuration is merging | |
| configurations. This part of the process particularly applies to scenarios | |
| where you have a parent configuration and a child, such as the following: | |
| </p> | |
| <highlight language="config"> | |
| <Directory "/var/www"> | |
| ExampleEnabled On | |
| ExamplePath "/foo/bar" | |
| ExampleAction file allow | |
| </Directory> | |
| <Directory "/var/www/subdir"> | |
| ExampleAction file deny | |
| </Directory> | |
| </highlight> | |
| <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> | |
| <!-- BEGIN EXAMPLE CODE --> | |
| <highlight language="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 ; | |
| } | |
| </highlight> | |
| <!-- END EXAMPLE CODE --> | |
| </section> | |
| <section id="context_example"><title>Trying out our new context aware configurations</title> | |
| <p> | |
| Now, let's try putting it all together to create a new module that is | |
| context aware. First off, we'll create a configuration that lets us test | |
| how the module works: | |
| </p> | |
| <highlight language="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> | |
| </highlight> | |
| <p> | |
| Then we'll assemble our module code. Note, that since we are now using our | |
| name tag as reference when fetching configurations in our handler, I have | |
| added some prototypes to keep the compiler happy: | |
| </p> | |
| <!-- BEGIN EXAMPLE CODE --> | |
| <highlight language="c"> | |
| /*$6 | |
| +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ | |
| * mod_example_config.c | |
| +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ | |
| */ | |
| #include <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!"), | |
| { } | |
| }; | |
| /*$1 | |
| ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ | |
| Our name tag | |
| ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ | |
| */ | |
| AP_DECLARE_MODULE(example) = | |
| { | |
| 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 */ | |
| AP_MODULE_FLAG_NONE /* Flags */ | |
| }; | |
| /* | |
| ======================================================================================================================= | |
| 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; | |
| } | |
| </highlight> | |
| <!-- END EXAMPLE CODE --> | |
| </section> | |
| </section> | |
| <section id="summary"><title>Summing up</title> | |
| <p> | |
| We have now looked at how to create simple modules for Apache HTTP Server 2.4 and | |
| configuring them. What you do next is entirely up to you, but it is my | |
| hope that something valuable has come out of reading this documentation. | |
| If you have questions on how to further develop modules, you are welcome | |
| to join our <a href="http://httpd.apache.org/lists.html">mailing lists</a> | |
| or check out the rest of our documentation for further tips. | |
| </p> | |
| </section> | |
| <section id="snippets"><title>Some useful snippets of code</title> | |
| <section id="get_post"><title>Retrieve variables from POST form data</title> | |
| <!-- BEGIN EXAMPLE CODE --> | |
| <highlight language="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; | |
| } | |
| </highlight> | |
| <!-- END EXAMPLE CODE --> | |
| </section> | |
| <section id="headers_out"><title>Printing out every HTTP header received</title> | |
| <!-- BEGIN EXAMPLE CODE --> | |
| <highlight language="c"> | |
| static int example_handler(request_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; | |
| } | |
| </highlight> | |
| <!-- END EXAMPLE CODE --> | |
| </section> | |
| <section id="request_body"><title>Reading the request body into memory</title> | |
| <!-- BEGIN EXAMPLE CODE --> | |
| <highlight language="c"> | |
| static int util_read(request_rec *r, const char **rbuf, apr_off_t *size) | |
| { | |
| /*~~~~~~~~*/ | |
| int rc = OK; | |
| /*~~~~~~~~*/ | |
| if((rc = ap_setup_client_block(r, REQUEST_CHUNKED_ERROR))) { | |
| return(rc); | |
| } | |
| if(ap_should_client_block(r)) { | |
| /*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/ | |
| char argsbuffer[HUGE_STRING_LEN]; | |
| apr_off_t rsize, len_read, rpos = 0; | |
| apr_off_t length = r->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; | |
| } | |
| </highlight> | |
| <!-- END EXAMPLE CODE --> | |
| </section> | |
| </section> | |
| </manualpage> |