function base_path() {
  return location.pathname.replace(/\/[^\/]*$/, '/');
}
Each test is run twice: once using etag/If-None-Match and once with
date/If-Modified-Since.  Each test run gets its own URL and randomized
content and operates independently.

The test steps are run with request_cache.length fetch requests issued
and their immediate results sanity-checked.  The cache.py server script
stashes an entry containing any If-None-Match, If-Modified-Since, Pragma,
and Cache-Control observed headers for each request it receives.  When
the test fetches have run, this state is retrieved from cache.py and the
expected_* lists are checked, including their length.

This means that if a request_* fetch is expected to hit the cache and not
touch the network, then there will be no entry for it in the expect_*
lists.  AKA (request_cache.length - expected_validation_headers.length)
should equal the number of cache hits that didn't touch the network.

Test dictionary keys:
- state: required string that determines whether the Expires response for
  the fetched document should be set in the future ("fresh") or past
  ("stale").
- vary: optional string to be passed to the server for it to quote back
  in a Vary header on the response to us.
- cache_control: optional string to be passed to the server for it to
  quote back in a Cache-Control header on the response to us.
- redirect: optional string "same-origin" or "cross-origin".  If
  provided, the server will issue an absolute redirect to the script on
  the same or a different origin, as appropriate.  The redirected
  location is the script with the redirect parameter removed, so the
  content/state/etc. will be as if you hadn't specified a redirect.
- request_cache: required array of cache modes to use (via `cache`).
- request_headers: optional array of explicit fetch `headers` arguments.
  If provided, the server will log an empty dictionary for each request
  instead of the request headers it would normally log.
- response: optional array of specialized response handling.  Right now,
  "error" array entries indicate a network error response is expected
  which will reject with a TypeError.
- expected_validation_headers: required boolean array indicating whether
  the server should have seen an If-None-Match/If-Modified-Since header
  in the request.
- expected_no_cache_headers: required boolean array indicating whether
  the server should have seen Pragma/Cache-control:no-cache headers in
  the request.
- expected_max_age_headers: optional boolean array indicating whether
  the server should have seen a Cache-Control:max-age=0 header in the
  request.