durusmail: quixote-users: Augmenting StaticFile to use "Expires:"
Adding If-Modified-Since support to util.StaticFile
2003-05-19
Re: Adding If-Modified-Since support to util.StaticFile
2003-05-19
Augmenting StaticFile to use "Expires:"
2003-05-28
Jason Sibre (3 parts)
Re: Augmenting StaticFile to use "Expires:"
2003-05-30
Augmenting StaticFile to use "Expires:"
Jason Sibre
2003-05-28
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
reply