4xthe mini multi-tasking HTTP/1.1 web-server
|
---|
This also allows the server to be relatively self-contained, requiring no additional dynamic runtime-support facilities over and above the host platform itself: you will not have to pre-download and pre-install dozens of other software packages: usually none, and at most one (for MS Windows).
The very wide availability of these interfaces (UNIX SVR4, BSD4.4, Linux, MS Windows NT/2K/XP/Vista/7, Cygwin, OpenVMS, NetBSD, and so on) is another reason why 4x is so portable.
4x avoids or works-around common socket interface bugs, including:
All of these choices aid portability and resource usage.
In other words, it is an old-style "forking" server, but taking advantage of HTTP/1.1 persistent connections to somewhat ameliorate the speed costs.
The forking architecture has several advantages, as well as a single drawback. On the plus side, the server does not need to second-guess the host operating-system - all concurrency control and sequencing is handed-off to the host systems, which are generally very good at it, having had decades of development and tuning.
Also, as each connection is completely self-contained (shares no address-space or open file-handles with any other connection), attacks that attempt to crash or corrupt the handling process can only effect that one connection - even if such an attack were successful, service for other clients or other connections would not be stopped or interfered with.
In summary:
This allows 4x to be much smaller, and leverages decades of multiplexing experience embodied in most host operating systems.
There is no need to explicitly deal with potential I/O race conditions, and each service process can remain blissfully unaware of the other processes - no explicit coordination is needed. This makes reasoning about the correctness of the software very much easier.
* a pure dataflow-driven architecture, thus no I/O-multiplexing APIs, thus: no select()! no poll() no /dev/poll or /dev/epoll no kqueue or kevent no readiness-signals no I/O-completion-ports * no aynschronous I/O APIs, thus: no AIO no realtime-signals no fcntl(..., F_SETOWN) or SIGURG semantics no mutexes no I/O-completion-ports * no new-fangled goodies (apart from IPv6 later, and optional PAM support): no high-resolution timers: use alarm() only no thread APIs of any kind no readv()/writev() or variations no sendfile() unless specifically requested, must work properly without * no kernel patches * no loadable kernel modules * no additional device-drivers * no explicit use of "alternative" process-scheduling facilities (eg: Solaris FSS or RT) The places where the implementation currently goes "outside the garden": * for security reasons, the lstat() and readlink() calls are allowed even though they are not part of POSIX 1003.1-1990. Because of the security implications and lack of any reasonable alternative, and the fact that almost all UNIX-like environments had both even in 1992, these two exceptions must be kept. * to allow zero-admin HTTP Basic Authentication, the PAM API can be optionally configured into the build. Currently, In the absence of that, HTTP Basic Authentication facilities will not be available. Other targets for the implementation are: * small executable size: target < 50Kb on SPARC and MIPS, < 45Kb on IA32 * beat the NCSA httpd 1.3, CERN w3 and Apache 1.3 scores in the "Acme98" performance test (see www.acme.com/software/thttpd/benchmarks.htm) on that same hardware/OS system, and to get within shouting distance of the thttpd scores if at all possible. ie: to prove that an on-demand-forking server can perform well on very old, plain old, modern and bleeding-edge systems (small, large and huge) without being specifically micro-tuned or restructured for any of those variations. * at most *gradual* decrease in performance with increaing number of concurrent users/sessions: no falling-off-a-cliff. To be a useful current server and a good netizen, it provides: * no gratuitous emmission of more network packets than necessary (not a "selfish" implementation). * support for HTTP/1.1 clients and facilities, expressly including: persistent connections with proper connection-management support of client pipelining If-Modified-Since conditional GETs outgoing streaming using chunked transfer-encoding incoming chunked transfer-encoding 100-Continue expectation processing Basic authentication (in this case, currently via PAM). * transparent support for HTTP/1.0 clients * CGI/1.1 with configurable timeout * bombproof finding of files to deliver: no escapes from the document-root, even if subsequently reenter it early decoding of URN-path, to avoid unexpected-character-escaping stripping of leading and trailing duplicate slashes from URNs (the implicit-Magic-Filesystem attack). support symbolic links but still with no escaping detect and disallow hard-links *all* file-/directory-access errors cause "Not Found" response: no side-band leaking of filesystem structures outside the document-root. Esp: no "access-denied" if non-existant file or directory, or for unreadable file, or even for disallowed files (hard-links, paths that attempt to escape with "..", invalid URN characters, and so on and so on). * Relatively-Simple-Admin: all configurable run-time options are expressed on the command-line. server can be gracefully stopped by either SIGINT, SIGQUIT or SIGTERM signals, and automatically shuts down all child processes. no need to adjust default per-process resource limits to run the server (server processes are small and use only 4 file-descriptors). no need for system-level thread-stack-size tuning (a common problem for multi-threaded servers, esp. on 32-bit platforms). error-logging to standard-error, so can be saved/discarded as desired. access-logging to standard-output, so can be saved/discarded as desired. Suggested Future Features: * Range requests and conditional range requests. * Support for IPv6. * transparent support for HTTP/0.9 clients.