Pretty Zipping Quick HTTP Daemon
C Makefile
Switch branches/tags
Nothing to show
Clone or download
Fetching latest commit…
Cannot retrieve the latest commit at this time.
Failed to load latest commit information.


pretty zipping quick HTTPd

Only offers static file serving. No CGI, no FastCGI, no logging, no directory listings, no mime type lists, etc. Just something to point at a directory, give it a port, and have it serve content.

  • Uses chroot. chroot only works as root, so you have to be root. If you're not root (and are given chdir() instead), ../ escaping is possible at present.
  • Uses setuid. You don't even need the user to exist. The purpose is to change to some non-existent user and only be able to do stuff where the everything bit allows it. This also only comes from running it as root.
  • Has no validation/intelligence around methods, arguments, headers, etc. It just yanks the path between the first two spaces.
  • Uses sendfile(). It's very simple from the application standpoint and is extremely fast.

With some recent changes, it seems capable of 10,000 requests per second (7KiB file on tmpfs) at a concurrency of about 10-20. This is on a Core 2 Duo at 1.3GHz, 2010ish. It's using a pool of forks() all competing for accept(). 128 forks with a listen() queue length of 128. Haven't tried tuning those yet.

Have not been able to test it properly on the wire. Only localhost where the benchmarking tool is usually the bottleneck, especially Siege which maxes out at about 7,000 per second. webbench is the only one that's been able to keep up fairly well, but its timing logic is buggy.

I wanted to use Capsicum, but couldn't find a good way for it to work out. I'm almost certain there's a way, but you pretty much want to only read/write on the network socket and then only allow open/read on a file for serving. With chroot and setuid, there doesn't seem to be a whole ton that Capsicum offers here, but I'm probably mistaken on that.

HTTP client behaviors

If you send Chrome back data without headers, it actually loads up. surf did not like that. Sending back just HTTP/1.0 200 was enough to see text (maybe HTML, too?), and images, on both browsers. So while no browser author may like you for it, you can probably get away without MIME types and length for super simple web servers.


  • Make libraru and integrate it?
  • Add (precompressed) gzip support
  • Make the code less bad
  • Fix ugly write() usage to use strlen() and maybe a #define


Released into the public domain (unlicense)