A few notes on general pedagogical style here. In the interest ofconciseness, all structure declarations here are incomplete --- thereal ones have more slots, that I'm not telling you about. For the mostpart, these are reserved to one component of the server core oranother, and should be altered by modules with caution. However, insome cases, they really are things I just haven't gotten around to yet.Welcome to the bleeding edge.
Finally, here's an outline, to give you some bare idea of what's coming up, and in what order:
* Basic concepts.
o Handlers, Modules, and Requests
o A brief tour of a module
* How handlers work
o A brief tour of the request_rec
o Where request_rec structures come from
o Handling requests, declining, and returning error codes
o Special considerations for response handlers
o Special considerations for authentication handlers
o Special considerations for logging handlers
* Resource allocation and resource pools
* Configuration, commands and the like
o Per-directory configuration structures
o Command handling
o Side notes --- per-server configuration, virtual servers, etc.
Basic concepts.
We begin with an overview of the basic concepts behind the API, and how they are manifested in the code.
Handlers, Modules, and Requests
Apache breaks down request handling into a series of steps, more orless the same way the Netscape Server API does (although this API has afew more stages than NetSite does, as hooks for stuff I thought mightbe useful in the future). These are:
* URI -> Filename translation
* Auth ID checking [is the user who they say they are?]
* Auth aclearcase/" target="_blank" >ccess checking [is the user authorized here?]
* Access checking other than auth
* Determining MIME type of the object requested
* "Fixups" --- there aren't any of these yet, but the phase isintended as a hook for possible extensions like SetEnv, which don'treally fit well elsewhere.
* Actually sending a response back to the client.
* Logging the request
These phases are handled by looking at each of a succession of modules,looking to see if each of them has a handler for the phase, andattempting invoking it if so. The handler can typically do one of threethings:
* Handle the request, and indicate that it has done so by returning the magic constant OK.
* Decline to handle the request, by returning the magic integerconstant DECLINED. In this case, the server behaves in all respects asif the handler simply hadn't been there.
* Signal an error, by returning one of the HTTP error codes. Thisterminates normal handling of the request, although an ErrorDocumentmay be invoked to try to mop up, and it will be logged in any case.
Most phases are terminated by the first module that handles them;however, for logging, "fixups", and non-access authentication checking,all handlers always run (barring an error). Also, the response phase isunique in that modules may declare multiple handlers for it, via adispatch table keyed on the MIME type of the requested object. Modulesmay declare a response-phase handler which can handle any request, bygiving it the key */* (i.e., a wildcard MIME type specification).However, wildcard handlers are only invoked if the server has alreadytried and failed to find a more specific response handler for the MIMEtype of the requested object (either none existed, or they alldeclined).
The handlers themselves are functions of one argument (a request_rec structure. vide infra), which returns an integer, as above.
A brief tour of a module
At this point, we need to explain the structure of a module. Ourcandidate will be one of the messier ones, the CGI module --- thishandles both CGI scripts and the ScriptAlias config file command. It'sactually a great deal more complicated than most modules, but if we'regoing to have only one example, it might as well be the one with itsfingers in everyplace.
在这部分,我们需要解释模块的结构。我们使用CGI模块来分析 -- 它截获配置文件中的CGI scripts和ScriptAlias命令。它实际上比大多数的模块都要复杂的多。但是如果我们仅仅需要一个例子,因为这个模块出现在各处,所以它最好的例子之一。
Let's begin with handlers. In order to handle the CGI scripts, themodule declares a response handler for them. Because of ScriptAlias, italso has handlers for the name translation phase (to recogniseScriptAliased URI's), the type-checking phase (any ScriptAliasedrequest is typed as a CGI script).
让我们从句柄开始。为了截获CGI脚本,这个模块定义了一个应答句柄。针对ScriptAlias,它还有名字转换阶段的句柄(用于识别脚本别名的URI),也就是类型检查阶段(任何脚本别名请求都做为CGI script类型)。
The module needs to maintain some per (virtual) server information,namely, the ScriptAliases in effect; the module structure thereforecontains pointers to a functions which builds these structures, and toanother which combines two of them (in case the main server and avirtual server both have ScriptAliases declared).
这个模块需要管理一些(虚拟)主机的信息。即ScriptAliases。这个模块结构包括了一个指针,它指向一个建立这些结构的函数,和其它二个结构(因为主服务器和虚拟服务器都有ScriptAliases的定义)。
Finally, this module contains code to handle the ScriptAlias commanditself. This particular module only declares one command, but therecould be more, so modules have command tables which declare theircommands, and describe where they are permitted, and how they are to beinvoked.
最后,这个模块包括了处理ScriptAlias命令的代码。这个模块只定义了一个命令,但是它能做的更多。所以模块拥有command tables来定义他们的命令,并且何处是允许的,他们如何被调用。
A final note on the declared types of the arguments of some of thesecommands: a pool is a pointer to a resource pool structure; these areused by the server to keep track of the memory which has beenallocated, files opened, etc., either to service a particular request,or to handle the process of configuring itself. That way, when therequest is over (or, for the configuration pool, when the server isrestarting), the memory can be freed, and the files closed, en masse,without anyone having to write explicit code to track them all down anddispose of them. Also, a cmd_parms structure contains variousinformation about the config file being read, and other statusinformation, which is sometimes of use to the function which processesa config-file command (such as ScriptAlias). With no further ado, themodule itself:
在这些命令的参数的类型的定义中,最后需要注意的是:池是一个指向资源池结构的指针;他们通常用于服务端保持内存申请的轨迹,文件打开等,或者为实际请求提供服务,又或者处理配置本身的过程。那就是说,当请求结束(或者,对于配置池而言,当服务重起时),内存会被释放,文件会被关闭,包括这些全部。没有人会被迫写精确的代码来追踪和处理他们。并且,一个cmd_parms结构包括配置文件被读取时的不同的信息,和其它的状态信息。
/* Declarations of handlers. */
/* 定义句柄 */
int translate_scriptalias (request_rec *);
int type_scriptalias (request_rec *);
int cgi_handler (request_rec *);
/* Subsdiary dispatch table for response-phase handlers, by MIME type */
/* 子分派表,关于MIME类型,在响应阶段的句柄。
handler_rec cgi_handlers[] = {
{ "application/x-httpd-cgi", cgi_handler },
{ NULL }
};
/* Declarations of routines to manipulate the module's configuration
* info. Note that these are returned, and passed in, as void *'s;
* the server core keeps track of them, but it doesn't, and can't,
* know their internal structure.
*/
/* 定义模块配置信息的操作路径。注意他们被做为void*类型来返回,传递;
* 服务核心记录着他们,但是它不知道,也不可能知道他们的内部结构
*/
void *make_cgi_server_config (pool *);
void *merge_cgi_server_config (pool *, void *, void *);
/* Declarations of routines to handle config-file commands */
/* 定义处理配置文件中的命令的程序
char *script_alias (cmd_parms *, void *per_dir_config, char *fake, char *real);
command_rec cgi_cmds[] = {
{ "ScriptAlias", script_alias, NULL, RSRC_CONF, TAKE2,
"a fakename and a realname"},
{ NULL }
};
module cgi_module = {
STANDARD_MODULE_STUFF,
NULL, /* initializer */
NULL, /* dir config creater */
NULL, /* dir merger --- default is to override */
make_cgi_server_config, /* server config */
merge_cgi_server_config, /* merge server config */
cgi_cmds, /* command table */
cgi_handlers, /* handlers */
translate_scriptalias, /* filename translation */
NULL, /* check_user_id */
NULL, /* check auth */
NULL, /* check access */
type_scriptalias, /* type_checker */
NULL, /* fixups */
NULL /* logger */
};