Browse Source

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

pull/761/head
Armin Ronacher 12 years ago
parent
commit
ef72b78042
  1. 2
      CHANGES
  2. 5
      docs/api.rst
  3. 11
      docs/patterns/jquery.rst
  4. 6
      docs/templating.rst
  5. 9
      flask/app.py
  6. 27
      flask/json.py
  7. 17
      flask/testsuite/helpers.py

2
CHANGES

@ -17,6 +17,8 @@ Release date to be decided.
``template_filter`` method family. ``template_filter`` method family.
- Set the content-length header for x-sendfile. - Set the content-length header for x-sendfile.
- ``tojson`` filter now does not escape script blocks in HTML5 parsers. - ``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 - Flask will now raise an error if you attempt to register a new function
on an already used endpoint. on an already used endpoint.
- Added wrapper module around simplejson and added default serialization - Added wrapper module around simplejson and added default serialization

5
docs/api.rst

@ -364,7 +364,8 @@ JSON module:
The :func:`~htmlsafe_dumps` function of this json module is also available The :func:`~htmlsafe_dumps` function of this json module is also available
as filter called ``|tojson`` in Jinja2. Note that inside `script` as filter called ``|tojson`` in Jinja2. Note that inside `script`
tags no escaping must take place, so make sure to disable escaping 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 .. sourcecode:: html+jinja
@ -372,8 +373,6 @@ with ``|safe`` if you intend to use it inside `script` tags:
doSomethingWith({{ user.username|tojson|safe }}); doSomethingWith({{ user.username|tojson|safe }});
</script> </script>
Note that the ``|tojson`` filter escapes forward slashes properly.
.. autofunction:: jsonify .. autofunction:: jsonify
.. autofunction:: dumps .. autofunction:: dumps

11
docs/patterns/jquery.rst

@ -63,9 +63,10 @@ like this:
$SCRIPT_ROOT = {{ request.script_root|tojson|safe }}; $SCRIPT_ROOT = {{ request.script_root|tojson|safe }};
</script> </script>
The ``|safe`` is necessary so that Jinja does not escape the JSON encoded The ``|safe`` is necessary in Flask before 0.10 so that Jinja does not
string with HTML rules. Usually this would be necessary, but we are escape the JSON encoded string with HTML rules. Usually this would be
inside a `script` block here where different rules apply. necessary, but we are inside a `script` block here where different rules
apply.
.. admonition:: Information for Pros .. 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 escape slashes for you (``{{ "</script>"|tojson|safe }}`` is rendered as
``"<\/script>"``). ``"<\/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 JSON View Functions
------------------- -------------------

6
docs/templating.rst

@ -106,8 +106,8 @@ by Jinja2 itself:
fly. fly.
Note that inside `script` tags no escaping must take place, so make 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 sure to disable escaping with ``|safe`` before Flask 0.10 if you intend
`script` tags: to use it inside `script` tags:
.. sourcecode:: html+jinja .. sourcecode:: html+jinja
@ -115,8 +115,6 @@ by Jinja2 itself:
doSomethingWith({{ user.username|tojson|safe }}); doSomethingWith({{ user.username|tojson|safe }});
</script> </script>
That the ``|tojson`` filter escapes forward slashes properly for you.
Controlling Autoescaping Controlling Autoescaping
------------------------ ------------------------

9
flask/app.py

@ -659,7 +659,7 @@ class Flask(_PackageBoundObject):
session=session, session=session,
g=g g=g
) )
rv.filters['tojson'] = json.htmlsafe_dumps rv.filters['tojson'] = json.tojson_filter
return rv return rv
def create_global_jinja_loader(self): def create_global_jinja_loader(self):
@ -1707,13 +1707,6 @@ class Flask(_PackageBoundObject):
rv = func(exc) rv = func(exc)
request_tearing_down.send(self, exc=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): def do_teardown_appcontext(self, exc=None):
"""Called when an application context is popped. This works pretty """Called when an application context is popped. This works pretty
much the same as :meth:`do_teardown_request` but for the application much the same as :meth:`do_teardown_request` but for the application

27
flask/json.py

@ -15,6 +15,7 @@ from .globals import current_app, request
from ._compat import text_type, PY2 from ._compat import text_type, PY2
from werkzeug.http import http_date from werkzeug.http import http_date
from jinja2 import Markup
# Use the same json implementation as itsdangerous on which we # Use the same json implementation as itsdangerous on which we
# depend anyways. # depend anyways.
@ -160,18 +161,26 @@ def load(fp, **kwargs):
def htmlsafe_dumps(obj, **kwargs): def htmlsafe_dumps(obj, **kwargs):
"""Works exactly like :func:`dumps` but is safe for use in ``<script>`` """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 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 this is available in templates through the ``|tojson`` filter which will
have to be wrapped in ``|safe`` unless **true** XHTML is being used. 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) rv = dumps(obj, **kwargs) \
if _slash_escape: .replace(u'<', u'\\u003c') \
rv = rv.replace('/', '\\/') .replace(u'>', u'\\u003e') \
return rv.replace('<!', '<\\u0021') .replace(u'&', u'\\u0026')
if not _slash_escape:
rv = rv.replace('\\/', '/')
return rv
def htmlsafe_dump(obj, fp, **kwargs): def htmlsafe_dump(obj, fp, **kwargs):
"""Like :func:`htmlsafe_dumps` but writes into a file object.""" """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): def jsonify(*args, **kwargs):
@ -213,3 +222,7 @@ def jsonify(*args, **kwargs):
return current_app.response_class(dumps(dict(*args, **kwargs), return current_app.response_class(dumps(dict(*args, **kwargs),
indent=indent), indent=indent),
mimetype='application/json') mimetype='application/json')
def tojson_filter(obj, **kwargs):
return Markup(htmlsafe_dumps(obj, **kwargs))

17
flask/testsuite/helpers.py

@ -92,12 +92,17 @@ class JSONTestCase(FlaskTestCase):
app = flask.Flask(__name__) app = flask.Flask(__name__)
render = flask.render_template_string render = flask.render_template_string
with app.test_request_context(): with app.test_request_context():
rv = render('{{ "</script>"|tojson|safe }}') rv = flask.json.htmlsafe_dumps('</script>')
self.assert_equal(rv, '"<\\/script>"') self.assert_equal(rv, u'"\\u003c/script\\u003e"')
rv = render('{{ "<\0/script>"|tojson|safe }}') self.assert_equal(type(rv), text_type)
self.assert_equal(rv, '"<\\u0000\\/script>"') rv = render('{{ "</script>"|tojson }}')
rv = render('{{ "<!--<script>"|tojson|safe }}') self.assert_equal(rv, '"\\u003c/script\\u003e"')
self.assert_equal(rv, '"<\\u0021--<script>"') 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): def test_json_customization(self):
class X(object): class X(object):

Loading…
Cancel
Save