Name

httpd — UCSPI-TCP HTTP server for static content

Synopsis

httpd {root}

Description

httpd prints requested public files from the root directory hierarchy. The Bernstein convention is for root to be /public/file, but it can use other conventional locations such as /home/publicfile/public or /var/www.

httpd accepts GET and HEAD requests on standard input, and responds on standard output according to the HTTP version employed in the request:

  • HTTP/0.9: httpd prints the requested file and exits.

  • HTTP/1.0: httpd prints an HTTP/1.0 header and the requested file. Then it exits.

  • HTTP/1.1: httpd prints an HTTP/1.1 header and the requested file in chunked format. Then it waits for further requests.

Unless the OLDPROTOCOLS environment variable is set, httpd only accepts the HTTP/1.1 request format, rejecting all others with a 426 error.

If the file is unopenable or if httpd does not like the request, httpd prints an error message and exits. If httpd runs out of memory, encounters an I/O error, or does not receive an input packet within 60 seconds, it exits silently.

httpd also prints local log information on standard error. Unless the LOGUNSUPPORTED environment variable is set, httpd does not output any log messages for requests with unsupported features.

httpd has exact-prefix support for If-Modified-Since: it uses code 304 if the Last-Modified contents are an exact prefix of the If-Modified-Since contents.

Normally httpd is run under a UCSPI-TCP server program (tcp-socket-accept, s6-tcpserver, or tcpserver spawning a server program per connection) to handle HTTP connections from hosts around the Internet. It can also be run under a UCSPI-SSL server program.

File handling

A request for http://v/f, where f does not end with a slash, refers to the file named ./v/f inside the root directory hierarchy. A request for http://v/f/, ending in a slash, refers to the file named ./v/f/index.html. httpd always converts the host name v to lowercase. HTTP/0.9 requests and old HTTP/1.0 requests do not specify a host name; in this case httpd uses the host name 0.

If it successfully opens the file, httpd uses the file name to select a file type for HTTP/1.0 and HTTP/1.1.

Unsupported features

httpd does not support file modification requests such as POST. httpd does not support SSI or CGI.

httpd rejects requests specifying Content-Length, Transfer-Encoding, Expect, If-Match, If-None-Match, or If-Unmodified-Since.

httpd does not generate its own directory listings, even if index.html does not exist. httpd rejects requests for directory names without terminating slashes; it does not redirect the requests.

Security

httpd chroots to root when it starts. It then sets its group id and user id to the numbers given in environment variables GID and UID, as set by envuidgid (or equivalent). httpd does not allow dots immediately after slashes in file names. It changes these dots to colons before attempting to open the file.

Note

Earlier versions of httpd required the /etc/leapsecs.dat to be copied under root . This file is now read before the chroot.

httpd will refuse to read a file if the file

  • is unreadable to user;

  • is unreadable to group;

  • is unreadable to world;

  • is world-executable without being user-executable; or

  • is anything other than a regular file: a directory, socket, device, etc.

Given that many clients are permissive HTTP/1.1 clients, the possibility that a HTTP/0.9 response could be misinterpreted as including headers, thus opening the possibility for headers to be faked by body content, is now a significant one and is what motivated curl in 2018 making HTTP/0.9 responses errors unless HTTP/0.9 is explicitly opted-in.

History

httpd was originally part of Daniel J. Bernstein's publicfile toolset in 1999. HTTP/1.1 was formalized that same year, having been proposed in 1997.

The default mode of only supporting HTTP/1.1 was introduced in 2025.

By that point: legitimate HTTP/0.9 and HTTP/1.0 traffic had been widely observed as having markedly dropped off since 2010, with even the (good-actor) robots having switched to HTTP/1.1; wget had switched to HTTP/1.1 by default in 2010; libcurl had supported HTTP/1.1 since 2001, had switched to it as the default in 2013, and had dropped HTTP/0.9 for security reasons, unless explicitly opted in, in 2018; libfetch had defaulted to HTTP/1.1; and Dominic Lovell had reported in the 2021 Web Almanac by the HTTP Archive essentially 0% use of HTTP/0.9 and HTTP/1.0. Moreover, old clients that could not use HTTP/1.1 were cut off from the modern WWW anyway for other reasons (the push for widespread use of HTTPS-only, and the deprecation of old encryption standards known by old clients) and would have to be behind HTTP/1.1-speaking proxies.

Over a quarter of a century since HTTP/1.1 was invented, permissively allowing earlier protocol versions by default is no longer a practical necessity and is now rather a weakness to be targetted.

Author

Original code and documentation by Daniel J. Bernstein. Documentation modernizations by Jonathan de Boyne Pollard.