Internet Explorer's Cache-Control Extensions

Some time ago, I wrote a summary of how Internet Explorer’s cache works. At the time, I left out mention of the two cache-control directives introduced by IE5: pre-check and post-check. These directives enable a “background update” mechanism where a cached resource is reused while simultaneously a background revalidation of the resource is performed, ensuring that any updates to the resource will be cached locally before the resource is reused a third time.

MSDN defines these directives as follows:

  • post-check - Defines an interval in seconds after which an entity should be checked for freshness. The check will happen after the user is shown the cached resource, but ensures that on the next visit the cached copy will be up-to-date.
  • pre-check - Defines an interval in seconds after which an entity must be checked for freshness prior to showing the user the cached resource.

The (sadly grainy & typo-ridden) timeline from MSDN shows how this mechanism might be used:

Caching timeline

As it turns out, there are few use-cases on today’s web where a site is willing to show the user potentially outdated content but also believes that it’s important enough to perform a background freshness check.

What’s worse is that, in my experience, no sites sending the post-check and pre-check directives are using them properly. Watching in Fiddler, all use of these directives I’ve seen is as follows:

Cache-Control: no-store, no-cache, must-revalidate, pre-check=0, post-check=0

Where exactly this bad pattern originally came from, I’m not sure, but it’s now replicated in many popular frameworks, and tons of sites send this header to try to forbid caching. If you want to prevent caching, do not include the post-check and pre-check directives. Doing so is completely unnecessary and results in wasted bandwidth and HTTP header processing cycles. In one of the IE7 betas, this pattern even resulted in a somewhat amusing and extremely frustrating bug.

A few other points about these directives:

  • post-check and pre-check must appear as a pair. If only one is present, it is ignored.
  • If both post-check and pre-check are specified and set to 0, both are entirely ignored.
  • post-check must be <= pre-check. If it is not, it will be set = to pre-check.
  • If post-check is set to 0 (and pre-check is >0), a background task will spin up to freshen the cache of the just-downloaded file.
    • So, if you want to double the load on your site for no reason, send Cache-Control: post-check=0; pre-check=1
  • Generally, the pre-check directive is very similar to max-age.
    • However, IE's implementation of max-age takes the Age response header into account. In contrast, the implementation of post-check and pre-check do not. Hence, pre-check is equivalent to max-age only when there is no Age header on the response.
    • IE will stop examining Cache-Control headers for expiration time information after it encounters a header containing a max-age directive. So, if you send multiple Cache-Control headers, post-check and pre-check should appear in the same header as the directive containing the max-age directive.

If you’re using post-check and pre-check on your site, I’d love to hear from you.  Thanks!

-Eric