PageRenderTime 63ms CodeModel.GetById 27ms app.highlight 28ms RepoModel.GetById 2ms app.codeStats 0ms

/circuits/web/dispatchers/static.py

https://bitbucket.org/prologic/circuits/
Python | 145 lines | 131 code | 6 blank | 8 comment | 0 complexity | 37783e36f49e8bf9b8aab1e6f5c9a565 MD5 | raw file
  1# Module:   static
  2# Date:     13th September 2007
  3# Author:   James Mills, prologic at shortcircuit dot net dot au
  4
  5"""Static
  6
  7This modStatic implements a Static dispatcher used to serve up static
  8resources and an optional apache-style directory listing.
  9"""
 10
 11import os
 12from string import Template
 13
 14try:
 15    from urllib import quote, unquote
 16except ImportError:
 17    from urllib.parse import quote, unquote  # NOQA
 18
 19from circuits import handler, BaseComponent
 20
 21from circuits.web.tools import serve_file
 22
 23DEFAULT_DIRECTORY_INDEX_TEMPLATE = """
 24<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
 25 "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
 26<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
 27    <head>
 28        <meta http-equiv="Content-type" content="text/html; charset=utf-8" />
 29        <meta http-equiv="Content-Language" content="en-us" />
 30        <meta name="robots" content="NONE,NOARCHIVE" />
 31        <title>Index of $directory</title>
 32    </head>
 33    <body>
 34        <h1>Index of $directory</h1>
 35        <ul>
 36            $url_up
 37            $listing
 38        </ul>
 39    </body>
 40</html>
 41"""
 42
 43_dirlisting_template = Template(DEFAULT_DIRECTORY_INDEX_TEMPLATE)
 44
 45
 46class Static(BaseComponent):
 47
 48    channel = "web"
 49
 50    def __init__(self, path=None, docroot=None,
 51                 defaults=("index.html", "index.xhtml",), dirlisting=False):
 52        super(Static, self).__init__()
 53
 54        self.path = path
 55        self.docroot = os.path.abspath(docroot) if docroot is not None else os.path.abspath(os.getcwd())
 56        self.defaults = defaults
 57        self.dirlisting = dirlisting
 58
 59    @handler("request", priority=0.9)
 60    def _on_request(self, event, request, response):
 61        if self.path is not None and not request.path.startswith(self.path):
 62            return
 63
 64        path = request.path
 65
 66        if self.path is not None:
 67            path = path[len(self.path):]
 68
 69        path = unquote(path.strip("/"))
 70
 71        if path:
 72            location = os.path.abspath(os.path.join(self.docroot, path))
 73        else:
 74            location = os.path.abspath(os.path.join(self.docroot, "."))
 75
 76        if not os.path.exists(location):
 77            return
 78
 79        if not location.startswith(os.path.dirname(self.docroot)):
 80            return  # hacking attemp e.g. /foo/../../../../../etc/shadow
 81
 82        # Is it a file we can serve directly?
 83        if os.path.isfile(location):
 84            # Don't set cookies for static content
 85            response.cookie.clear()
 86            try:
 87                return serve_file(request, response, location)
 88            finally:
 89                event.stop()
 90
 91        # Is it a directory?
 92        elif os.path.isdir(location):
 93
 94            # Try to serve one of default files first..
 95            for default in self.defaults:
 96                location = os.path.abspath(
 97                    os.path.join(self.docroot, path, default)
 98                )
 99                if os.path.exists(location):
100                    # Don't set cookies for static content
101                    response.cookie.clear()
102                    try:
103                        return serve_file(request, response, location)
104                    finally:
105                        event.stop()
106
107            # .. serve a directory listing if allowed to.
108            if self.dirlisting:
109                directory = os.path.abspath(os.path.join(self.docroot, path))
110                cur_dir = os.path.join(self.path, path) if self.path else ""
111
112                if not path:
113                    url_up = ""
114                else:
115                    if self.path is None:
116                        url_up = os.path.join("/", os.path.split(path)[0])
117                    else:
118                        url_up = os.path.join(cur_dir, "..")
119                    url_up = '<li><a href="%s">%s</a></li>' % (url_up, "..")
120
121                listing = []
122                for item in os.listdir(directory):
123                    if not item.startswith("."):
124                        url = os.path.join("/", path, cur_dir, item)
125                        location = os.path.abspath(
126                            os.path.join(self.docroot, path, item)
127                        )
128                        if os.path.isdir(location):
129                            li = '<li><a href="%s/">%s/</a></li>' % (
130                                quote(url), item
131                            )
132                        else:
133                            li = '<li><a href="%s">%s</a></li>' % (
134                                quote(url), item
135                            )
136                        listing.append(li)
137
138                ctx = {}
139                ctx["directory"] = cur_dir or os.path.join("/", cur_dir, path)
140                ctx["url_up"] = url_up
141                ctx["listing"] = "\n".join(listing)
142                try:
143                    return _dirlisting_template.safe_substitute(ctx)
144                finally:
145                    event.stop()