Implement a basic HTTP memory cache

High-level design:
* shared memory cache with exclusive access for one querying/updating/remove operation at a time
* cache users submit a pending request and receive a result which either:
  * instructs the user to continue with the uncacheable request
  * instructs the user to continue with the cacheable request and provides a key with which to perform further cache operations as the response arrives
  * instructs the user to perform a revalidation of a matching, expired cached entry
  * instructs the user to quietly drop the pending request and await a cached response
* cache transparently drops uncacheable responses after they complete

This design handles multiple simultaneous requests for an in-progress cached response; each time a new portion of the body is stored, the list of awaiting consumers will be notified. It is also quite amenable to future changes to use asynchronous, push-based network operations.

Additionally, this changeset enables some really simple tests of caching behaviour by making all content tests run under a custom webserver that can track the number of full responses for a particular resource.