21.4. A Complete Example
We spent some time trying to think of
an example of a module that uses all the available hooks. At the same
time, we spent considerable effort tracking through the innards of
Apache to find out what happened when. Then we suddenly thought of
writing a module to show what happened when. And, presto,
mod_reveal.c was born. This is not a module
you'd want to include in a live Apache without
modification, since it prints stuff to the standard error output
(which ends up in the error log, for the most part). But rather than
obscure the main functionality by including code to switch the
monitoring on and off, we thought it best to keep it simple. Besides,
even in this form the module is very useful; it's
presented and explained in this section.
21.4.1. Overview
The module implements two commands,
RevealServerTag and RevealTag.
RevealServerTag names a server section and is
stored in the per-server configuration. RevealTag
names a directory (or location or file) section and is stored in the
per-directory configuration. When per-server or per-directory
configurations are merged, the resulting configuration is tagged with
a combination of the tags of the two merged sections. The module also
implements a handler, which generates HTML with interesting
information about a URL.
No self-respecting module starts without a copyright notice:
/*
Reveal the order in which things are done.
Copyright (C) 1996, 1998 Ben Laurie
*/
Note that the included http_protocol.h is only
needed for the request handle; the other two are required by almost
all modules:
#include "httpd.h"
#include "http_config.h"
#include "http_protocol.h"
#include "http_request.h" [2.0]
#include "apr_strings.h" [2.0]
#include "http_connection.h" [2.0]
#include "http_log.h" [2.0]
#include "http_core.h" [2.0]
#include "scoreboard.h" [2.0]
#include <unistd.h> [2.0]
The per-directory configuration structure is:
typedef struct
{
char *szDir;
char *szTag;
} SPerDir;
And the per-server configuration structure is:
typedef struct
{
char *szServer;
char *szTag;
} SPerServer;
There is an unavoidable circular reference in most modules; the
module structure is needed to access the
per-server and per-directory configurations in the hook functions.
But in order to construct the module structure, we
need to know the hook functions. Since there is only one
module structure and a lot of hook functions, it
is simplest to forward reference the module
structure:
extern module reveal_module;
If a string is NULL, it may crash printf(
) on some systems, so we define a function to give us a
stand-in for NULL strings:
static const char *None(const char *szStr)
{
if(szStr)
return szStr;
return "(none)";
}
Since the server names and port numbers are often not known when the
per-server structures are created, but are filled in by the time the
initialization function is called, we rename them in the
init function. Note that we have to iterate over
all the servers, since init is only called with
the "main"; server structure. As we
go, we print the old and new names so we can see what is going on.
Just for completeness, we add a module version string to the server
version string. Note that you would not normally do this for such a
minor module:
static void SubRevealInit(server_rec *pServer,pool *pPool)
{
SPerServer *pPerServer=ap_get_module_config(pServer->module_config,
&reveal_module);
if(pServer->server_hostname &&
(!strncmp(pPerServer->szServer,"(none):",7)
|| !strcmp(pPerServer->szServer+strlen(pPerServer->szServer)
-2,":0")))
{
char szPort[20];
fprintf(stderr,"Init : update server name from %s\n",
pPerServer->szServer);
sprintf(szPort,"%d",pServer->port);
pPerServer->szServer=ap_pstrcat(pPool,pServer->server_hostname,":",
szPort,NULL);
}
fprintf(stderr,"Init : host=%s port=%d server=%s tag=%s\n",
pServer->server_hostname,pServer->port,pPerServer->szServer,
None(pPerServer->szTag));
}
static void RevealInit(server_rec *pServer,pool *pPool)
{
ap_add_version_component("Reveal/0.0");
for( ; pServer ; pServer=pServer->next)
SubRevealInit(pServer,pPool);
fprintf(stderr,"Init : done\n");
}
Here we create the per-server configuration structure. Since this is
called as soon as the server is created,
pServer->server_hostname and
pServer->port may not have been initialized, so
their values must be taken with a pinch of salt (but they get
corrected later):
static void *RevealCreateServer(pool *pPool,server_rec *pServer)
{
SPerServer *pPerServer=ap_palloc(pPool,sizeof *pPerServer);
const char *szServer;
char szPort[20];
szServer=None(pServer->server_hostname);
sprintf(szPort,"%d",pServer->port);
pPerServer->szTag=NULL;
pPerServer->szServer=ap_pstrcat(pPool,szServer,":",szPort,NULL);
fprintf(stderr,"CreateServer: server=%s:%s\n",szServer,szPort);
return pPerServer;
}
Here we merge two per-server configurations. The merged configuration
is tagged with the names of the two configurations from which it is
derived (or the string (none) if they
weren't tagged). Note that we create a new
per-server configuration structure to hold the merged information
(this is the standard thing to do):
static void *RevealMergeServer(pool *pPool,void *_pBase,void *_pNew)
{
SPerServer *pBase=_pBase;
SPerServer *pNew=_pNew;
SPerServer *pMerged=ap_palloc(pPool,sizeof *pMerged);
fprintf(stderr,
"MergeServer : pBase: server=%s tag=%s pNew: server=%s tag=%s\n",
pBase->szServer,None(pBase->szTag),
pNew->szServer,None(pNew->szTag));
pMerged->szServer=ap_pstrcat(pPool,pBase->szServer,"+",pNew->szServer,
NULL);
pMerged->szTag=ap_pstrcat(pPool,None(pBase->szTag),"+",
None(pNew->szTag),NULL);
return pMerged;
}
Now we create a per-directory configuration structure. If
szDir is NULL, we change it to
(none) to ensure that later merges have something
to merge! Of course, szDir is
NULL once for each server. Notice that we
don't log which server this was created for;
that's because there is no legitimate way to find
out. It is also worth mentioning that this will only be called for a
particular directory (or location or file) if a
RevealTag directive occurs in that section:
static void *RevealCreateDir(pool *pPool,char *_szDir)
{
SPerDir *pPerDir=ap_palloc(pPool,sizeof *pPerDir);
const char *szDir=None(_szDir);
fprintf(stderr,"CreateDir : dir=%s\n",szDir);
pPerDir->szDir=ap_pstrdup(pPool,szDir);
pPerDir->szTag=NULL;
return pPerDir;
}
Next we merge the per-directory structures. Again, we have no clue
which server we are dealing with. In practice,
you'll find this function is called a great deal:
static void *RevealMergeDir(pool *pPool,void *_pBase,void *_pNew)
{
SPerDir *pBase=_pBase;
SPerDir *pNew=_pNew;
SPerDir *pMerged=ap_palloc(pPool,sizeof *pMerged);
fprintf(stderr,"MergeDir : pBase: dir=%s tag=%s "
"pNew: dir=%s tag=%s\n",pBase->szDir,None(pBase->szTag),
pNew->szDir,None(pNew->szTag));
pMerged->szDir=ap_pstrcat(pPool,pBase->szDir,"+",pNew->szDir,NULL);
pMerged->szTag=ap_pstrcat(pPool,None(pBase->szTag),"+",
None(pNew->szTag),NULL);
return pMerged;
}
Here is a helper function used by most of the other hooks to show the
per-server and per-directory configurations currently in use.
Although it caters to the situation in which there is no
per-directory configuration, that should never happen:[81]
static void ShowRequestStuff(request_rec *pReq)
{
SPerDir *pPerDir=ap_get_module_config(pReq->per_dir_config,
&reveal_module); [1.3]
SPerDir *pPerDir=pReq->per_dir_config ?
ap_get_module_config(pReq->per_dir_config,&reveal_module) : NULL; [2.0]
SPerServer *pPerServer=ap_get_module_config(pReq->server->
module_config,&reveal_module);
SPerDir none={"(null)","(null)"};
SPerDir noconf={"(no per-dir config)","(no per-dir config)"};
if(!pReq->per_dir_config)
pPerDir=&noconf;
else if(!pPerDir)
pPerDir=&none;
fprintf(stderr," server=%s tag=%s dir=%s tag=%s\n",
pPerServer->szServer,pPerServer->szTag,pPerDir->szDir,
pPerDir->szTag);
}
None of the following hooks does anything more than trace itself:
static int RevealTranslate(request_rec *pReq)
{
fprintf(stderr,"Translate : uri=%s",pReq->uri);
ShowRequestStuff(pReq);
return DECLINED;
}
static int RevealCheckUserID(request_rec *pReq)
{
fprintf(stderr,"CheckUserID :");
ShowRequestStuff(pReq);
return DECLINED;
}
static int RevealCheckAuth(request_rec *pReq)
{
fprintf(stderr,"CheckAuth :");
ShowRequestStuff(pReq);
return DECLINED;
}
static int RevealCheckAccess(request_rec *pReq)
{
fprintf(stderr,"CheckAccess :");
ShowRequestStuff(pReq);
return DECLINED;
}
static int RevealTypeChecker(request_rec *pReq)
{
fprintf(stderr,"TypeChecker :");
ShowRequestStuff(pReq);
return DECLINED;
}
static int RevealFixups(request_rec *pReq)
{
fprintf(stderr,"Fixups :");
ShowRequestStuff(pReq);
return DECLINED;
}
static int RevealLogger(request_rec *pReq)
{
fprintf(stderr,"Logger :");
ShowRequestStuff(pReq);
return DECLINED;
}
static int RevealHeaderParser(request_rec *pReq)
{
fprintf(stderr,"HeaderParser:");
ShowRequestStuff(pReq);
return DECLINED;
}
Next comes the child-initialization function. This extends the
server tag to include the PID of the particular
server instance in which it exists. Note that, like the
init function, it must iterate through all the
server instances — also, in 2.0, it must register the child exit
handler:
static void RevealChildInit(server_rec *pServer, pool *pPool)
{
char szPID[20];
fprintf(stderr,"Child Init : pid=%d\n",(int)getpid( ));
sprintf(szPID,"[%d]",(int)getpid( ));
for( ; pServer ; pServer=pServer->next)
{
SPerServer *pPerServer=ap_get_module_config(pServer->module_config,
&reveal_module);
pPerServer->szServer=ap_pstrcat(pPool,pPerServer->szServer,szPID,
NULL);
}
apr_pool_cleanup_register(pPool,pServer,RevealChildExit,RevealChildExit);[2.0]
}
Then the last two hooks are simply logged — however, note that
RevealChildExit( ) is completely differently as
declared for 1.3 and 2.0. Also, in 2.0 RevealChildExit(
) has to come before RevealChildInit( )
to avoid compiler errors:
(1.3)
static void RevealChildExit(server_rec *pServer, pool *pPool)
{
fprintf(stderr,"Child Exit : pid=%d\n",(int)getpid( ));
}
(2.0)
static apr_status_t RevealChildExit(void *p)
{
fprintf(stderr,"Child Exit : pid=%d\n",(int)getpid( ));
return OK;
}
static int RevealPostReadRequest(request_rec *pReq)
{
fprintf(stderr,"PostReadReq : method=%s uri=%s protocol=%s",
pReq->method,pReq->unparsed_uri,pReq->protocol);
ShowRequestStuff(pReq);
return DECLINED;
}
The following is the handler for the RevealTag
directive. If more than one RevealTag appears in a
section, they are glued together with a
"-"; separating them. A
NULL is returned to indicate that there was no
error:
static const char *RevealTag(cmd_parms *cmd, SPerDir *pPerDir, char *arg)
{
SPerServer *pPerServer=ap_get_module_config(cmd->server->module_config,
&reveal_module);
fprintf(stderr,"Tag : new=%s dir=%s server=%s tag=%s\n",
arg,pPerDir->szDir,pPerServer->szServer,
None(pPerServer->szTag));
if(pPerDir->szTag)
pPerDir->szTag=ap_pstrcat(cmd->pool,pPerDir->szTag,"-",arg,NULL);
else
pPerDir->szTag=ap_pstrdup(cmd->pool,arg);
return NULL;
}
This code handles the RevealServerTag directive.
Again, if more than one Reveal-ServerTag appears
in a server section, they are glued together with
"-"; in between:
static const char *RevealServerTag(cmd_parms *cmd, SPerDir *pPerDir,
char *arg)
{
SPerServer *pPerServer=ap_get_module_config(cmd->server->module_config,
&reveal_module);
fprintf(stderr,"ServerTag : new=%s server=%s stag=%s\n",arg,
pPerServer->szServer,None(pPerServer->szTag));
if(pPerServer->szTag)
pPerServer->szTag=ap_pstrcat(cmd->pool,pPerServer->szTag,"-",arg,
NULL);
else
pPerServer->szTag=ap_pstrdup(cmd->pool,arg);
return NULL;
}
Here we bind the directives to their handlers. Note that
RevealTag uses
ACCESS_CONF|OR_ALL as its
req_override so that it is legal wherever a
<Directory> section occurs.
RevealServerTag only makes sense outside
<Directory> sections, so it uses
RSRC_CONF:
(1.3)static command_rec aCommands[]=
{
{ "RevealTag", RevealTag, NULL, ACCESS_CONF|OR_ALL, TAKE1, "a tag for this
section"},
{ "RevealServerTag", RevealServerTag, NULL, RSRC_CONF, TAKE1, "a tag for this
server" },
{ NULL }
};
(2.0)static command_rec aCommands[]=
{
AP_INIT_TAKE1("RevealTag", RevealTag, NULL, ACCESS_CONF|OR_ALL,
"a tag for this section"),
AP_INIT_TAKE1("RevealServerTag", RevealServerTag, NULL, RSRC_CONF,
"a tag for this server" ),
{ NULL }
};
These two helper functions simply output things as a row in a table:
static void TShow(request_rec *pReq,const char *szHead,const char *szItem)
{
ap_rprintf(pReq,"<TR><TH>%s<TD>%s\n",szHead,szItem);
}
static void TShowN(request_rec *pReq,const char *szHead,int nItem)
{
ap_rprintf(pReq,"<TR><TH>%s<TD>%d\n",szHead,nItem);
}
The following code is the request handler; it generates HTML
describing the configurations that handle the URI:
static int RevealHandler(request_rec *pReq)
{
SPerDir *pPerDir=ap_get_module_config(pReq->per_dir_config,
&reveal_module);
SPerServer *pPerServer=ap_get_module_config(pReq->server->
module_config,&reveal_module);
pReq->content_type="text/html";
ap_send_http_header(pReq);
ap_rputs("<CENTER><H1>Revelation of ",pReq);
ap_rputs(pReq->uri,pReq);
ap_rputs("</H1></CENTER><HR>\n",pReq);
ap_rputs("<TABLE>\n",pReq);
TShow(pReq,"URI",pReq->uri);
TShow(pReq,"Filename",pReq->filename);
TShow(pReq,"Server name",pReq->server->server_hostname);
TShowN(pReq,"Server port",pReq->server->port);
TShow(pReq,"Server config",pPerServer->szServer);
TShow(pReq,"Server config tag",pPerServer->szTag);
TShow(pReq,"Directory config",pPerDir->szDir);
TShow(pReq,"Directory config tag",pPerDir->szTag);
ap_rputs("</TABLE>\n",pReq);
return OK;
}
Here we associate the request handler with the handler string (1.3):
static handler_rec aHandlers[]=
{
{ "reveal", RevealHandler },
{ NULL },
};
And finally, in 1.3, there is the module structure:
module reveal_module = {
STANDARD_MODULE_STUFF,
RevealInit, /* initializer */
RevealCreateDir, /* dir config creater */
RevealMergeDir, /* dir merger --- default is to override */
RevealCreateServer, /* server config */
RevealMergeServer, /* merge server configs */
aCommands, /* command table */
aHandlers, /* handlers */
RevealTranslate, /* filename translation */
RevealCheckUserID, /* check_user_id */
RevealCheckAuth, /* check auth */
RevealCheckAccess, /* check access */
RevealTypeChecker, /* type_checker */
RevealFixups, /* fixups */
RevealLogger, /* logger */
RevealHeaderParser, /* header parser */
RevealChildInit, /* child init */
RevealChildExit, /* child exit */
RevealPostReadRequest, /* post read request */
};
In 2.0, we have the hook-registering function and the module
structure:
static void RegisterHooks(apr_pool_t *pPool)
{
ap_hook_post_config(RevealInit,NULL,NULL,APR_HOOK_MIDDLE);
ap_hook_handler(RevealHandler,NULL,NULL,APR_HOOK_MIDDLE);
ap_hook_translate_name(RevealTranslate,NULL,NULL,APR_HOOK_MIDDLE);
ap_hook_check_user_id(RevealCheckUserID,NULL,NULL,APR_HOOK_MIDDLE);
ap_hook_auth_checker(RevealCheckAuth,NULL,NULL,APR_HOOK_MIDDLE);
ap_hook_access_checker(RevealCheckAccess,NULL,NULL,APR_HOOK_MIDDLE);
ap_hook_type_checker(RevealTypeChecker,NULL,NULL,APR_HOOK_MIDDLE);
ap_hook_fixups(RevealFixups,NULL,NULL,APR_HOOK_MIDDLE);
ap_hook_log_transaction(RevealLogger,NULL,NULL,APR_HOOK_MIDDLE);
ap_hook_header_parser(RevealHeaderParser,NULL,NULL,APR_HOOK_MIDDLE);
ap_hook_child_init(RevealChildInit,NULL,NULL,APR_HOOK_MIDDLE);
ap_hook_post_read_request(RevealPostReadRequest,NULL,NULL,APR_HOOK_MIDDLE);
}
module reveal_module = {
STANDARD20_MODULE_STUFF,
RevealCreateDir, /* dir config creater */
RevealMergeDir, /* dir merger --- default is to override */
RevealCreateServer, /* server config */
RevealMergeServer, /* merge server configs */
aCommands, /* command table */
RegisterHooks /* hook registration */
};
The module can be included in Apache by specifying:
AddModule modules/extra/mod_reveal.o
in Configuration. You might like to try it on
your favorite server: just pepper the httpd.conf
file with RevealTag and
RevealServerTag directives. Because of the huge
amount of logging this produces, it would be unwise to use it on a
live server!
21.4.2. Example Output
To illustrate mod_reveal.c in use, we used the
following configuration:
Listen 9001
Listen 9000
TransferLog /home/ben/www/APACHE3/book/logs/access_log
ErrorLog /home/ben/www/APACHE3/book/logs/error_log
RevealTag MainDir
RevealServerTag MainServer
<LocationMatch /.reveal>
RevealTag Revealer
SetHandler reveal
</LocationMatch>
<VirtualHost *:9001>
DocumentRoot /home/ben/www/APACHE3/docs
RevealTag H1Main
RevealServerTag H1
<Directory /home/ben/www/APACHE3/docs/protected>
RevealTag H1ProtectedDirectory
</Directory>
<Location /protected>
RevealTag H1ProtectedLocation
</Location>
</VirtualHost>
<VirtualHost *:9000>
DocumentRoot /home/camilla/www/APACHE3/docs
RevealTag H2Main
RevealServerTag H2
</VirtualHost>
Note that the <Directory> and
<Location> sections in the first virtual
host actually refer to the same place. This is to illustrate the
order in which the sections are combined. Also note that the
<LocationMatch> section
doesn't have to correspond to a real file; looking
at any location that ends with .reveal will
invoke mod_reveal.c 's handler.
Starting the server produces this on the screen:
bash$ httpd -d ~/www/APACHE3/book/
CreateServer: server=(none):0
CreateDir : dir=(none)
PreConfig [2.0]
Tag : new=MainDir dir=(none) server=(none):0 tag=(none)
ServerTag : new=MainServer server=(none):0 stag=(none)
CreateDir : dir=/.reveal
Tag : new=Revealer dir=/.reveal server=(none):0 tag=MainServer
CreateDir : dir=(none)
CreateServer: server=(none):9001
Tag : new=H1Main dir=(none) server=(none):9001 tag=(none)
ServerTag : new=H1 server=(none):9001 stag=(none)
CreateDir : dir=/home/ben/www/APACHE3/docs/protected
Tag : new=H1ProtectedDirectory dir=/home/ben/www/APACHE3/docs/protected
server=(none):9001 tag=H1
CreateDir : dir=/protected
Tag : new=H1ProtectedLocation dir=/protected server=(none):9001
tag=H1
CreateDir : dir=(none)
CreateServer: server=(none):9000
Tag : new=H2Main dir=(none) server=(none):9000 tag=(none)
ServerTag : new=H2 server=(none):9000 stag=(none)
MergeServer : pBase: server=(none):0 tag=MainServer pNew: server=(none):9000
tag=H2
MergeDir : pBase: dir=(none) tag=MainDir pNew: dir=(none) tag=H2Main
MergeServer : pBase: server=(none):0 tag=MainServer pNew: server=(none):9001
tag=H1
MergeDir : pBase: dir=(none) tag=MainDir pNew: dir=(none) tag=H1Main
Notice that in 2.0, the pre_config hook actually
comes slightly after configuration has started!
Notice that the <Location> and
<LocationMatch> sections are treated as
directories as far as the code is concerned. At this point,
stderr is switched to the error log, and the
following is logged:
OpenLogs : server=(none):0 tag=MainServer [2.0]
Init : update server name from (none):0
Init : host=scuzzy.ben.algroup.co.uk port=0 server=scuzzy.ben.algroup.co.
uk:0 tag=MainServer
Init : update server name from (none):0+(none):9000
Init : host=scuzzy.ben.algroup.co.uk port=9000 server=scuzzy.ben.algroup.
co.uk:9000 tag=MainServer+H2
Init : update server name from (none):0+(none):9001
Init : host=scuzzy.ben.algroup.co.uk port=9001 server=scuzzy.ben.algroup.
co.uk:9001 tag=MainServer+H1
Init : done
At this point, the first-pass initialization is complete, and Apache
destroys the configurations and starts again (this double
initialization is required because directives may change things such
as the location of the initialization files):[82]
CreateServer: server=(none):0
CreateDir : dir=(none)
Tag : new=MainDir dir=(none) server=(none):0 tag=(none)
ServerTag : new=MainServer server=(none):0 stag=(none)
CreateDir : dir=/.reveal
Tag : new=Revealer dir=/.reveal server=(none):0 tag=MainServer
CreateDir : dir=(none)
CreateServer: server=(none):9001
Tag : new=H1Main dir=(none) server=(none):9001 tag=(none)
ServerTag : new=H1 server=(none):9001 stag=(none)
CreateDir : dir=/home/ben/www/APACHE3/docs/protected
Tag : new=H1ProtectedDirectory dir=/home/ben/www/APACHE3/docs/protected
server=(none):9001 tag=H1
CreateDir : dir=/protected
Tag : new=H1ProtectedLocation dir=/protected server=(none):9001
tag=H1
CreateDir : dir=(none)
CreateServer: server=(none):9000
Tag : new=H2Main dir=(none) server=(none):9000 tag=(none)
ServerTag : new=H2 server=(none):9000 stag=(none)
Now we've created all the server and directory
sections, and the top-level server is merged with the virtual hosts:
MergeServer : pBase: server=(none):0 tag=MainServer pNew: server=(none):9000
tag=H2
MergeDir : pBase: dir=(none) tag=MainDir pNew: dir=(none) tag=H2Main
MergeServer : pBase: server=(none):0 tag=MainServer pNew: server=(none):9001
tag=H1
MergeDir : pBase: dir=(none) tag=MainDir pNew: dir=(none) tag=H1Main
Now the init functions are called (which rename
the servers now that their "real"
names are known):
Init : update server name from (none):0
Init : host=freeby.ben.algroup.co.uk port=0
server=freeby.ben.algroup.co.uk:0 tag=MainServer
Init : update server name from (none):0+(none):9000
Init : host=freeby.ben.algroup.co.uk port=9000
server=freeby.ben.algroup.co.uk:9000 tag=MainServer+H2
Init : update server name from (none):0+(none):9001
Init : host=freeby.ben.algroup.co.uk port=9001
server=freeby.ben.algroup.co.uk:9001 tag=MainServer+H1
Init : done
Apache logs its startup message:
[Sun Jul 12 13:08:01 1998] [notice] Apache/1.3.1-dev (Unix) Reveal/0.0 configured —
resuming normal operations
Child init s are called:
Child Init : pid=23287
Child Init : pid=23288
Child Init : pid=23289
Child Init : pid=23290
Child Init : pid=23291
And Apache is ready to start handling requests. First, we request
http://host:9001/:
CreateConnection : server=scuzzy.ben.algroup.co.uk:0[78348] tag=MainServer conn_id=0
[2.0]
PreConnection : keepalive=0 double_reverse=0 [2.0]
ProcessConnection: keepalive=0 double_reverse=0 [2.0]
CreateRequest : server=scuzzy.ben.algroup.co.uk:9001[78348] tag=MainServer+H1
dir=(no per-dir config) tag=(no per-dir config) [2.0]
PostReadReq : method=GET uri=/ protocol=HTTP/1.0
server=freeby.ben.algroup.co.uk:9001[23287] tag=MainServer+H1
dir=(none)+(none) tag=MainDir+H1Main
QuickHandler : lookup_uri=0 server=scuzzy.ben.algroup.co.uk:9001[78348]
tag=MainServer+H1 dir=(none)+(none) tag=MainDir+H1Main [2.0]
Translate : uri=/ server=freeby.ben.algroup.co.uk:9001[23287]
tag=MainServer+H1 dir=(none)+(none) tag=MainDir+H1Main
MapToStorage : server=scuzzy.ben.algroup.co.uk:9001[78348] tag=MainServer+H1
dir=(none)+(none) tag=MainDir+H1Main [2.0]
HeaderParser: server=freeby.ben.algroup.co.uk:9001[23287] tag=MainServer+H1
dir=(none)+(none) tag=MainDir+H1Main
CheckAccess : server=freeby.ben.algroup.co.uk:9001[23287] tag=MainServer+H1
dir=(none)+(none) tag=MainDir+H1Main
TypeChecker : server=freeby.ben.algroup.co.uk:9001[23287] tag=MainServer+H1
dir=(none)+(none) tag=MainDir+H1Main [1.3]
Fixups : server=freeby.ben.algroup.co.uk:9001[23287] tag=MainServer+H1
dir=(none)+(none) tag=MainDir+H1Main
Because / is a directory, Apache attempts to use
/index.html instead (in this case, it
didn't exist, but Apache still goes through the
motions):
CreateRequest : server=scuzzy.ben.algroup.co.uk:9001[78348] tag=MainServer+H1
dir=(none)+(none) tag=MainDir+H1Main [2.0]
QuickHandler : lookup_uri=1 server=scuzzy.ben.algroup.co.uk:9001[78348]
tag=MainServer+H1 dir=(none)+(none) tag=MainDir+H1Main [2.0]
Translate : uri=/index.html server=freeby.ben.algroup.co.uk:9001[23287]
tag=MainServer+H1 dir=(none)+(none) tag=MainDir+H1Main
At this point, 1.3 and 2.0 diverge fairly radically. In 1.3:
CheckAccess : server=freeby.ben.algroup.co.uk:9001[23287] tag=MainServer+H1
dir=(none)+(none) tag=MainDir+H1Main
TypeChecker : server=freeby.ben.algroup.co.uk:9001[23287] tag=MainServer+H1
dir=(none)+(none) tag=MainDir+H1Main
Fixups : server=freeby.ben.algroup.co.uk:9001[23287] tag=MainServer+H1
dir=(none)+(none) tag=MainDir+H1Main
Logger : server=freeby.ben.algroup.co.uk:9001[23287] tag=MainServer+H1
dir=(none)+(none) tag=MainDir+H1Main
Child Init : pid=23351
Pretty straightforward, but note that the configurations used are the
merge of the main server's and the first virtual
host's. Also notice the Child
init at the end: this is because Apache decided
the load warranted starting another child to handle it.
But 2.0 is rather more complex:
MapToStorage : server=scuzzy.ben.algroup.co.uk:9001[79410] tag=MainServer+H1
dir=(none)+(none) tag=MainDir+H1Main unparsed_uri=/index.html
Fixups : server=scuzzy.ben.algroup.co.uk:9001[79410] tag=MainServer+H1
dir=(none)+(none) tag=MainDir+H1Main unparsed_uri=/index.html
InsertFilter : server=scuzzy.ben.algroup.co.uk:9001[79410] tag=MainServer+H1
dir=(none)+(none) tag=MainDir+H1Main unparsed_uri=/
Up to this point, we're checking for
/index.html and then continuing with
/. From here, we get lots of extra stuff caused
by mod_autoindex using internal requests to
construct the URLs for the index page:
CreateRequest : server=scuzzy.ben.algroup.co.uk:9001[79410] tag=MainServer+H1
dir=(none)+(none) tag=MainDir+H1Main unparsed_uri=(null)
MapToStorage : server=scuzzy.ben.algroup.co.uk:9001[79410] tag=MainServer+H1
dir=(none)+(none) tag=MainDir+H1Main unparsed_uri=/protected/
MergeDir : pBase: dir=(none)+(none) tag=MainDir+H1Main pNew: dir=/home/ben/
www5/docs/protected/ tag=H1ProtectedDirectory
CheckAccess : server=scuzzy.ben.algroup.co.uk:9001[79410] tag=MainServer+H1
dir=(none)+(none)+/home/ben/www5/docs/protected/ tag=MainDir+H1Main+H1Protected
Directory unparsed_uri=/protected/
Fixups : server=scuzzy.ben.algroup.co.uk:9001[79410] tag=MainServer+H1
dir=(none)+(none)+/home/ben/www5/docs/protected/ tag=MainDir+H1Main+H1Protected
Directory unparsed_uri=/protected/
CreateRequest : server=scuzzy.ben.algroup.co.uk:9001[79410] tag=MainServer+H1
dir=(none)+(none) tag=MainDir+H1Main unparsed_uri=(null)
QuickHandler : lookup_uri=1 server=scuzzy.ben.algroup.co.uk:9001[79410]
tag=MainServer+H1 dir=(none)+(none) tag=MainDir+H1Main unparsed_uri=/protected/index.
html
MergeDir : pBase: dir=(none)+(none) tag=MainDir+H1Main pNew: dir=/protected
tag=H1ProtectedLocation
Translate : uri=/protected/index.html server=scuzzy.ben.algroup.co.uk:9001[79410]
tag=MainServer+H1 dir=(none)+(none)+/protected tag=MainDir+H1Main+H1ProtectedLocation
unparsed_uri=/protected/index.html
MapToStorage : server=scuzzy.ben.algroup.co.uk:9001[79410] tag=MainServer+H1
dir=(none)+(none) tag=MainDir+H1Main unparsed_uri=/protected/index.html
MergeDir : pBase: dir=(none)+(none) tag=MainDir+H1Main pNew: dir=/home/ben/
www5/docs/protected/ tag=H1ProtectedDirectory
MergeDir : pBase: dir=(none)+(none)+/home/ben/www5/docs/protected/
tag=MainDir+H1Main+H1ProtectedDirectory pNew: dir=/protected tag=H1ProtectedLocation
CheckAccess : server=scuzzy.ben.algroup.co.uk:9001[79410] tag=MainServer+H1
dir=(none)+(none)+/home/ben/www5/docs/protected/+/protected
tag=MainDir+H1Main+H1ProtectedDirectory+H1ProtectedLocation unparsed_uri=/protected/
index.html
Fixups : server=scuzzy.ben.algroup.co.uk:9001[79410] tag=MainServer+H1
dir=(none)+(none)+/home/ben/www5/docs/protected/+/protected
tag=MainDir+H1Main+H1ProtectedDirectory+H1ProtectedLocation unparsed_uri=/protected/
index.html
And now normal programming is resumed:
Logger : server=scuzzy.ben.algroup.co.uk:9001[79410] tag=MainServer+H1
dir=(none)+(none) tag=MainDir+H1Main unparsed_uri=/
And finally, a request is created in anticipation of the next request
on the same connection:
CreateRequest : server=scuzzy.ben.algroup.co.uk:9001[79410] tag=MainServer+H1
dir=(no per-dir config) tag=(no per-dir config) unparsed_uri=(null)
At this point, 2.0 is finished.
Rather than go on at length, here's the most
complicated request we can make: http://host:9001/protected/.reveal:
CreateConnection : server=scuzzy.ben.algroup.co.uk:0[84997] tag=MainServer conn_id=0 [2.0]
PreConnection : keepalive=0 double_reverse=0 [2.0]
ProcessConnection: keepalive=0 double_reverse=0 [2.0]
CreateRequest : server=scuzzy.ben.algroup.co.uk:9001[84997] tag=MainServer+H1
dir=(no per-dir config) tag=(no per-dir config) unparsed_uri=(null) [2.0]
PostReadReq : method=GET uri=/protected/.reveal protocol=HTTP/1.0
server=freeby.ben.algroup.co.uk:9001[23288] tag=MainServer+H1
dir=(none)+(none) tag=MainDir+H1Main
QuickHandler : lookup_uri=0 server=scuzzy.ben.algroup.co.uk:9001[84997] tag=MainServer+H1
dir=(none)+(none) tag=MainDir+H1Main unparsed_uri=/protected/.reveal [2.0]
After the post_read_request phase, some merging is
done on the basis of location (1.3):
MergeDir : pBase: dir=(none)+(none) tag=MainDir+H1Main pNew: dir=/.reveal
tag=Revealer
MergeDir : pBase: dir=(none)+(none)+/.reveal tag=MainDir+H1Main+Revealer
pNew: dir=/protected tag=H1ProtectedLocation
Essentially the same thing happens in 2.0, but in a different order:
MergeDir : pBase: dir=/.reveal tag=Revealer pNew: dir=/protected
tag=H1ProtectedLocation
MergeDir : pBase: dir=(none)+(none) tag=MainDir+H1Main pNew: dir=/.reveal+/protected
tag=Revealer+H1ProtectedLocation
Of course, this illustrates the need to make sure your directory and
server mergers behave sensibly despite ordering changes. Note that
the end product of these two different ordering is, in fact,
identical.
Then the URL is translated into a filename, using the newly merged
directory configuration:
Translate : uri=/protected/.reveal
server=freeby.ben.algroup.co.uk:9001[23288] tag=MainServer+H1
dir=(none)+(none)+/.reveal+/protected
tag=MainDir+H1Main+Revealer+H1ProtectedLocation
MapToStorage : server=scuzzy.ben.algroup.co.uk:9001[84997] tag=MainServer+H1
dir=(none)+(none) tag=MainDir+H1Main unparsed_uri=/protected/.reveal
[2.0]
Now that the filename is known, even more merging can be done. Notice
that this time the section tagged as
H1ProtectedDirectory is pulled in, too:
MergeDir : pBase: dir=(none)+(none) tag=MainDir+H1Main pNew: dir=/home/
ben/www/APACHE3/docs/protected tag=H1ProtectedDirectory
MergeDir : pBase: dir=(none)+(none)+/home/ben/www/APACHE3/docs/protected
tag=MainDir+H1Main+H1ProtectedDirectory pNew: dir=/.reveal
tag=Revealer [1.3
MergeDir : pBase: dir=(none)+(none)+/home/ben/www/APACHE3/docs/protected+/.reveal
tag=MainDir+H1Main+H1ProtectedDirectory+Revealer pNew: dir=/
protected tag=H1ProtectedLocation [1.3]
MergeDir : pBase: dir=(none)+(none)+/home/ben/www5/docs/protected/
tag=MainDir+H1Main+H1ProtectedDirectory pNew: dir=/.reveal+/protected
tag=Revealer+H1ProtectedLocation [2.0]
Note that 2.0 cunningly reuses an earlier merge and does the job in
one less step.
And finally the request proceeds as usual:
HeaderParser : server=freeby.ben.algroup.co.uk:9001[23288] tag=MainServer+H1
dir=(none)+(none)+/home/ben/www/APACHE3/docs/protected+/.reveal+/
protected tag=MainDir+H1Main+H1ProtectedDirectory+
Revealer+H1ProtectedLocation
CheckAccess : server=freeby.ben.algroup.co.uk:9001[23288] tag=MainServer+H1
dir=(none)+(none)+/home/ben/www/APACHE3/docs/protected+/.reveal+/
protected tag=MainDir+H1Main+H1ProtectedDirectory+
Revealer+H1ProtectedLocation
TypeChecker : server=freeby.ben.algroup.co.uk:9001[23288] tag=MainServer+H1
dir=(none)+(none)+/home/ben/www/APACHE3/docs/protected+/.reveal+/
protected tag=MainDir+H1Main+H1ProtectedDirectory+
Revealer+H1ProtectedLocation
Fixups : server=freeby.ben.algroup.co.uk:9001[23288] tag=MainServer+H1
dir=(none)+(none)+/home/ben/www/APACHE3/docs/protected+/.reveal+/
protected tag=MainDir+H1Main+H1ProtectedDirectory+
Revealer+H1ProtectedLocation
InsertFilter : server=scuzzy.ben.algroup.co.uk:9001[84997] tag=MainServer+H1
dir=(none)+(none)+/home/ben/www5/docs/protected/+/.reveal+/protected
tag=MainDir+H1Main+H1ProtectedDirectory+Revealer+H1ProtectedLocation
unparsed_uri=/protected/.reveal [2.0]
Logger : server=freeby.ben.algroup.co.uk:9001[23288] tag=MainServer+H1
dir=(none)+(none)+/home/ben/www/APACHE3/docs/protected+/.reveal+/
protected tag=MainDir+H1Main+H1ProtectedDirectory+
Revealer+H1ProtectedLocation
CreateRequest : server=scuzzy.ben.algroup.co.uk:9001[84997] tag=MainServer+H1
dir=(no per-dir config) tag=(no per-dir config) unparsed_uri=(null)
[2.0]
And there we have it. Although the merging of directories, locations,
files, and so on gets rather hairy, Apache deals with it all for you,
presenting you with a single server and directory configuration on
which to base your code's decisions.
 |  |  | | 21.3. The Module Structure |  | 21.5. General Hints |
Copyright © 2003 O'Reilly & Associates. All rights reserved.
|