Graham, I just decided that this was important to me (I wasn't using StaticFile until a few days ago), and applied your patch. It's working fine for me, but I realized that for most of my static files (small icons, css, etc) the size of the file was pretty low, and hence the IMS protocol wasn't saving me much. I.e. since the broswer still makes a request, and has to wait for the response, in the case of small files, you really don't gain anything. Network latency takes up more time than the actual xfer of that 400 byte image (for example). Seemed to me that setting the Expires header to something other than quixote's default of -1 would make a bigger difference in my situation than the IMS, so I added support for it to util.py. You pass in an optional cache_time option when constructing the StaticFile (it defaults to 3600 seconds, seems reasonable for a 'static file') and it sets the .cache attribute on the response object, letting it actually write the "Expires" header. StaticDirectory uses the same optional attribute in it's constructor (cache_time) and also defaults it to 3600, and passes that value to any StaticFiles it constructs. In the event you want the ims behavior without the expires benefit, set the cache_time to None. Quixote will then do it's default (currently set expires to -1). This would be handy if you were still working on the image (or stylesheet, or whatever)... Browser caching can cause major headaches sometimes. Shift-refresh is a close friend. I'm seeing a big help here when using high latency connections between the server and the browser, and think these two changes (ims and expires support) would be worth folding back into the main tree. I'm attaching two patches: - Use util.py.patch_orig-expires if you're patching the Quixote 0.6 util.py to include support for both ims and expires - Use util.py.patch_ims-expires to add support for expires to a util.py that has already been patched for ims. Hope this is useful, Jason Sibre -----Original Message----- From: quixote-users-bounces@mems-exchange.org [mailto:quixote-users-bounces@mems-exchange.org]On Behalf Of Graham Fawcett Sent: Monday, May 19, 2003 12:03 AM To: quixote-users@mems-exchange.org Subject: [Quixote-users] Adding If-Modified-Since support to util.StaticFile 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 _______________________________________________ Quixote-users mailing list Quixote-users@mems-exchange.org http://mail.mems-exchange.org/mailman/listinfo/quixote-users