Distributable cache for files

The current HTTP caching for files uses last-modified and an etag based on the ino, size and modified time. The problem with this approach is that both headers end up being inconsistent between nodes on a network.

This branch removes Last-Modified entirely, since it's impossible to make it consistent across nodes without using a networked filesystem.

This branch replaces the old etag with a new one that is a hash of the entire file. That etag is kept in an LRU cache keyed by the filepath, ino, size and mtime. This means that the first time a file is requested after process start or file modification it will not return an etag but will return an etag for every request for that file afterward.