On Sep 15, 2009, at 5:30 PM, Christopher Lenz wrote:
This is a somewhat misleading description; it's not the lack of an
Expires header on CouchDB responses that results in incorrect
caching, it's a (really ugly) bug in the XMLHttpRequest
implementation of IE6 that does this. As far as I know, the cache
control headers sent by CouchDB are absolutely correct according to
the HTTP specification. Unconditionally adding an Expires header
(with a date in the past) just to workaround the XHR bug in IE6
*completely disables* any caching by any user agent!
One of the earlier patches did, but the current patch has no negative
effect on other browsers (other than adding 20 or so bytes to the
header) and brings XmlHttpRequest's behavior into line with the other
browsers. Adding Expires in conjunction with the must-revalidate
simply explicitly declares that any reuse of previously cached
documents must be revalidated with the server. There is no time that
the document is fresh and does not need revalidation. Without the
Expires header, other browsers guess what we'd like them to (that the
document isn't fresh) and IE 6's XmlHttpRequest uses heuristics and
typically guesses that the document is fresh. Adding an Expires
header in the past (or a value of 0) is explicitly mentioned in the
HTTP RFC as the mechanism to mark as response as immediately stale. I
kept the date in the past (though I would have preferred sending a 0)
since one of the UUID tests was over-specified and would fail if it
didn't have a valid date.
I've monitored the traffic and the logs before and after the patch and
see exactly what I would expect. Second requests to unchanged
documents get a 304 returned from the CouchDB and use the previously
retrieved value on every browser I've tried. Fire up Fiddler or your
favorite network monitoring tool and see for yourself.
Note also that IE6 gets cache invalidation right when you don't go
through XMLHttpRequest (that is, request CouchDB documents/views
directly).
A CouchDB-based application that runs on the client (CouchApp-
style), and that needs to work on IE6, has the option to force all
XHR requests to invalidate the cache (for example by using jQuery's
"cache=false" option to AJAX requests, which simply adds an extra
timestamp-valued query string parameter). In addition, it can choose
to do so if, and only if, it detects to be running on IE6. And of
course, applications accessing CouchDB only through server-side code
do not need to care about this issue at all.
Presumably we *could* add the browser detection and the conditional
addition of an Expires header to the CouchDB HTTP server, but
browser detection is a really slippery slope that I think we should
avoid, and IE6 is likely (or so I hope) to be pretty much extinct by
the time CouchDB reaches the 1.0 mark. In any case, I'm -1 on any
patch that does this unconditionally, and -0.5 on any patch that
does the Expires header dance conditionally. I'd be okay with adding
the cache busting trick to Futon (but again, only conditionally),
and documenting the issue and workaround for CouchApps.
Cheers,
The unconditional Expires header is the simplest fix. As far as I can
tell, it has no undesirable effects and accomplishes the goal. If
that doesn't go in, then I'd prefer to see the header values being
configurable instead of baking in other logic.
I don't want to get in a reopen war, but please reopen the bug.