SVN: r20964 - trunk/quixote

Andrew Kuchling <akuchlin-fVcApmY9cLvQ3/1i3zOLAti2O/[email protected]> Wed, 05 Mar 2003 13:36:46 -0500
Newsgroups gmane.comp.web.quixote.cvs
Message-ID <[email protected]>
Author: akuchlin
Date: 2003-03-05 13:36:45 -0500 (Wed, 05 Mar 2003)
New Revision: 20964

Modified:
   trunk/quixote/util.py
Log:
Improve docstrings
Add mime_type argument to StaticFile constructor
Use htmltext() to avoid XSS in directory listing


Modified: trunk/quixote/util.py
==============================================================================
--- trunk/quixote/util.py	(original)
+++ trunk/quixote/util.py	2003-03-05 13:36:46.000000000 -0500
@@ -17,7 +17,8 @@
 __revision__ = "$Id$"
 
 import sys, xmlrpclib
-import quixote, os, mimetypes, cgi, email, urllib
+import os, mimetypes, cgi, email, urllib
+from quixote import errors, html
 from cStringIO import StringIO
 
 def xmlrpc (request, func):
@@ -61,35 +62,40 @@
 
     """
     Wrapper for a static file on the filesystem.
-    
-    An instance is initialized with the absolute path to the file and 
-    optionally flags indicating whether the file's content should be cached 
-    and whether a symbolic link should be followed. The instance can then 
-    be called with a request object, so behaving like any Quixote object 
-    that models a resource.
     """
 
-    def __init__(self, path, use_cache=0, follow_symlinks=0):
-
-        # Check that the supplied path is absolute and (if a symbolic link) may 
+    def __init__(self, path, use_cache=0, follow_symlinks=0,
+                 mime_type=None):
+        """StaticFile(path:string, use_cache:bool, follow_symlinks:bool)
+        
+        Initialize instance with the absolute path to the file.
+        If 'use_cache' is true, the file's contents will be cached in memory.
+        If 'follow_symlinks' is true, symbolic links will be followed.
+        'mime_type' specifies the MIME type; if omitted, the MIME
+        type will be guessed, defaulting to text/plain.
+        """
+        
+        # Check that the supplied path is absolute and (if a symbolic link) may
         # be followed 
         self.path = path
-        assert os.path.isabs(path)
+        if not os.path.isabs(path):
+            raise ValueError, "Path %r is not absolute" % path
         if os.path.islink(path) and not follow_symlinks:
-            raise quixote.errors.TraversalError
+            raise errors.TraversalError(private_msg="Path %r is a symlink"
+                                        % path)
 
         self.use_cache = use_cache
         self.cache = None
 
         # Decide the Content-Type of the file
-        self.mimetype = \
+        self.mime_type = mime_type or \
                 mimetypes.guess_type(os.path.basename(path), strict=0)[0] \
                 or 'text/plain'
 
     def __call__(self, request):
         # Set the Content-Type for the response and return the file's contents;
         # use caching if enabled.
-        request.response.set_header('Content-Type', self.mimetype)
+        request.response.set_header('Content-Type', self.mime_type)
         if self.cache:
             contents = self.cache
         else:
@@ -105,19 +111,24 @@
 
     """
     Wrap a filesystem folder containing static files as a Quixote namespace.
-    
-    An instance is initialized with the absolute path to the folder and 
-    optionally flags indicating whether items within the folder should be 
-    cached and whether symbolic links should be followed.
     """
 
     _q_exports = []
 
     def __init__(self, path, use_cache=0, list_folder=0, follow_symlinks=0):
+        """StaticFilesFolder(path:string, use_cache:bool,
+                             list_folder:bool, follow_symlinks:bool)
+        
+        Initialize instance with the absolute path to the file.
+        If 'use_cache' is true, the file's content will be cached in memory.
+        If 'list_folder' is true, users can request a directory listing.
+        If 'follow_symlinks' is true, symbolic links will be followed.
+        """
 
         # Check that the supplied path is absolute
         self.path = path
-        assert os.path.isabs(path)
+        if not os.path.isabs(path):
+            raise ValueError, "Path %r is not absolute" % path
 
         self.use_cache = use_cache
         self.cache = {}
@@ -132,8 +143,9 @@
         """
         out = StringIO()
         if self.list_folder:
-            template = '<a href="%s">%s</a>%s'
-            print >>out, "<h1>%s</h1>" % request.environ['REQUEST_URI']
+            template = html.htmltext('<a href="%s">%s</a>%s')
+            print >>out, (html.htmltext("<h1>%s</h1>")
+                          % request.environ['REQUEST_URI'])
             print >>out, "<pre>"
             print >>out, template % ('..', '..', '')
             for filename in os.listdir(self.path):
@@ -154,7 +166,7 @@
         or StaticFilesFolder wrapper of it; use caching if that is in use.
         """
         if name in ('.', '..'):
-            raise quixote.errors.TraversalError
+            raise errors.TraversalError(private_msg="Attempt to use '.', '..'")
         if self.cache.has_key(name):
             # Get item from cache
             item = self.cache[name]
@@ -162,7 +174,7 @@
             # Get item from filesystem; cache it if caching is in use.
             item_filepath = os.path.join(self.path, name)
             if os.path.islink(item_filepath) and not self.follow_symlinks:
-                raise quixote.errors.TraversalError
+                raise errors.TraversalError
             if os.path.isdir(item_filepath):
                 item = StaticFilesFolder(item_filepath, self.use_cache,
                         self.list_folder, self.follow_symlinks)
@@ -170,7 +182,7 @@
                 item = StaticFile(item_filepath, self.use_cache,
                         self.follow_symlinks)
             else:
-                raise quixote.errors.TraversalError
+                raise errors.TraversalError
             if self.use_cache:
                 self.cache[name] = item
         if isinstance(item, StaticFilesFolder):
@@ -227,7 +239,7 @@
                 assert not os.path.islink(self.filepath) or self.follow_symlinks
                 scriptfile = open(self.filepath)
             except AssertionError, IOError:
-                raise quixote.errors.TraversalError
+                raise errors.TraversalError
             code = compile(scriptfile.read(), self.filepath, 'exec')
             scriptfile.close()
             if self.use_cache: