diff --git a/CHANGES b/CHANGES index a8543e6c3b..53208f779b 100644 --- a/CHANGES +++ b/CHANGES @@ -67,6 +67,8 @@ Version 1.0 - Don't leak exception info of already catched exceptions to context teardown handlers (pull request ``#1393``). - Allow custom Jinja environment subclasses (pull request ``#1422``). +- Turn on autoescape for ``flask.templating.render_template_string`` by default + (pull request ``#1515``). Version 0.10.2 -------------- diff --git a/docs/templating.rst b/docs/templating.rst index a8c8d0a9d8..11d5d48d3c 100644 --- a/docs/templating.rst +++ b/docs/templating.rst @@ -18,7 +18,10 @@ Jinja Setup Unless customized, Jinja2 is configured by Flask as follows: - autoescaping is enabled for all templates ending in ``.html``, - ``.htm``, ``.xml`` as well as ``.xhtml`` + ``.htm``, ``.xml`` as well as ``.xhtml`` when using + :func:`~flask.templating.render_template`. +- autoescaping is enabled for all strings when using + :func:`~flask.templating.render_template_string`. - a template has the ability to opt in/out autoescaping with the ``{% autoescape %}`` tag. - Flask inserts a couple of global functions and helpers into the diff --git a/docs/upgrading.rst b/docs/upgrading.rst index b0460b3879..fca4d75b82 100644 --- a/docs/upgrading.rst +++ b/docs/upgrading.rst @@ -37,6 +37,10 @@ Now the inheritance hierarchy takes precedence and handlers for more specific exception classes are executed instead of more general ones. See :ref:`error-handlers` for specifics. +The :func:`~flask.templating.render_template_string` function has changed to +autoescape template variables by default. This better matches the behavior +of :func:`~flask.templating.render_template`. + .. note:: There used to be a logic error allowing you to register handlers diff --git a/flask/app.py b/flask/app.py index 668f36ce03..f0a8b69b12 100644 --- a/flask/app.py +++ b/flask/app.py @@ -724,12 +724,12 @@ def init_jinja_globals(self): def select_jinja_autoescape(self, filename): """Returns ``True`` if autoescaping should be active for the given - template name. + template name. If no template name is given, returns `True`. .. versionadded:: 0.5 """ if filename is None: - return False + return True return filename.endswith(('.html', '.htm', '.xml', '.xhtml')) def update_template_context(self, context): @@ -1090,14 +1090,14 @@ def _get_exc_class_and_code(exc_class_or_code): exc_class = default_exceptions[exc_class_or_code] else: exc_class = exc_class_or_code - + assert issubclass(exc_class, Exception) - + if issubclass(exc_class, HTTPException): return exc_class, exc_class.code else: return exc_class, None - + @setupmethod def errorhandler(self, code_or_exception): """A decorator that is used to register a function give a given @@ -1166,9 +1166,9 @@ def _register_error_handler(self, key, code_or_exception, f): 'Tried to register a handler for an exception instance {0!r}. ' 'Handlers can only be registered for exception classes or HTTP error codes.' .format(code_or_exception)) - + exc_class, code = self._get_exc_class_and_code(code_or_exception) - + handlers = self.error_handler_spec.setdefault(key, {}).setdefault(code, {}) handlers[exc_class] = f @@ -1460,7 +1460,7 @@ def handle_http_exception(self, e): # those unchanged as errors if e.code is None: return e - + handler = self._find_error_handler(e) if handler is None: return e @@ -1503,12 +1503,12 @@ def handle_user_exception(self, e): # wants the traceback preserved in handle_http_exception. Of course # we cannot prevent users from trashing it themselves in a custom # trap_http_exception method so that's their fault then. - + if isinstance(e, HTTPException) and not self.trap_http_exception(e): return self.handle_http_exception(e) handler = self._find_error_handler(e) - + if handler is None: reraise(exc_type, exc_value, tb) return handler(e) diff --git a/flask/templating.py b/flask/templating.py index 59fd988e76..8c95a6a706 100644 --- a/flask/templating.py +++ b/flask/templating.py @@ -127,7 +127,7 @@ def render_template(template_name_or_list, **context): def render_template_string(source, **context): """Renders a template from the given template source string - with the given context. + with the given context. Template variables will be autoescaped. :param source: the source code of the template to be rendered diff --git a/tests/templates/non_escaping_template.txt b/tests/templates/non_escaping_template.txt new file mode 100644 index 0000000000..542864e8bb --- /dev/null +++ b/tests/templates/non_escaping_template.txt @@ -0,0 +1,8 @@ +{{ text }} +{{ html }} +{% autoescape false %}{{ text }} +{{ html }}{% endautoescape %} +{% autoescape true %}{{ text }} +{{ html }}{% endautoescape %} +{{ text }} +{{ html }} diff --git a/tests/test_templating.py b/tests/test_templating.py index 293ca06f26..b60a592a79 100644 --- a/tests/test_templating.py +++ b/tests/test_templating.py @@ -81,10 +81,29 @@ def index(): ] def test_no_escaping(): + text = '

Hello World!' + app = flask.Flask(__name__) + @app.route('/') + def index(): + return flask.render_template('non_escaping_template.txt', text=text, + html=flask.Markup(text)) + lines = app.test_client().get('/').data.splitlines() + assert lines == [ + b'

Hello World!', + b'

Hello World!', + b'

Hello World!', + b'

Hello World!', + b'<p>Hello World!', + b'

Hello World!', + b'

Hello World!', + b'

Hello World!' + ] + +def test_escaping_without_template_filename(): app = flask.Flask(__name__) with app.test_request_context(): assert flask.render_template_string( - '{{ foo }}', foo='') == '' + '{{ foo }}', foo='') == '<test>' assert flask.render_template('mail.txt', foo='') == \ ' Mail'