forked from orbit-oss/flask
use Jinja's tojson filter
This commit is contained in:
parent
fdf5d11b51
commit
b473e7c97c
7 changed files with 28 additions and 88 deletions
|
|
@ -63,6 +63,7 @@ Unreleased
|
|||
- The request context does route matching before opening the session.
|
||||
This could allow a session interface to change behavior based on
|
||||
``request.endpoint``. :issue:`3776`
|
||||
- Use Jinja's implementation of the ``|tojson`` filter. :issue:`3881`
|
||||
|
||||
|
||||
Version 1.1.2
|
||||
|
|
|
|||
|
|
@ -250,14 +250,15 @@ for easier customization. By default it handles some extra data types:
|
|||
- :class:`~markupsafe.Markup` (or any object with a ``__html__``
|
||||
method) will call the ``__html__`` method to get a string.
|
||||
|
||||
:func:`~htmlsafe_dumps` is also available as the ``|tojson`` template
|
||||
filter. The filter marks the output with ``|safe`` so it can be used
|
||||
inside ``script`` tags.
|
||||
Jinja's ``|tojson`` filter is configured to use Flask's :func:`dumps`
|
||||
function. The filter marks the output with ``|safe`` automatically. Use
|
||||
the filter to render data inside ``<script>`` tags.
|
||||
|
||||
.. sourcecode:: html+jinja
|
||||
|
||||
<script type=text/javascript>
|
||||
renderChart({{ axis_data|tojson }});
|
||||
const names = {{ names|tosjon }};
|
||||
renderChart(names, {{ axis_data|tojson }});
|
||||
</script>
|
||||
|
||||
.. autofunction:: jsonify
|
||||
|
|
|
|||
|
|
@ -60,27 +60,9 @@ like this:
|
|||
.. sourcecode:: html+jinja
|
||||
|
||||
<script type=text/javascript>
|
||||
$SCRIPT_ROOT = {{ request.script_root|tojson|safe }};
|
||||
$SCRIPT_ROOT = {{ request.script_root|tojson }};
|
||||
</script>
|
||||
|
||||
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
|
||||
|
||||
In HTML the ``script`` tag is declared ``CDATA`` which means that entities
|
||||
will not be parsed. Everything until ``</script>`` is handled as script.
|
||||
This also means that there must never be any ``</`` between the script
|
||||
tags. ``|tojson`` is kind enough to do the right thing here and
|
||||
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
|
||||
-------------------
|
||||
|
|
|
|||
|
|
@ -95,37 +95,6 @@ by default:
|
|||
|
||||
{% from '_helpers.html' import my_macro with context %}
|
||||
|
||||
Standard Filters
|
||||
----------------
|
||||
|
||||
Flask provides the following Jinja2 filters in addition to the filters provided
|
||||
by Jinja2 itself:
|
||||
|
||||
.. function:: tojson
|
||||
:noindex:
|
||||
|
||||
This function converts the given object into JSON representation. This
|
||||
is for example very helpful if you try to generate JavaScript on the
|
||||
fly.
|
||||
|
||||
.. sourcecode:: html+jinja
|
||||
|
||||
<script type=text/javascript>
|
||||
doSomethingWith({{ user.username|tojson }});
|
||||
</script>
|
||||
|
||||
It is also safe to use the output of `|tojson` in a *single-quoted* HTML
|
||||
attribute:
|
||||
|
||||
.. sourcecode:: html+jinja
|
||||
|
||||
<button onclick='doSomethingWith({{ user.username|tojson }})'>
|
||||
Click me
|
||||
</button>
|
||||
|
||||
Note that in versions of Flask prior to 0.10, if using the output of
|
||||
``|tojson`` inside ``script``, make sure to disable escaping with ``|safe``.
|
||||
In Flask 0.10 and above, this happens automatically.
|
||||
|
||||
Controlling Autoescaping
|
||||
------------------------
|
||||
|
|
|
|||
|
|
@ -681,7 +681,7 @@ class Flask(Scaffold):
|
|||
session=session,
|
||||
g=g,
|
||||
)
|
||||
rv.filters["tojson"] = json.tojson_filter
|
||||
rv.policies["json.dumps_function"] = json.dumps
|
||||
return rv
|
||||
|
||||
def create_global_jinja_loader(self):
|
||||
|
|
|
|||
|
|
@ -5,7 +5,7 @@ import warnings
|
|||
from datetime import date
|
||||
from datetime import datetime
|
||||
|
||||
from markupsafe import Markup
|
||||
from jinja2.utils import htmlsafe_json_dumps as _jinja_htmlsafe_dumps
|
||||
from werkzeug.http import http_date
|
||||
|
||||
from ..globals import current_app
|
||||
|
|
@ -234,30 +234,28 @@ def load(fp, app=None, **kwargs):
|
|||
return _json.load(fp, **kwargs)
|
||||
|
||||
|
||||
_htmlsafe_map = str.maketrans(
|
||||
{"<": "\\u003c", ">": "\\u003e", "&": "\\u0026", "'": "\\u0027"}
|
||||
)
|
||||
|
||||
|
||||
def htmlsafe_dumps(obj, **kwargs):
|
||||
"""Serialize an object to a string of JSON, replacing HTML-unsafe
|
||||
characters with Unicode escapes. Otherwise behaves the same as
|
||||
:func:`dumps`.
|
||||
"""Serialize an object to a string of JSON with :func:`dumps`, then
|
||||
replace HTML-unsafe characters with Unicode escapes and mark the
|
||||
result safe with :class:`~markupsafe.Markup`.
|
||||
|
||||
This is available in templates as the ``|tojson`` filter, which will
|
||||
also mark the result with ``|safe``.
|
||||
This is available in templates as the ``|tojson`` filter.
|
||||
|
||||
The returned string is safe to render in HTML documents and
|
||||
``<script>`` tags. The exception is in HTML attributes that are
|
||||
double quoted; either use single quotes or the ``|forceescape``
|
||||
filter.
|
||||
|
||||
.. versionchanged:: 2.0
|
||||
Uses :func:`jinja2.utils.htmlsafe_json_dumps`. The returned
|
||||
value is marked safe by wrapping in :class:`~markupsafe.Markup`.
|
||||
|
||||
.. versionchanged:: 0.10
|
||||
Single quotes are escaped, making this safe to use in HTML,
|
||||
``<script>`` tags, and single-quoted attributes without further
|
||||
escaping.
|
||||
"""
|
||||
return dumps(obj, **kwargs).translate(_htmlsafe_map)
|
||||
return _jinja_htmlsafe_dumps(obj, dumps=dumps, **kwargs)
|
||||
|
||||
|
||||
def htmlsafe_dump(obj, fp, **kwargs):
|
||||
|
|
@ -335,7 +333,3 @@ def jsonify(*args, **kwargs):
|
|||
f"{dumps(data, indent=indent, separators=separators)}\n",
|
||||
mimetype=current_app.config["JSONIFY_MIMETYPE"],
|
||||
)
|
||||
|
||||
|
||||
def tojson_filter(obj, **kwargs):
|
||||
return Markup(htmlsafe_dumps(obj, **kwargs))
|
||||
|
|
|
|||
|
|
@ -204,24 +204,17 @@ def test_json_attr(app, client):
|
|||
assert rv.data == b"3"
|
||||
|
||||
|
||||
def test_template_escaping(app, req_ctx):
|
||||
render = flask.render_template_string
|
||||
rv = flask.json.htmlsafe_dumps("</script>")
|
||||
assert rv == '"\\u003c/script\\u003e"'
|
||||
rv = render('{{ "</script>"|tojson }}')
|
||||
assert rv == '"\\u003c/script\\u003e"'
|
||||
rv = render('{{ "<\0/script>"|tojson }}')
|
||||
assert rv == '"\\u003c\\u0000/script\\u003e"'
|
||||
rv = render('{{ "<!--<script>"|tojson }}')
|
||||
assert rv == '"\\u003c!--\\u003cscript\\u003e"'
|
||||
rv = render('{{ "&"|tojson }}')
|
||||
assert rv == '"\\u0026"'
|
||||
rv = render('{{ "\'"|tojson }}')
|
||||
assert rv == '"\\u0027"'
|
||||
rv = render(
|
||||
"<a ng-data='{{ data|tojson }}'></a>", data={"x": ["foo", "bar", "baz'"]}
|
||||
def test_tojson_filter(app, req_ctx):
|
||||
# The tojson filter is tested in Jinja, this confirms that it's
|
||||
# using Flask's dumps.
|
||||
rv = flask.render_template_string(
|
||||
"const data = {{ data|tojson }};",
|
||||
data={"name": "</script>", "time": datetime.datetime(2021, 2, 1, 7, 15)},
|
||||
)
|
||||
assert rv == (
|
||||
'const data = {"name": "\\u003c/script\\u003e",'
|
||||
' "time": "Mon, 01 Feb 2021 07:15:00 GMT"};'
|
||||
)
|
||||
assert rv == '<a ng-data=\'{"x": ["foo", "bar", "baz\\u0027"]}\'></a>'
|
||||
|
||||
|
||||
def test_json_customization(app, client):
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue