Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with
or
.
Download ZIP
Browse files

Imply the |safe on tojson in templates and change escaping logic

  • Loading branch information...
commit ef72b78042d7feffc864e7f2da3f62835fc63ee8 1 parent 56d3b74
@mitsuhiko authored
View
2  CHANGES
@@ -17,6 +17,8 @@ Release date to be decided.
``template_filter`` method family.
- Set the content-length header for x-sendfile.
- ``tojson`` filter now does not escape script blocks in HTML5 parsers.
+- ``tojson`` used in templates is now safe by default due. This was
+ allowed due to the different escaping behavior.
- Flask will now raise an error if you attempt to register a new function
on an already used endpoint.
- Added wrapper module around simplejson and added default serialization
View
5 docs/api.rst
@@ -364,7 +364,8 @@ JSON module:
The :func:`~htmlsafe_dumps` function of this json module is also available
as filter called ``|tojson`` in Jinja2. Note that inside `script`
tags no escaping must take place, so make sure to disable escaping
-with ``|safe`` if you intend to use it inside `script` tags:
+with ``|safe`` if you intend to use it inside `script` tags unless
+you are using Flask 0.10 which implies that:
.. sourcecode:: html+jinja
@@ -372,8 +373,6 @@ with ``|safe`` if you intend to use it inside `script` tags:
doSomethingWith({{ user.username|tojson|safe }});
</script>
-Note that the ``|tojson`` filter escapes forward slashes properly.
-
.. autofunction:: jsonify
.. autofunction:: dumps
View
11 docs/patterns/jquery.rst
@@ -63,9 +63,10 @@ like this:
$SCRIPT_ROOT = {{ request.script_root|tojson|safe }};
</script>
-The ``|safe`` is necessary so that Jinja does not escape the JSON encoded
-string with HTML rules. Usually this would be necessary, but we are
-inside a `script` block here where different rules apply.
+The ``|safe`` is necessary in Flask before 0.10 so that Jinja does not
+escape the JSON encoded string with HTML rules. Usually this would be
+necessary, but we are inside a `script` block here where different rules
+apply.
.. admonition:: Information for Pros
@@ -76,6 +77,10 @@ inside a `script` block here where different rules apply.
escape slashes for you (``{{ "</script>"|tojson|safe }}`` is rendered as
``"<\/script>"``).
+ In Flask 0.10 it goes a step further and escapes all HTML tags with
+ unicode escapes. This makes it possible for Flask to automatically
+ mark the result as HTML safe.
+
JSON View Functions
-------------------
View
6 docs/templating.rst
@@ -106,8 +106,8 @@ by Jinja2 itself:
fly.
Note that inside `script` tags no escaping must take place, so make
- sure to disable escaping with ``|safe`` if you intend to use it inside
- `script` tags:
+ sure to disable escaping with ``|safe`` before Flask 0.10 if you intend
+ to use it inside `script` tags:
.. sourcecode:: html+jinja
@@ -115,8 +115,6 @@ by Jinja2 itself:
doSomethingWith({{ user.username|tojson|safe }});
</script>
- That the ``|tojson`` filter escapes forward slashes properly for you.
-
Controlling Autoescaping
------------------------
View
9 flask/app.py
@@ -659,7 +659,7 @@ def create_jinja_environment(self):
session=session,
g=g
)
- rv.filters['tojson'] = json.htmlsafe_dumps
+ rv.filters['tojson'] = json.tojson_filter
return rv
def create_global_jinja_loader(self):
@@ -1707,13 +1707,6 @@ def do_teardown_request(self, exc=None):
rv = func(exc)
request_tearing_down.send(self, exc=exc)
- # If this interpreter supports clearing the exception information
- # we do that now. This will only go into effect on Python 2.x,
- # on 3.x it disappears automatically at the end of the exception
- # stack.
- if hasattr(sys, 'exc_clear'):
- sys.exc_clear()
-
def do_teardown_appcontext(self, exc=None):
"""Called when an application context is popped. This works pretty
much the same as :meth:`do_teardown_request` but for the application
View
27 flask/json.py
@@ -15,6 +15,7 @@
from ._compat import text_type, PY2
from werkzeug.http import http_date
+from jinja2 import Markup
# Use the same json implementation as itsdangerous on which we
# depend anyways.
@@ -160,18 +161,26 @@ def load(fp, **kwargs):
def htmlsafe_dumps(obj, **kwargs):
"""Works exactly like :func:`dumps` but is safe for use in ``<script>``
tags. It accepts the same arguments and returns a JSON string. Note that
- this is available in templates through the ``|tojson`` filter but it will
- have to be wrapped in ``|safe`` unless **true** XHTML is being used.
+ this is available in templates through the ``|tojson`` filter which will
+ also mark the result as safe. Due to how this function escapes certain
+ characters this is safe even if used outside of ``<script>`` tags.
+
+ .. versionchanged:: 0.10
+ This function's return value is now always safe for HTML usage, even
+ if outside of script tags or if used in XHTML.
"""
- rv = dumps(obj, **kwargs)
- if _slash_escape:
- rv = rv.replace('/', '\\/')
- return rv.replace('<!', '<\\u0021')
+ rv = dumps(obj, **kwargs) \
+ .replace(u'<', u'\\u003c') \
+ .replace(u'>', u'\\u003e') \
+ .replace(u'&', u'\\u0026')
+ if not _slash_escape:
+ rv = rv.replace('\\/', '/')
+ return rv
def htmlsafe_dump(obj, fp, **kwargs):
"""Like :func:`htmlsafe_dumps` but writes into a file object."""
- fp.write(htmlsafe_dumps(obj, **kwargs))
+ fp.write(unicode(htmlsafe_dumps(obj, **kwargs)))
def jsonify(*args, **kwargs):
@@ -213,3 +222,7 @@ def get_current_user():
return current_app.response_class(dumps(dict(*args, **kwargs),
indent=indent),
mimetype='application/json')
+
+
+def tojson_filter(obj, **kwargs):
+ return Markup(htmlsafe_dumps(obj, **kwargs))
View
17 flask/testsuite/helpers.py
@@ -92,12 +92,17 @@ def test_template_escaping(self):
app = flask.Flask(__name__)
render = flask.render_template_string
with app.test_request_context():
- rv = render('{{ "</script>"|tojson|safe }}')
- self.assert_equal(rv, '"<\\/script>"')
- rv = render('{{ "<\0/script>"|tojson|safe }}')
- self.assert_equal(rv, '"<\\u0000\\/script>"')
- rv = render('{{ "<!--<script>"|tojson|safe }}')
- self.assert_equal(rv, '"<\\u0021--<script>"')
+ rv = flask.json.htmlsafe_dumps('</script>')
+ self.assert_equal(rv, u'"\\u003c/script\\u003e"')
+ self.assert_equal(type(rv), text_type)
+ rv = render('{{ "</script>"|tojson }}')
+ self.assert_equal(rv, '"\\u003c/script\\u003e"')
+ rv = render('{{ "<\0/script>"|tojson }}')
+ self.assert_equal(rv, '"\\u003c\\u0000/script\\u003e"')
+ rv = render('{{ "<!--<script>"|tojson }}')
+ self.assert_equal(rv, '"\\u003c!--\\u003cscript\\u003e"')
+ rv = render('{{ "&"|tojson }}')
+ self.assert_equal(rv, '"\\u0026"')
def test_json_customization(self):
class X(object):
Please sign in to comment.
Something went wrong with that request. Please try again.