Index: sky/tools/staticdirindex.py |
diff --git a/sky/tools/staticdirindex.py b/sky/tools/staticdirindex.py |
new file mode 100644 |
index 0000000000000000000000000000000000000000..35eded7fbf10e59d23f0c8f800c90cb9c9df528a |
--- /dev/null |
+++ b/sky/tools/staticdirindex.py |
@@ -0,0 +1,120 @@ |
+# From http://tools.cherrypy.org/wiki/staticdirindex |
+# CherryPy code is covered under a BSD License: |
+# https://bitbucket.org/cherrypy/cherrypy/src/697c7af588b8/cherrypy/LICENSE.txt |
+ |
+import os |
+import re |
+import stat |
+import urllib |
+import cherrypy |
+from cherrypy.lib import cptools, http |
+ |
+# Undercover kludge to wrap staticdir |
+from cherrypy.lib.static import staticdir |
+ |
+def staticdirindex(section, dir, root="", match="", content_types=None, |
+ index="", indexlistermatch="", indexlister=None, **kwargs): |
+ """Serve a directory index listing for a dir. |
+ |
+ Compatibility alert: staticdirindex is built on and is dependent on |
+ staticdir and its configurations. staticdirindex only works effectively |
+ in locations where staticdir is also configured. staticdirindex is |
+ coded to allow easy integration with staticdir, if demand warrants. |
+ |
+ indexlister must be configured, or no function is performed. |
+ indexlister should be a callable that accepts the following parameters: |
+ section: same as for staticdir (and implicitly calculated for it) |
+ dir: same as for staticdir, but already combined with root |
+ path: combination of section and dir |
+ |
+ Other parameters that are configured for staticdirindex will be passed |
+ on to indexlister. |
+ |
+ Should use priorty > than that of staticdir, so that only directories not |
+ served by staticdir, call staticdirindex. |
+ |
+""" |
+ # first call old staticdir, and see if it does anything |
+ sdret = staticdir( section, dir, root, match, content_types, index ) |
+ if sdret: |
+ return True |
+ |
+ # if not, then see if we are configured to do anything |
+ if indexlister is None: |
+ return False |
+ |
+ req = cherrypy.request |
+ response = cherrypy.response |
+ |
+ match = indexlistermatch |
+ |
+ # N.B. filename ending in a slash or not does not imply a directory |
+ # the following block of code directly copied from static.py staticdir |
+ if match and not re.search(match, cherrypy.request.path_info): |
+ return False |
+ |
+ # Allow the use of '~' to refer to a user's home directory. |
+ dir = os.path.expanduser(dir) |
+ |
+ # If dir is relative, make absolute using "root". |
+ if not os.path.isabs(dir): |
+ if not root: |
+ msg = "Static dir requires an absolute dir (or root)." |
+ raise ValueError(msg) |
+ dir = os.path.join(root, dir) |
+ |
+ # Determine where we are in the object tree relative to 'section' |
+ # (where the static tool was defined). |
+ if section == 'global': |
+ section = "/" |
+ section = section.rstrip(r"\/") |
+ branch = cherrypy.request.path_info[len(section) + 1:] |
+ branch = urllib.unquote(branch.lstrip(r"\/")) |
+ |
+ # If branch is "", filename will end in a slash |
+ filename = os.path.join(dir, branch) |
+ |
+ # There's a chance that the branch pulled from the URL might |
+ # have ".." or similar uplevel attacks in it. Check that the final |
+ # filename is a child of dir. |
+ if not os.path.normpath(filename).startswith(os.path.normpath(dir)): |
+ raise cherrypy.HTTPError(403) # Forbidden |
+ # the above block of code directly copied from static.py staticdir |
+ # N.B. filename ending in a slash or not does not imply a directory |
+ |
+ # Check if path is a directory. |
+ |
+ path = filename |
+ # The following block of code copied from static.py serve_file |
+ |
+ # If path is relative, users should fix it by making path absolute. |
+ # That is, CherryPy should not guess where the application root is. |
+ # It certainly should *not* use cwd (since CP may be invoked from a |
+ # variety of paths). If using tools.static, you can make your relative |
+ # paths become absolute by supplying a value for "tools.static.root". |
+ if not os.path.isabs(path): |
+ raise ValueError("'%s' is not an absolute path." % path) |
+ |
+ try: |
+ st = os.stat(path) |
+ except OSError: |
+ # The above block of code copied from static.py serve_file |
+ |
+ return False |
+ |
+ if stat.S_ISDIR(st.st_mode): |
+ |
+ # Set the Last-Modified response header, so that |
+ # modified-since validation code can work. |
+ response.headers['Last-Modified'] = http.HTTPDate(st.st_mtime) |
+ cptools.validate_since() |
+ response.body = indexlister( section=section, dir=dir, path=path, |
+ **kwargs ) |
+ response.headers['Content-Type'] = 'text/html' |
+ req.is_index = True |
+ return True |
+ |
+ return False |
+ |
+# Replace the real staticdir with our version |
+cherrypy.tools.staticdir = cherrypy._cptools.HandlerTool( staticdirindex ) |