OLD | NEW |
(Empty) | |
| 1 # From http://tools.cherrypy.org/wiki/staticdirindex |
| 2 # CherryPy code is covered under a BSD License: |
| 3 # https://bitbucket.org/cherrypy/cherrypy/src/697c7af588b8/cherrypy/LICENSE.txt |
| 4 |
| 5 import os |
| 6 import re |
| 7 import stat |
| 8 import urllib |
| 9 import cherrypy |
| 10 from cherrypy.lib import cptools, http |
| 11 |
| 12 # Undercover kludge to wrap staticdir |
| 13 from cherrypy.lib.static import staticdir |
| 14 |
| 15 def staticdirindex(section, dir, root="", match="", content_types=None, |
| 16 index="", indexlistermatch="", indexlister=None, **kwargs): |
| 17 """Serve a directory index listing for a dir. |
| 18 |
| 19 Compatibility alert: staticdirindex is built on and is dependent on |
| 20 staticdir and its configurations. staticdirindex only works effectively |
| 21 in locations where staticdir is also configured. staticdirindex is |
| 22 coded to allow easy integration with staticdir, if demand warrants. |
| 23 |
| 24 indexlister must be configured, or no function is performed. |
| 25 indexlister should be a callable that accepts the following parameters: |
| 26 section: same as for staticdir (and implicitly calculated for it) |
| 27 dir: same as for staticdir, but already combined with root |
| 28 path: combination of section and dir |
| 29 |
| 30 Other parameters that are configured for staticdirindex will be passed |
| 31 on to indexlister. |
| 32 |
| 33 Should use priorty > than that of staticdir, so that only directories not |
| 34 served by staticdir, call staticdirindex. |
| 35 |
| 36 """ |
| 37 # first call old staticdir, and see if it does anything |
| 38 sdret = staticdir( section, dir, root, match, content_types, index ) |
| 39 if sdret: |
| 40 return True |
| 41 |
| 42 # if not, then see if we are configured to do anything |
| 43 if indexlister is None: |
| 44 return False |
| 45 |
| 46 req = cherrypy.request |
| 47 response = cherrypy.response |
| 48 |
| 49 match = indexlistermatch |
| 50 |
| 51 # N.B. filename ending in a slash or not does not imply a directory |
| 52 # the following block of code directly copied from static.py staticdir |
| 53 if match and not re.search(match, cherrypy.request.path_info): |
| 54 return False |
| 55 |
| 56 # Allow the use of '~' to refer to a user's home directory. |
| 57 dir = os.path.expanduser(dir) |
| 58 |
| 59 # If dir is relative, make absolute using "root". |
| 60 if not os.path.isabs(dir): |
| 61 if not root: |
| 62 msg = "Static dir requires an absolute dir (or root)." |
| 63 raise ValueError(msg) |
| 64 dir = os.path.join(root, dir) |
| 65 |
| 66 # Determine where we are in the object tree relative to 'section' |
| 67 # (where the static tool was defined). |
| 68 if section == 'global': |
| 69 section = "/" |
| 70 section = section.rstrip(r"\/") |
| 71 branch = cherrypy.request.path_info[len(section) + 1:] |
| 72 branch = urllib.unquote(branch.lstrip(r"\/")) |
| 73 |
| 74 # If branch is "", filename will end in a slash |
| 75 filename = os.path.join(dir, branch) |
| 76 |
| 77 # There's a chance that the branch pulled from the URL might |
| 78 # have ".." or similar uplevel attacks in it. Check that the final |
| 79 # filename is a child of dir. |
| 80 if not os.path.normpath(filename).startswith(os.path.normpath(dir)): |
| 81 raise cherrypy.HTTPError(403) # Forbidden |
| 82 # the above block of code directly copied from static.py staticdir |
| 83 # N.B. filename ending in a slash or not does not imply a directory |
| 84 |
| 85 # Check if path is a directory. |
| 86 |
| 87 path = filename |
| 88 # The following block of code copied from static.py serve_file |
| 89 |
| 90 # If path is relative, users should fix it by making path absolute. |
| 91 # That is, CherryPy should not guess where the application root is. |
| 92 # It certainly should *not* use cwd (since CP may be invoked from a |
| 93 # variety of paths). If using tools.static, you can make your relative |
| 94 # paths become absolute by supplying a value for "tools.static.root". |
| 95 if not os.path.isabs(path): |
| 96 raise ValueError("'%s' is not an absolute path." % path) |
| 97 |
| 98 try: |
| 99 st = os.stat(path) |
| 100 except OSError: |
| 101 # The above block of code copied from static.py serve_file |
| 102 |
| 103 return False |
| 104 |
| 105 if stat.S_ISDIR(st.st_mode): |
| 106 |
| 107 # Set the Last-Modified response header, so that |
| 108 # modified-since validation code can work. |
| 109 response.headers['Last-Modified'] = http.HTTPDate(st.st_mtime) |
| 110 cptools.validate_since() |
| 111 response.body = indexlister( section=section, dir=dir, path=path, |
| 112 **kwargs ) |
| 113 response.headers['Content-Type'] = 'text/html' |
| 114 req.is_index = True |
| 115 return True |
| 116 |
| 117 return False |
| 118 |
| 119 # Replace the real staticdir with our version |
| 120 cherrypy.tools.staticdir = cherrypy._cptools.HandlerTool( staticdirindex ) |
OLD | NEW |