diff --git a/CHANGES b/CHANGES index 3490f0e2..7336c377 100644 --- a/CHANGES +++ b/CHANGES @@ -11,6 +11,10 @@ Codename to be decided, release date to be announced. - fixed a bug with subdomains that was caused by the inability to specify the server name. The server name can now be set with the `SERVER_NAME` config key. +- autoescaping is no longer active for all templates. Instead it + is only active for ``.html``, ``.htm``, ``.xml`` and ``.xhtml``. + Inside templates this behaviour can be changed with the + ``autoescape`` tag. Version 0.4 ----------- diff --git a/docs/quickstart.rst b/docs/quickstart.rst index a4858f1c..e1fdce51 100644 --- a/docs/quickstart.rst +++ b/docs/quickstart.rst @@ -414,6 +414,13 @@ Markup(u'<blink>hacker</blink>') >>> Markup('Marked up » HTML').striptags() u'Marked up \xbb HTML' +.. versionchanged:: 0.5 + + Autoescaping is no longer enabled for all templates. The following + extensions for templates trigger autoescaping: ``.html``, ``.htm``, + ``.xml``, ``.xhtml``. Templates loaded from string will have + autoescaping disabled. + .. [#] Unsure what that :class:`~flask.g` object is? It's something you can store information on yourself, check the documentation of that object (:class:`~flask.g`) and the :ref:`sqlite3` for more diff --git a/flask.py b/flask.py index 9c720ef0..c55838dc 100644 --- a/flask.py +++ b/flask.py @@ -788,6 +788,15 @@ class Config(dict): return '<%s %s>' % (self.__class__.__name__, dict.__repr__(self)) +def _select_autoescape(filename): + """Returns `True` if autoescaping should be active for the given + template name. + """ + if filename is None: + return False + return filename.endswith(('.html', '.htm', '.xml', '.xhtml')) + + class Flask(_PackageBoundObject): """The flask object implements a WSGI application and acts as the central object. It is passed the name of the module or package of the @@ -920,7 +929,7 @@ class Flask(_PackageBoundObject): #: Options that are passed directly to the Jinja2 environment. jinja_options = ImmutableDict( - autoescape=True, + autoescape=_select_autoescape, extensions=['jinja2.ext.autoescape', 'jinja2.ext.with_'] ) @@ -1018,13 +1027,8 @@ class Flask(_PackageBoundObject): #: The Jinja2 environment. It is created from the #: :attr:`jinja_options` and the loader that is returned #: by the :meth:`create_jinja_loader` function. - self.jinja_env = Environment(loader=self.create_jinja_loader(), - **self.jinja_options) - self.jinja_env.globals.update( - url_for=url_for, - get_flashed_messages=get_flashed_messages - ) - self.jinja_env.filters['tojson'] = _tojson_filter + self.jinja_env = self.create_jinja_environment() + self.init_jinja_globals() @property def logger(self): @@ -1061,6 +1065,15 @@ class Flask(_PackageBoundObject): self._logger = logger return logger + def create_jinja_environment(self): + """Creates the Jinja2 environment based on :attr:`jinja_options` + and :meth:`create_jinja_loader`. + + .. versionadded:: 0.5 + """ + return Environment(loader=self.create_jinja_loader(), + **self.jinja_options) + def create_jinja_loader(self): """Creates the Jinja loader. By default just a package loader for the configured package is returned that looks up templates in the @@ -1071,6 +1084,19 @@ class Flask(_PackageBoundObject): return FileSystemLoader(os.path.join(self.root_path, 'templates')) return PackageLoader(self.import_name) + def init_jinja_globals(self): + """Callde directly after the environment was created to inject + some defaults (like `url_for`, `get_flashed_messages` and the + `tojson` filter. + + .. versionadded:: 0.5 + """ + self.jinja_env.globals.update( + url_for=url_for, + get_flashed_messages=get_flashed_messages + ) + self.jinja_env.filters['tojson'] = _tojson_filter + def update_template_context(self, context): """Update the template context with some commonly used variables. This injects request, session and g into the template context. diff --git a/tests/flask_tests.py b/tests/flask_tests.py index 1c5dc729..4309f214 100644 --- a/tests/flask_tests.py +++ b/tests/flask_tests.py @@ -461,6 +461,14 @@ class TemplatingTestCase(unittest.TestCase): '

Hello World!' ] + def test_no_escaping(self): + app = flask.Flask(__name__) + with app.test_request_context(): + assert flask.render_template_string('{{ foo }}', + foo='') == '' + assert flask.render_template('mail.txt', foo='') \ + == ' Mail' + def test_macros(self): app = flask.Flask(__name__) with app.test_request_context(): diff --git a/tests/templates/mail.txt b/tests/templates/mail.txt new file mode 100644 index 00000000..d6cb92ea --- /dev/null +++ b/tests/templates/mail.txt @@ -0,0 +1 @@ +{{ foo}} Mail