Hi folks, I'd like to suggest the changes below to add support for the If-Modified-Since header (hereafter called IMS), which can substantially improve cache resuse (and thus server performance!) for static files. There are two main requirements to meet in order to get IMS support working: -- all responses for the static asset must include a Last-Modified header. This lets the browser know that IMS might be possible; next time it requests the asset it includes the IMS header with the asset's Last-Modified date; -- the server may choose to detect an IMS header and, if the asset has not been modified since the IMS date, it may return a 304 Not Modified with a content-length of 0. This directs the browser to re-use the cached copy of the file. In Quixote, this means that the IMS header must be included in the request.environ dict. I've only been using Medusa and Twisted as request producers; a patch for medusa_http is included below, and the twisted_http will work as is. Other handlers may need work to take advantage of this optimization. Note that IMS is totally separate in intent from the Expires cache directive; it's an active protocol, not a caching hint. My experience with Expires vs. IMS is that IMS leads to the expected behaviour (i.e., browser doesn't require a second download of the file) more frequently. Here's the util.py patch: --- util.py Tue Apr 08 12:48:54 2003 +++ util_new.py Mon May 19 00:36:52 2003 @@ -22,4 +22,6 @@ from quixote import errors, html from cStringIO import StringIO +from rfc822 import formatdate, parsedate +import time def xmlrpc (request, func): @@ -93,4 +95,14 @@ def __call__(self, request): + last_mod = os.stat(self.path).st_mtime + # check for an If-Modified-Since header, and try to honour it. + ims = request.get_header('if-modified-since') + if ims: + ims_value = parsedate(ims) + last_mod_tuple = time.gmtime(last_mod) + if last_mod_tuple[:6] <= ims_value[:6]: + request.response.set_status(304, 'Not Modified') + return '' + # Set the Content-Type for the response and return the file's contents. request.response.set_content_type(self.mime_type) @@ -100,4 +112,9 @@ contents = fsfile.read() fsfile.close() + + # set the last-modified header (in GMT) + last_modified = formatdate(last_mod) + request.response.set_header('Last-Modified', last_modified) + return contents and for medusa_http: --- server\medusa_http.py Mon May 19 00:38:38 2003 +++ \python22\lib\site-packages\quixote\server\medusa_http.py Mon May 19 00:37:47 2003 @@ -49,4 +49,5 @@ environ = {'REQUEST_METHOD':request.command, + 'HTTP_IF_MODIFIED_SINCE':msg.get('If-modified-since'), 'ACCEPT_ENCODING':msg.get('Accept-encoding'), 'CONTENT_TYPE': msg.get('Content-type'), -- Graham