From ac13deff401069c3854acca10c926119c6e1cbe0 Mon Sep 17 00:00:00 2001 From: Armin Ronacher Date: Mon, 5 Jul 2010 10:23:35 +0200 Subject: [PATCH] Re-added support for folder with static files, refactored static file sending --- flask/__init__.py | 3 +- flask/app.py | 2 +- flask/helpers.py | 36 +++++++++++++++---- flask/module.py | 2 +- tests/flask_tests.py | 2 ++ .../moduleapp/apps/admin/static/css/test.css | 1 + 6 files changed, 36 insertions(+), 10 deletions(-) create mode 100644 tests/moduleapp/apps/admin/static/css/test.css diff --git a/flask/__init__.py b/flask/__init__.py index 76eed660..f4617271 100644 --- a/flask/__init__.py +++ b/flask/__init__.py @@ -18,7 +18,8 @@ from jinja2 import Markup, escape from .app import Flask, Request, Response from .config import Config from .helpers import url_for, jsonify, json_available, flash, \ - send_file, get_flashed_messages, get_template_attribute + send_file, send_from_directory, get_flashed_messages, \ + get_template_attribute from .globals import current_app, g, request, session, _request_ctx_stack from .module import Module from .templating import render_template, render_template_string diff --git a/flask/app.py b/flask/app.py index 9cdf9274..8e559d4e 100644 --- a/flask/app.py +++ b/flask/app.py @@ -273,7 +273,7 @@ class Flask(_PackageBoundObject): # if there is a static folder, register it for the application. if self.has_static_folder: - self.add_url_rule(self.static_path + '/', + self.add_url_rule(self.static_path + '/', endpoint='static', view_func=self.send_static_file) diff --git a/flask/helpers.py b/flask/helpers.py index 8f2a2083..65506698 100644 --- a/flask/helpers.py +++ b/flask/helpers.py @@ -291,6 +291,33 @@ def send_file(filename_or_fp, mimetype=None, as_attachment=False, return rv +def send_from_directory(directory, filename, **options): + """Send a file from a given directory with :func:`send_file`. This + is a secure way to quickly expose static files from an upload folder + or something similar. + + Example usage:: + + @app.route('/uploads/') + def download_file(filename): + return send_from_directory(app.config['UPLOAD_FOLDER'], + filename, as_attachment=True) + + :param directory: the directory where all the files are stored. + :param filename: the filename relative to that directory to + download. + :param options: optional keyword arguments that are directly + forwarded to :func:`send_file`. + """ + filename = posixpath.normpath(filename) + if filename.startswith(('/', '../')): + raise NotFound() + filename = os.path.join(directory, filename) + if not os.path.isfile(filename): + raise NotFound() + return send_file(filename, conditional=True, **options) + + def _get_package_path(name): """Returns the path to a package or cwd if that cannot be found.""" try: @@ -334,13 +361,8 @@ class _PackageBoundObject(object): .. versionadded:: 0.5 """ - filename = posixpath.normpath(filename) - if filename.startswith(('/', '../')): - raise NotFound() - filename = os.path.join(self.root_path, 'static', filename) - if not os.path.isfile(filename): - raise NotFound() - return send_file(filename, conditional=True) + return send_from_directory(os.path.join(self.root_path, 'static'), + filename) def open_resource(self, resource): """Opens a resource from the application's resource folder. To see diff --git a/flask/module.py b/flask/module.py index 6a4f0fb3..7bebac4b 100644 --- a/flask/module.py +++ b/flask/module.py @@ -29,7 +29,7 @@ def _register_module(module, static_path): path = state.app.static_path if state.url_prefix: path = state.url_prefix + path - state.app.add_url_rule(path + '/', + state.app.add_url_rule(path + '/', '%s.static' % module.name, view_func=module.send_static_file) return _register diff --git a/tests/flask_tests.py b/tests/flask_tests.py index b3835302..129ec3b2 100644 --- a/tests/flask_tests.py +++ b/tests/flask_tests.py @@ -641,6 +641,8 @@ class ModuleTestCase(unittest.TestCase): assert rv.data == 'Hello from the Admin' rv = c.get('/admin/static/test.txt') assert rv.data.strip() == 'Admin File' + rv = c.get('/admin/static/css/test.css') + assert rv.data.strip() == '/* nested file */' with app.test_request_context(): assert flask.url_for('admin.static', filename='test.txt') \ diff --git a/tests/moduleapp/apps/admin/static/css/test.css b/tests/moduleapp/apps/admin/static/css/test.css new file mode 100644 index 00000000..b9f564de --- /dev/null +++ b/tests/moduleapp/apps/admin/static/css/test.css @@ -0,0 +1 @@ +/* nested file */