Code

Refactored CGI file serving so that FileClass contents are a) read more
authorrichard <richard@57a73879-2fb5-44c3-a270-3262357dd7e2>
Fri, 5 Dec 2003 03:28:38 +0000 (03:28 +0000)
committerrichard <richard@57a73879-2fb5-44c3-a270-3262357dd7e2>
Fri, 5 Dec 2003 03:28:38 +0000 (03:28 +0000)
cleanly and b) served with reasonable modification dates and handling of
if-modified-since.
File serving also sends a content-length now too.

git-svn-id: http://svn.roundup-tracker.org/svnroot/roundup/trunk@2014 57a73879-2fb5-44c3-a270-3262357dd7e2

CHANGES.txt
roundup/backends/blobfiles.py
roundup/cgi/client.py
roundup/date.py

index 069021acb39e5f9e0a4bf9a70d33afd91cb599da..5a8d645af427a020cc3b8b90338359378ad5c093 100644 (file)
@@ -20,6 +20,7 @@ Feature:
 - added script for copying user(s) from tracker to tracker (sf patch
   828963)
 - ignore incoming email with "Precedence: bulk" (sf patch 843489)
+- use HTTP 'Content-Length' header (modified sf patch 844577)
 
 Fixed:
 - mysql documentation fixed to note requirement of 4.0+ and InnoDB
index 0008ba60c468aacf0f7bfe91acb97fb23a72d9fa..1a04aae5b3b41e0e6d8a557f23e083578de8b107 100644 (file)
@@ -15,7 +15,7 @@
 # BASIS, AND THERE IS NO OBLIGATION WHATSOEVER TO PROVIDE MAINTENANCE,
 # SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
 # 
-#$Id: blobfiles.py,v 1.9 2002-09-10 00:11:50 richard Exp $
+#$Id: blobfiles.py,v 1.10 2003-12-05 03:28:38 richard Exp $
 '''
 This module exports file storage for roundup backends.
 Files are stored into a directory hierarchy.
@@ -87,17 +87,21 @@ class FileStorage:
     def getfile(self, classname, nodeid, property):
         '''Get the content of the file in the database.
         '''
+        # try a variety of different filenames - the file could be in the
+        # usual place, or it could be in a temp file pre-commit *or* it
+        # could be in an old-style, backwards-compatible flat directory
         filename = self.filename(classname, nodeid, property)
-        try:
-            return open(filename, 'rb').read()
-        except:
-            # now try the temp pre-commit filename
-            try:
-                return open(filename+'.tmp', 'rb').read()
-            except:
-                # fallback to flat file storage
-                filename = self.filename_flat(classname, nodeid, property)
-                return open(filename, 'rb').read()
+        flat_filename = self.filename_flat(classname, nodeid, property)
+        for filename in (filename, filename+'.tmp', flat_filename):
+            if os.path.exists(filename):
+                f = open(filename, 'rb')
+                break
+        else:
+            raise IOError, 'content file not found'
+        # snarf the contents and make sure we close the file
+        content = f.read()
+        f.close()
+        return content
 
     def numfiles(self):
         '''Get number of files in storage, even across subdirectories.
index a72ae84c0b5b5272ed4250bee5db20fdc3620905..fe8831371b8590243b153b644e93d7bd4bef0411 100644 (file)
@@ -1,4 +1,4 @@
-# $Id: client.py,v 1.148 2003-11-21 22:22:32 jlgijsbers Exp $
+# $Id: client.py,v 1.149 2003-12-05 03:28:38 richard Exp $
 
 __doc__ = """
 WWW request handler (also used in the stand-alone server).
@@ -471,13 +471,44 @@ class Client:
         if classname != 'file':
             raise NotFound, designator
 
-        # we just want to serve up the file named
         self.opendb('admin')
         file = self.db.file
-        self.additional_headers['Content-Type'] = file.get(nodeid, 'type')
-        self.write(file.get(nodeid, 'content'))
+
+        mime_type = file.get(nodeid, 'type')
+        content = file.get(nodeid, 'content')
+        lmt = file.get(nodeid, 'activity').timestamp()
+
+        self._serve_file(lmt, mime_type, content)
 
     def serve_static_file(self, file):
+        ''' Serve up the file named from the templates dir
+        '''
+        filename = os.path.join(self.instance.config.TEMPLATES, file)
+
+        # last-modified time
+        lmt = os.stat(filename)[stat.ST_MTIME]
+
+        # detemine meta-type
+        file = str(file)
+        mime_type = mimetypes.guess_type(file)[0]
+        if not mime_type:
+            if file.endswith('.css'):
+                mime_type = 'text/css'
+            else:
+                mime_type = 'text/plain'
+
+        # snarf the content
+        f = open(filename, 'rb')
+        try:
+            content = f.read()
+        finally:
+            f.close()
+
+        self._serve_file(lmt, mime_type, content)
+
+    def _serve_file(self, last_modified, mime_type, content):
+        ''' guts of serve_file() and serve_static_file()
+        '''
         ims = None
         # see if there's an if-modified-since...
         if hasattr(self.request, 'headers'):
@@ -485,25 +516,18 @@ class Client:
         elif self.env.has_key('HTTP_IF_MODIFIED_SINCE'):
             # cgi will put the header in the env var
             ims = self.env['HTTP_IF_MODIFIED_SINCE']
-        filename = os.path.join(self.instance.config.TEMPLATES, file)
-        lmt = os.stat(filename)[stat.ST_MTIME]
         if ims:
             ims = rfc822.parsedate(ims)[:6]
             lmtt = time.gmtime(lmt)[:6]
             if lmtt <= ims:
                 raise NotModified
 
-        # we just want to serve up the file named
-        file = str(file)
-        mt = mimetypes.guess_type(file)[0]
-        if not mt:
-            if file.endswith('.css'):
-                mt = 'text/css'
-            else:
-                mt = 'text/plain'
-        self.additional_headers['Content-Type'] = mt
-        self.additional_headers['Last-Modifed'] = rfc822.formatdate(lmt)
-        self.write(open(filename, 'rb').read())
+        # spit out headers
+        self.additional_headers['Content-Type'] = mime_type
+        self.additional_headers['Content-Length'] = len(content)
+        lmt = rfc822.formatdate(last_modified)
+        self.additional_headers['Last-Modifed'] = lmt
+        self.write(content)
 
     def renderContext(self):
         ''' Return a PageTemplate for the named page
index b07bcf1664a41a34550da3f28f26b9e568c5cb38..49151768aedaf563b78e76c689702609803b671d 100644 (file)
@@ -15,7 +15,7 @@
 # BASIS, AND THERE IS NO OBLIGATION WHATSOEVER TO PROVIDE MAINTENANCE,
 # SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
 # 
-# $Id: date.py,v 1.58 2003-12-04 23:06:53 richard Exp $
+# $Id: date.py,v 1.59 2003-12-05 03:28:38 richard Exp $
 
 __doc__ = """
 Date, time and time interval handling.
@@ -323,6 +323,11 @@ class Date:
         return '%4d%02d%02d%02d%02d%02d'%(self.year, self.month,
             self.day, self.hour, self.minute, self.second)
 
+    def timestamp(self):
+        ''' return a UNIX timestamp for this date '''
+        return calendar.timegm((self.year, self.month, self.day, self.hour,
+            self.minute, self.second, 0, 0, 0))
+
 class Interval:
     '''
     Date intervals are specified using the suffixes "y", "m", and "d". The