horde
文件大小: unknow
源码售价: 5 个金币 积分规则     积分充值
资源说明:An HTTP server designed around message-passing daemons
-=====--------------------------------------------------------
:Horde: An HTTP server designed around message-passing daemons
-=====--------------------------------------------------------

This document is a cross between a specification, a manual, and a plan of future development; these three functions will be separated out as the project matures.

Release Notes: see NEWS
License details: see COPYING

How the server works:
---------------------
The actual 'horde' process is the dispatcher, with the following functions:
	Is the initial process, holds the listen()ing socket, has a pipe() to each child produced
	When a request comes in on socket, fork() a 'net' process
	When a request comes in over a pipe, hand it off to whatever process is registered to handle it (if none are running, fork() a new one)
	When a response comes in over a pipe, send it to the appropriate recipient.

Every child process (with the exception of 'net') is a 'handler', which is registered with the dispatcher by an entry in a .horde file; typically the name should be {modulename}.horde.
The core handlers are:
	net		Calls accept() on the listening socket, does protocol with HTTP.  Calls 'ext', and 'proc' to obtain the entity body.  Makes a 'tail' call when done
	proc	Loads a resource from disk, and applies appropriate preprocessing to it.  Calls appropriate preprocessor daemons
	ext		Determines the Content-Type (MIMEtype) of a document based on its extension.  Is a daemon (rather than a libhorde function) in order to amortise the cost of reading in /etc/mime.types
	log		Writes lines to the log file (/var/log/horde).  Serialises these writes, obviating the need for locking
	stats	Tracks server stats like bytes_today, for use by eg. traffic limiters
Other handlers go in the modules/ directory; any site-specific handlers go in modules/local/.

The standard way of extending horde's capabilities is by registering processors with 'proc'; this is done by an entry in a .proc file; typically the name should be {modulename}.proc.
One preprocessor is provided as an example of how the proc system works; it is called 'pico' and emulates the dynamic rewriting functions of the "httpico" webserver, an earlier (and somewhat unsuccessful) project by the same developer.  (The main reason for implementing 'pico' was that the author had used its features throughout his own website)

Good things to note: because all the preprocessor daemons communicate only through textual IPC (using a simple RPC protocol), they can be implemented in a wide variety of languages, although it helps if you have a binding for the hmsg-related libhorde functions.

Readiness:
----------
All workers that may conceivably need to issue sub-requests must use the (ready) message to signal that they are able to take a new request.
All workers of which only one instance may exist must always be ready to accept a new request; this usually means that they never issue sub-requests and use their stdin-buffer to queue requests.
A module uses the 'only' flag to indicate in which of the above categories it resides.  At present the dispatcher assumes these categories are mutually exclusive and exhaustive.

If you need to implement functionality involving both a gatekeeper to a shared resource and the use of subrequests (eg. to gather state), you should split it into two modules, so that the gatekeeper merely becomes one of the subrequests of the application logic / driver module.

proc Rules:
-----------
The preprocessor-matching rules in .proc are expression trees based very loosely on LISP forms (except using [square brackets] instead of (parens) because the latter are already used by the horde message protocol.  In a future version the roles of these two characters may be swapped).  For instance, the rule used by 'pico' is:
	[or [= [ext]["pico"]] [and [= [subst [0][5][ctype]]["text/"]] [grep [str [body]]["dlen by way of new_hmsg_d().  Similarly, it allows them in htag values.  BUT... it doesn't allow them in funct or htag names, which should be purely textual.
On a related note, some preprocessors (namely, those operating only on textual data, and which will typically only be /called/ for textual data) can pretend all-the-world's-a-Cstring, and ignore the possibility of NULs - after all, who passes an image file to a preprocessor?  You may, however, feel that robustness is worth the slight extra complication involved in using hmsg->dlen.
Another way to pass binary data, rather than using new_hmsg_d(), is to use the (read) tag, and either a file on disk or a FIFO (named pipe); this will be abstracted away on the receiving side by libhorde.  Notice however that this facility means that hmsg_from_str() can block (because it's reading from a file which might be a pipe).

hmsg format:
------------
An hmsg (pronounced 'aitch-message') consists of 'funct', 'data', and a list of 'htags', each of which is a key-value pair.
'funct' and the htag names (keys) are purely textual and may not contain parens, newlines, spaces or NULs.
'data' and the htag values may contain any character; on the wire these are escaped as follows:
	NUL		-> \0
	newline	-> \n
	(		-> \[
	)		-> \]
	\		-> \\
The representation of an hmsg is as follows:
	(funct (htag-name htag-value) (htag-name htag-value) data)

Unit Testing:
-------------
horde's textual IPC scheme makes automated testing of individual modules easy.  One way to do it would be to run "./path/to/module < test-input | diff expected-output", however this isn't very flexible.
Consequently, horde includes a testing framework, whereby a test for a module ./path/to/module can be registered by creating a test specification at ./path/to/module.tests/name.test; all registered tests can then be run with ./tests, which collates and summarises the results.  The test specification format is line-based; every line starts with a line type identifier followed by a space, as follows:
$ The human-readable name of the test
# A comment
< A line to supply to the module's input
> A line expected from the module's output
Typically, < and > lines will be hmsgs, though this isn't always the case (eg. the stock tests for 'modules/core/log' use (logf /dev/stdout) to redirect the log entries to standard output, then >-expect the resulting log entries).
A horde module should not be considered complete unless accompanied by a suite of tests covering essentially all of its normal functionality.

Plans:
------
TODO: arguments to 'tests', like --all (default & current behaviour), ./path/to/module (run all tests in ./path/to/module.tests), ./path/to/module.tests/which.test (run only the specified test), --diff (use 'diff -u' to compare the expected and received output, instead of doing a straight line-by-line comparison)
TODO: make the libhorde interfaces use string structs (rather than having the new_hmsg and new_hmsg_d profusion)
TODO: cull excessive idle workers
TODO: add a second form of time profiling in dispatcher, which doesn't charge a worker for the time it spends waiting for someone else (start counting when you receive a message, stop counting when you send one)
TODO: make proc pay attention to the (onfail) attribute
TODO: make 'net' handle errors by requesting (proc /500.htm), though find a way to detect loops (in case a 500 page triggers an error/bug within proc or one of its processors)
TODO: HTTP pipelining in 'net' (controlled, of course, by hst.pipeline)
TODO: Handle hostnames in GET-url (check it's ours!)
TODO: Bernstein chaining - have a launcher that binds the socket, drops privs, then execs horde.  At the moment horde could (maybe) regain privs if compromised

本源码包内暂不包含可直接显示的源代码文件,请下载源码包。