def __init__(self, path, blacklist=(re.compile('.*\.py[co]?$'), ), defaults=('index.html', 'index.htm')): # Make sure our path is unicode. if not isinstance(path, unicode): path = decode(path) self.path = os.path.normpath(os.path.realpath(path)) self.defaults = defaults # Build the blacklist. self.blacklist = [] for bl in blacklist: if isinstance(bl, str): bl = re.compile(bl) self.blacklist.append(bl)
def list_directory(self, request, path): """ Generate a directory listing and return it. """ # Normalize the path. full_path = os.path.normpath(os.path.join(self.path, path)) # Get the URL, which is just request.path decoded. url = decode(urllib.unquote(request.path)) if not url.startswith(u'/'): url = u'/%s' % url if not url.endswith(u'/'): return redirect(u'%s/' % url) go_up = u'' if url.strip(u'/'): go_up = u'<p><a href="..">Up to Higher Directory</a></p>' files = [] dirs = [] try: contents = os.listdir(full_path) except OSError: abort(403) for p in sorted(contents, key=unicode.lower): if _is_hidden(p, full_path): continue full = os.path.join(full_path, p) try: fp = full if os.path.isdir(full): fp += '/' self.check_blacklist(fp) except HTTPException: continue stat = os.stat(full) mtime = datetime.fromtimestamp(stat.st_mtime).strftime( u'%Y-%m-%d %I:%M:%S %p' ) if os.path.isdir(full): cls = u'folder' link = u'%s/' % p size = u'<span class="faint">Directory</span>' obj = dirs elif os.path.isfile(full): cls = 'document' ext = p[p.rfind('.')+1:] if ext in ('jpg','jpeg','png','gif','bmp'): cls = 'image' elif ext in ('zip','gz','tar','7z','tgz'): cls = 'zip' elif ext in ('mp3','mpa','wma','wav','flac','mid','midi','raw', 'mod','xm','aac','m4a','ogg','aiff','au','voc','m3u', 'pls','asx'): cls = 'audio' elif ext in ('mpg','mpeg','mkv','mp4','wmv','avi','mov'): cls = 'video' link = p size = _human_readable_size(stat.st_size) obj = files else: continue obj.append(DIRECTORY_ENTRY.safe_substitute( cls=cls, url=url + link, name=p, size=size, modified=mtime )) if files or dirs: files = u''.join(dirs) + u''.join(files) else: files = (u'<tr><td colspan="3" class="noborder">' u'<div class="footer center">' u'This directory is empty.</div></td></tr>') if Application.current_app and Application.current_app.debug: rtime = u'%0.3f ms' % (1000 * request.time) else: rtime = u'' output = DIRECTORY_PAGE.safe_substitute( path=url, go_up=go_up, host=request.host, scheme=request.scheme, content=''.join(files), debug=rtime ) return output, 200, {'Content-Type': 'text/html; charset=UTF-8'}
def __call__(self, request): """ Serve a request. """ try: path = request.match.groups()[-1] if path is None: path = urllib.unquote_plus(request.path) except (AttributeError, IndexError): path = urllib.unquote_plus(request.path) # Convert the path to unicode. path = decode(path) # Strip off a starting quote. if path.startswith('/') or path.startswith('\\'): path = path[1:] # Normalize the path. full_path = os.path.normpath(os.path.join(self.path, path)) # Validate the request. if not full_path.startswith(self.path): abort(403) elif not os.path.exists(full_path): abort() elif not os.access(full_path, os.R_OK): abort(403) # Is this a directory? if os.path.isdir(full_path): # Check defaults. for f in self.defaults: full = os.path.join(full_path, f) if os.path.exists(full): request.path = urllib.quote(full.encode('utf8')) if hasattr(request, 'match'): del request.match return self.__call__(request) # Guess not. List it. if hasattr(request, 'match'): return self.list_directory(request, path) else: body, status, headers = self.list_directory(request, path) if isinstance(body, unicode): body = body.encode('utf-8') headers['Content-Length'] = len(body) request.send_status(status) request.send_headers(headers) request.send(body) request.finish() return # Blacklist Checking. self.check_blacklist(full_path) # Let's send the file. request.auto_finish = False request.send_file(full_path)
def __call__(self, request): """ Serve a request. """ try: path = request.match.group(1) if path is None: path = urllib.unquote_plus(request.path) except (AttributeError, IndexError): path = urllib.unquote_plus(request.path) # Convert the path to unicode. path = decode(path) # Strip off a starting quote. if path.startswith('/') or path.startswith('\\'): path = path[1:] # Normalize the path. full_path = os.path.normpath(os.path.join(self.path, path)) # Validate the request. if not full_path.startswith(self.path): abort(403) elif not os.path.exists(full_path): abort() elif not os.access(full_path, os.R_OK): abort(403) # Is this a directory? if os.path.isdir(full_path): # Check defaults. for f in self.defaults: full = os.path.join(full_path, f) if os.path.exists(full): request.path = urllib.quote(full.encode('utf8')) if hasattr(request, 'match'): del request.match return self.__call__(request) # Guess not. List it. if hasattr(request, 'match'): return self.list_directory(request, path) else: body, status, headers = self.list_directory(request, path) if isinstance(body, unicode): body = body.encode('utf-8') headers['Content-Length'] = len(body) request.send_status(status) request.send_headers(headers) request.send(body) request.finish() return # Blacklist Checking. self.check_blacklist(full_path) # Try rendering the content. ext = os.path.basename(full_path).rpartition('.')[-1] if ext in self.renderers: f, mtime, size, type = self.renderers[ext](request, full_path) else: # Get the information for the actual file. f = None stat = os.stat(full_path) mtime = stat.st_mtime size = stat.st_size type = mimetypes.guess_type(full_path)[0] # If we don't have a type, text/plain it. if type is None: type = 'text/plain' # Generate a bunch of data for headers. modified = datetime.fromtimestamp(mtime) expires = datetime.utcnow() + timedelta(days=7) etag = '"%x-%x"' % (size, int(mtime)) headers = { 'Last-Modified' : date(modified), 'Expires' : date(expires), 'Cache-Control' : 'max-age=604800', 'Content-Type' : type, 'Date' : date(datetime.utcnow()), 'Server' : SERVER, 'Accept-Ranges' : 'bytes', 'ETag' : etag } do304 = False if 'If-Modified-Since' in request.headers: try: since = _parse_date(request.headers['If-Modified-Since']) except ValueError: since = None if since and since >= modified: do304 = True if 'If-None-Match' in request.headers: if etag == request.headers['If-None-Match']: do304 = True if do304: if f: f.close() request.auto_finish = False request.send_status(304) request.send_headers(headers) request.finish() return if 'If-Range' in request.headers: if etag != request.headers['If-Range'] and \ 'Range' in request.headers: del request.headers['Range'] last = size - 1 range = 0, last status = 200 if 'Range' in request.headers: if request.headers['Range'].startswith('bytes='): try: val = request.headers['Range'][6:].split(',')[0] start, end = val.split('-') except ValueError: if f: f.close() abort(416) try: if end and not start: end = last start = last - int(end) else: start = int(start or 0) end = int(end or last) if start < 0 or start > end or end > last: if f: f.close() abort(416) range = start, end except ValueError: pass if range[0] != 0 or range[1] != last: status = 206 headers['Content-Range'] = 'bytes %d-%d/%d' % ( range[0], range[1], size) # Set the content length header. if range[0] == range[1]: headers['Content-Length'] = 0 else: headers['Content-Length'] = 1 + (range[1] - range[0]) # Send the headers and status line. request.auto_finish = False request.send_status(status) request.send_headers(headers) # Don't send the body if this is head. if request.method == 'HEAD': if f: f.close() request.finish() return # Open the file and send it. if range[0] == range[1]: if f: f.close() request.finish() return if f is None: f = open(full_path, 'rb') if range[1] != last: length = 1 + (range[1] - range[0]) else: length = 0 request.connection.write_file(f, nbytes=length, offset=range[0]) request.connection._finished = True
def error(message=None, status=None, headers=None, request=None, debug=None): """ Return a very simple error page, defaulting to a ``404 Not Found`` error if no status code is supplied. Usually, you'll want to call :func:`abort` in your code, rather than error(). Usage:: return error(404) return error("Some message.", 404) return error("Blah blah blah.", 403, {'Some-Header': 'Fish'}) """ if request is None: request = Application.current_app.request if status is None: if isinstance(message, (int, long)): status, message = message, None else: status = 404 status_text = None if isinstance(status, basestring): status, _, status_text = status.partition(' ') status = int(status) if not status_text: status_text = HTTP.get(status, "Unknown Error") if not headers: headers = {} if message is None: message = HTTP_MESSAGES.get(status, u"An unknown error has occurred.") values = request.__dict__.copy() values['uri'] = decode(urllib.unquote(values['uri'])) message = message.format(**values) if status in HAIKUS: haiku = u'<div class="haiku">%s</div>' % HAIKUS[status] else: haiku = u"" if not message[0] == u"<": message = u"<p>%s</p>" % message if debug is None: debug = Application.current_app and Application.current_app.debug if debug: debug = u"%0.3f ms" % (1000 * request.time) else: debug = u"" result = ERROR_PAGE.safe_substitute( status=status, status_text=status_text, status_text_nbsp=status_text.replace(u" ", u" "), haiku=haiku, content=message, scheme=request.scheme, host=request.host, debug=debug ) return result, status, headers
def list_directory(self, request, path): """ Generate a directory listing and return it. """ # Normalize the path. full_path = os.path.normpath(os.path.join(self.path, path)) # Get the URL, which is just request.path decoded. url = decode(urllib.unquote(request.path)) if not url.startswith(u'/'): url = u'/%s' % url if not url.endswith(u'/'): return redirect(u'%s/' % url) go_up = u'' if url.strip(u'/'): go_up = u'<p><a href="..">Up to Higher Directory</a></p>' files = [] dirs = [] try: contents = os.listdir(full_path) except OSError: abort(403) for p in sorted(contents, key=unicode.lower): if _is_hidden(p, full_path): continue full = os.path.join(full_path, p) try: fp = full if os.path.isdir(full): fp += '/' self.check_blacklist(fp) except HTTPException: continue stat = os.stat(full) mtime = datetime.fromtimestamp( stat.st_mtime).strftime(u'%Y-%m-%d %I:%M:%S %p') if os.path.isdir(full): cls = u'folder' link = u'%s/' % p size = u'<span class="faint">Directory</span>' obj = dirs elif os.path.isfile(full): cls = 'document' ext = p[p.rfind('.') + 1:] if ext in ('jpg', 'jpeg', 'png', 'gif', 'bmp'): cls = 'image' elif ext in ('zip', 'gz', 'tar', '7z', 'tgz'): cls = 'zip' elif ext in ('mp3', 'mpa', 'wma', 'wav', 'flac', 'mid', 'midi', 'raw', 'mod', 'xm', 'aac', 'm4a', 'ogg', 'aiff', 'au', 'voc', 'm3u', 'pls', 'asx'): cls = 'audio' elif ext in ('mpg', 'mpeg', 'mkv', 'mp4', 'wmv', 'avi', 'mov'): cls = 'video' link = p size = _human_readable_size(stat.st_size) obj = files else: continue obj.append( DIRECTORY_ENTRY.safe_substitute(cls=cls, url=url + link, name=p, size=size, modified=mtime)) if files or dirs: files = u''.join(dirs) + u''.join(files) else: files = (u'<tr><td colspan="3" class="noborder">' u'<div class="footer center">' u'This directory is empty.</div></td></tr>') if Application.current_app and Application.current_app.debug: rtime = u'%0.3f ms' % (1000 * request.time) else: rtime = u'' output = DIRECTORY_PAGE.safe_substitute(path=url, go_up=go_up, host=request.host, scheme=request.scheme, content=''.join(files), debug=rtime) return output, 200, {'Content-Type': 'text/html; charset=UTF-8'}