Kaydet (Commit) 8d76443a authored tarafından Jon Dufresne's avatar Jon Dufresne Kaydeden (comit) Carlton Gibson

Fixed #30399 -- Changed django.utils.html.escape()/urlize() to use html.escape()/unescape().

üst 28d5262f
"""HTML utilities suitable for global use.""" """HTML utilities suitable for global use."""
import html
import json import json
import re import re
from html.parser import HTMLParser from html.parser import HTMLParser
...@@ -24,14 +25,6 @@ word_split_re = re.compile(r'''([\s<>"']+)''') ...@@ -24,14 +25,6 @@ word_split_re = re.compile(r'''([\s<>"']+)''')
simple_url_re = re.compile(r'^https?://\[?\w', re.IGNORECASE) simple_url_re = re.compile(r'^https?://\[?\w', re.IGNORECASE)
simple_url_2_re = re.compile(r'^www\.|^(?!http)\w[^@]+\.(com|edu|gov|int|mil|net|org)($|/.*)$', re.IGNORECASE) simple_url_2_re = re.compile(r'^www\.|^(?!http)\w[^@]+\.(com|edu|gov|int|mil|net|org)($|/.*)$', re.IGNORECASE)
_html_escapes = {
ord('&'): '&amp;',
ord('<'): '&lt;',
ord('>'): '&gt;',
ord('"'): '&quot;',
ord("'"): '&#39;',
}
@keep_lazy(str, SafeString) @keep_lazy(str, SafeString)
def escape(text): def escape(text):
...@@ -43,7 +36,7 @@ def escape(text): ...@@ -43,7 +36,7 @@ def escape(text):
This may result in double-escaping. If this is a concern, use This may result in double-escaping. If this is a concern, use
conditional_escape() instead. conditional_escape() instead.
""" """
return mark_safe(str(text).translate(_html_escapes)) return mark_safe(html.escape(str(text)))
_js_escapes = { _js_escapes = {
...@@ -259,15 +252,6 @@ def urlize(text, trim_url_limit=None, nofollow=False, autoescape=False): ...@@ -259,15 +252,6 @@ def urlize(text, trim_url_limit=None, nofollow=False, autoescape=False):
return x return x
return '%s…' % x[:max(0, limit - 1)] return '%s…' % x[:max(0, limit - 1)]
def unescape(text):
"""
If input URL is HTML-escaped, unescape it so that it can be safely fed
to smart_urlquote. For example:
http://example.com?x=1&amp;y=&lt;2&gt; => http://example.com?x=1&y=<2>
"""
return text.replace('&amp;', '&').replace('&lt;', '<').replace(
'&gt;', '>').replace('&quot;', '"').replace('&#39;', "'")
def trim_punctuation(lead, middle, trail): def trim_punctuation(lead, middle, trail):
""" """
Trim trailing and wrapping punctuation from `middle`. Return the items Trim trailing and wrapping punctuation from `middle`. Return the items
...@@ -292,7 +276,7 @@ def urlize(text, trim_url_limit=None, nofollow=False, autoescape=False): ...@@ -292,7 +276,7 @@ def urlize(text, trim_url_limit=None, nofollow=False, autoescape=False):
# Trim trailing punctuation (after trimming wrapping punctuation, # Trim trailing punctuation (after trimming wrapping punctuation,
# as encoded entities contain ';'). Unescape entites to avoid # as encoded entities contain ';'). Unescape entites to avoid
# breaking them by removing ';'. # breaking them by removing ';'.
middle_unescaped = unescape(middle) middle_unescaped = html.unescape(middle)
stripped = middle_unescaped.rstrip(TRAILING_PUNCTUATION_CHARS) stripped = middle_unescaped.rstrip(TRAILING_PUNCTUATION_CHARS)
if middle_unescaped != stripped: if middle_unescaped != stripped:
trail = middle[len(stripped):] + trail trail = middle[len(stripped):] + trail
...@@ -329,9 +313,9 @@ def urlize(text, trim_url_limit=None, nofollow=False, autoescape=False): ...@@ -329,9 +313,9 @@ def urlize(text, trim_url_limit=None, nofollow=False, autoescape=False):
url = None url = None
nofollow_attr = ' rel="nofollow"' if nofollow else '' nofollow_attr = ' rel="nofollow"' if nofollow else ''
if simple_url_re.match(middle): if simple_url_re.match(middle):
url = smart_urlquote(unescape(middle)) url = smart_urlquote(html.unescape(middle))
elif simple_url_2_re.match(middle): elif simple_url_2_re.match(middle):
url = smart_urlquote('http://%s' % unescape(middle)) url = smart_urlquote('http://%s' % html.unescape(middle))
elif ':' not in middle and is_email_simple(middle): elif ':' not in middle and is_email_simple(middle):
local, domain = middle.rsplit('@', 1) local, domain = middle.rsplit('@', 1)
try: try:
......
...@@ -387,7 +387,7 @@ With that ready, we can ask the client to do some work for us:: ...@@ -387,7 +387,7 @@ With that ready, we can ask the client to do some work for us::
>>> response.status_code >>> response.status_code
200 200
>>> response.content >>> response.content
b'\n <ul>\n \n <li><a href="/polls/1/">What&#39;s up?</a></li>\n \n </ul>\n\n' b'\n <ul>\n \n <li><a href="/polls/1/">What&#x27;s up?</a></li>\n \n </ul>\n\n'
>>> response.context['latest_question_list'] >>> response.context['latest_question_list']
<QuerySet [<Question: What's up?>]> <QuerySet [<Question: What's up?>]>
......
...@@ -1603,7 +1603,7 @@ Escapes a string's HTML. Specifically, it makes these replacements: ...@@ -1603,7 +1603,7 @@ Escapes a string's HTML. Specifically, it makes these replacements:
* ``<`` is converted to ``&lt;`` * ``<`` is converted to ``&lt;``
* ``>`` is converted to ``&gt;`` * ``>`` is converted to ``&gt;``
* ``'`` (single quote) is converted to ``&#39;`` * ``'`` (single quote) is converted to ``&#x27;``
* ``"`` (double quote) is converted to ``&quot;`` * ``"`` (double quote) is converted to ``&quot;``
* ``&`` is converted to ``&amp;`` * ``&`` is converted to ``&amp;``
......
...@@ -492,7 +492,7 @@ escaped: ...@@ -492,7 +492,7 @@ escaped:
* ``<`` is converted to ``&lt;`` * ``<`` is converted to ``&lt;``
* ``>`` is converted to ``&gt;`` * ``>`` is converted to ``&gt;``
* ``'`` (single quote) is converted to ``&#39;`` * ``'`` (single quote) is converted to ``&#x27;``
* ``"`` (double quote) is converted to ``&quot;`` * ``"`` (double quote) is converted to ``&quot;``
* ``&`` is converted to ``&amp;`` * ``&`` is converted to ``&amp;``
......
...@@ -584,6 +584,11 @@ escaping HTML. ...@@ -584,6 +584,11 @@ escaping HTML.
for use in HTML. The input is first coerced to a string and the output has for use in HTML. The input is first coerced to a string and the output has
:func:`~django.utils.safestring.mark_safe` applied. :func:`~django.utils.safestring.mark_safe` applied.
.. versionchanged:: 3.0
In older versions, ``'`` is converted to its decimal code ``&#39;``
instead of the equivalent hex code ``&#x27;``.
.. function:: conditional_escape(text) .. function:: conditional_escape(text)
Similar to ``escape()``, except that it doesn't operate on pre-escaped Similar to ``escape()``, except that it doesn't operate on pre-escaped
......
...@@ -348,6 +348,10 @@ Miscellaneous ...@@ -348,6 +348,10 @@ Miscellaneous
the session and :func:`django.contrib.auth.logout` no longer preserves the the session and :func:`django.contrib.auth.logout` no longer preserves the
session's language after logout. session's language after logout.
* :func:`django.utils.html.escape` now uses :func:`html.escape` to escape HTML.
This converts ``'`` to ``&#x27;`` instead of the previous equivalent decimal
code ``&#39;``.
.. _deprecated-features-3.0: .. _deprecated-features-3.0:
Features deprecated in 3.0 Features deprecated in 3.0
......
...@@ -199,7 +199,7 @@ class TestModelDetailView(TestDataMixin, AdminDocsTestCase): ...@@ -199,7 +199,7 @@ class TestModelDetailView(TestDataMixin, AdminDocsTestCase):
""" """
Methods with keyword arguments should have their arguments displayed. Methods with keyword arguments should have their arguments displayed.
""" """
self.assertContains(self.response, "<td>suffix=&#39;ltd&#39;</td>") self.assertContains(self.response, '<td>suffix=&#x27;ltd&#x27;</td>')
def test_methods_with_multiple_arguments_display_arguments(self): def test_methods_with_multiple_arguments_display_arguments(self):
""" """
......
...@@ -236,7 +236,7 @@ class UserCreationFormTest(TestDataMixin, TestCase): ...@@ -236,7 +236,7 @@ class UserCreationFormTest(TestDataMixin, TestCase):
form = UserCreationForm() form = UserCreationForm()
self.assertEqual( self.assertEqual(
form.fields['password1'].help_text, form.fields['password1'].help_text,
'<ul><li>Your password can&#39;t be too similar to your other personal information.</li></ul>' '<ul><li>Your password can&#x27;t be too similar to your other personal information.</li></ul>'
) )
@override_settings(AUTH_PASSWORD_VALIDATORS=[ @override_settings(AUTH_PASSWORD_VALIDATORS=[
......
...@@ -995,7 +995,7 @@ Java</label></li> ...@@ -995,7 +995,7 @@ Java</label></li>
self.assertHTMLEqual( self.assertHTMLEqual(
f.as_table(), f.as_table(),
"""<tr><th>&lt;em&gt;Special&lt;/em&gt; Field:</th><td> """<tr><th>&lt;em&gt;Special&lt;/em&gt; Field:</th><td>
<ul class="errorlist"><li>Something&#39;s wrong with &#39;Nothing to escape&#39;</li></ul> <ul class="errorlist"><li>Something&#x27;s wrong with &#x27;Nothing to escape&#x27;</li></ul>
<input type="text" name="special_name" value="Nothing to escape" required></td></tr> <input type="text" name="special_name" value="Nothing to escape" required></td></tr>
<tr><th><em>Special</em> Field:</th><td> <tr><th><em>Special</em> Field:</th><td>
<ul class="errorlist"><li>'<b>Nothing to escape</b>' is a safe string</li></ul> <ul class="errorlist"><li>'<b>Nothing to escape</b>' is a safe string</li></ul>
...@@ -1008,10 +1008,10 @@ Java</label></li> ...@@ -1008,10 +1008,10 @@ Java</label></li>
self.assertHTMLEqual( self.assertHTMLEqual(
f.as_table(), f.as_table(),
"""<tr><th>&lt;em&gt;Special&lt;/em&gt; Field:</th><td> """<tr><th>&lt;em&gt;Special&lt;/em&gt; Field:</th><td>
<ul class="errorlist"><li>Something&#39;s wrong with &#39;Should escape &lt; &amp; &gt; and <ul class="errorlist"><li>Something&#x27;s wrong with &#x27;Should escape &lt; &amp; &gt; and
&lt;script&gt;alert(&#39;xss&#39;)&lt;/script&gt;&#39;</li></ul> &lt;script&gt;alert(&#x27;xss&#x27;)&lt;/script&gt;&#x27;</li></ul>
<input type="text" name="special_name" <input type="text" name="special_name"
value="Should escape &lt; &amp; &gt; and &lt;script&gt;alert(&#39;xss&#39;)&lt;/script&gt;" required></td></tr> value="Should escape &lt; &amp; &gt; and &lt;script&gt;alert(&#x27;xss&#x27;)&lt;/script&gt;" required></td></tr>
<tr><th><em>Special</em> Field:</th><td> <tr><th><em>Special</em> Field:</th><td>
<ul class="errorlist"><li>'<b><i>Do not escape</i></b>' is a safe string</li></ul> <ul class="errorlist"><li>'<b><i>Do not escape</i></b>' is a safe string</li></ul>
<input type="text" name="special_safe_name" value="&lt;i&gt;Do not escape&lt;/i&gt;" required></td></tr>""" <input type="text" name="special_safe_name" value="&lt;i&gt;Do not escape&lt;/i&gt;" required></td></tr>"""
...@@ -2632,7 +2632,7 @@ Password: <input type="password" name="password" required> ...@@ -2632,7 +2632,7 @@ Password: <input type="password" name="password" required>
t.render(Context({'form': UserRegistration(auto_id=False)})), t.render(Context({'form': UserRegistration(auto_id=False)})),
"""<form> """<form>
<p>Username: <input type="text" name="username" maxlength="10" required><br> <p>Username: <input type="text" name="username" maxlength="10" required><br>
Good luck picking a username that doesn&#39;t already exist.</p> Good luck picking a username that doesn&#x27;t already exist.</p>
<p>Password1: <input type="password" name="password1" required></p> <p>Password1: <input type="password" name="password1" required></p>
<p>Password2: <input type="password" name="password2" required></p> <p>Password2: <input type="password" name="password2" required></p>
<input type="submit" required> <input type="submit" required>
......
...@@ -22,7 +22,10 @@ class WidgetTest(SimpleTestCase): ...@@ -22,7 +22,10 @@ class WidgetTest(SimpleTestCase):
if self.jinja2_renderer: if self.jinja2_renderer:
output = widget.render(name, value, attrs=attrs, renderer=self.jinja2_renderer, **kwargs) output = widget.render(name, value, attrs=attrs, renderer=self.jinja2_renderer, **kwargs)
# Django escapes quotes with '&quot;' while Jinja2 uses '&#34;'. # Django escapes quotes with '&quot;' while Jinja2 uses '&#34;'.
assertEqual(output.replace('&#34;', '&quot;'), html) output = output.replace('&#34;', '&quot;')
# Django escapes single quotes with '&#x27;' while Jinja2 uses '&#39;'.
output = output.replace('&#39;', '&#x27;')
assertEqual(output, html)
output = widget.render(name, value, attrs=attrs, renderer=self.django_renderer, **kwargs) output = widget.render(name, value, attrs=attrs, renderer=self.django_renderer, **kwargs)
assertEqual(output, html) assertEqual(output, html)
...@@ -46,7 +46,7 @@ class ClearableFileInputTest(WidgetTest): ...@@ -46,7 +46,7 @@ class ClearableFileInputTest(WidgetTest):
self.check_html(ClearableFileInput(), 'my<div>file', StrangeFieldFile(), html=( self.check_html(ClearableFileInput(), 'my<div>file', StrangeFieldFile(), html=(
""" """
Currently: <a href="something?chapter=1&amp;sect=2&amp;copy=3&amp;lang=en"> Currently: <a href="something?chapter=1&amp;sect=2&amp;copy=3&amp;lang=en">
something&lt;div onclick=&quot;alert(&#39;oops&#39;)&quot;&gt;.jpg</a> something&lt;div onclick=&quot;alert(&#x27;oops&#x27;)&quot;&gt;.jpg</a>
<input type="checkbox" name="my&lt;div&gt;file-clear" id="my&lt;div&gt;file-clear_id"> <input type="checkbox" name="my&lt;div&gt;file-clear" id="my&lt;div&gt;file-clear_id">
<label for="my&lt;div&gt;file-clear_id">Clear</label><br> <label for="my&lt;div&gt;file-clear_id">Clear</label><br>
Change: <input type="file" name="my&lt;div&gt;file"> Change: <input type="file" name="my&lt;div&gt;file">
......
...@@ -1197,7 +1197,7 @@ class ModelFormBasicTests(TestCase): ...@@ -1197,7 +1197,7 @@ class ModelFormBasicTests(TestCase):
<li>Article: <textarea rows="10" cols="40" name="article" required></textarea></li> <li>Article: <textarea rows="10" cols="40" name="article" required></textarea></li>
<li>Categories: <select multiple name="categories"> <li>Categories: <select multiple name="categories">
<option value="%s" selected>Entertainment</option> <option value="%s" selected>Entertainment</option>
<option value="%s" selected>It&#39;s a test</option> <option value="%s" selected>It&#x27;s a test</option>
<option value="%s">Third test</option> <option value="%s">Third test</option>
</select></li> </select></li>
<li>Status: <select name="status"> <li>Status: <select name="status">
...@@ -1239,7 +1239,7 @@ class ModelFormBasicTests(TestCase): ...@@ -1239,7 +1239,7 @@ class ModelFormBasicTests(TestCase):
<li>Article: <textarea rows="10" cols="40" name="article" required>Hello.</textarea></li> <li>Article: <textarea rows="10" cols="40" name="article" required>Hello.</textarea></li>
<li>Categories: <select multiple name="categories"> <li>Categories: <select multiple name="categories">
<option value="%s">Entertainment</option> <option value="%s">Entertainment</option>
<option value="%s">It&#39;s a test</option> <option value="%s">It&#x27;s a test</option>
<option value="%s">Third test</option> <option value="%s">Third test</option>
</select></li> </select></li>
<li>Status: <select name="status"> <li>Status: <select name="status">
...@@ -1290,7 +1290,7 @@ class ModelFormBasicTests(TestCase): ...@@ -1290,7 +1290,7 @@ class ModelFormBasicTests(TestCase):
<li><label for="id_categories">Categories:</label> <li><label for="id_categories">Categories:</label>
<select multiple name="categories" id="id_categories"> <select multiple name="categories" id="id_categories">
<option value="%d" selected>Entertainment</option> <option value="%d" selected>Entertainment</option>
<option value="%d" selected>It&39;s a test</option> <option value="%d" selected>It&#x27;s a test</option>
<option value="%d">Third test</option> <option value="%d">Third test</option>
</select></li>""" </select></li>"""
% (self.c1.pk, self.c2.pk, self.c3.pk)) % (self.c1.pk, self.c2.pk, self.c3.pk))
...@@ -1361,7 +1361,7 @@ class ModelFormBasicTests(TestCase): ...@@ -1361,7 +1361,7 @@ class ModelFormBasicTests(TestCase):
<tr><th>Article:</th><td><textarea rows="10" cols="40" name="article" required></textarea></td></tr> <tr><th>Article:</th><td><textarea rows="10" cols="40" name="article" required></textarea></td></tr>
<tr><th>Categories:</th><td><select multiple name="categories"> <tr><th>Categories:</th><td><select multiple name="categories">
<option value="%s">Entertainment</option> <option value="%s">Entertainment</option>
<option value="%s">It&#39;s a test</option> <option value="%s">It&#x27;s a test</option>
<option value="%s">Third test</option> <option value="%s">Third test</option>
</select></td></tr> </select></td></tr>
<tr><th>Status:</th><td><select name="status"> <tr><th>Status:</th><td><select name="status">
...@@ -1391,7 +1391,7 @@ class ModelFormBasicTests(TestCase): ...@@ -1391,7 +1391,7 @@ class ModelFormBasicTests(TestCase):
<li>Article: <textarea rows="10" cols="40" name="article" required>Hello.</textarea></li> <li>Article: <textarea rows="10" cols="40" name="article" required>Hello.</textarea></li>
<li>Categories: <select multiple name="categories"> <li>Categories: <select multiple name="categories">
<option value="%s" selected>Entertainment</option> <option value="%s" selected>Entertainment</option>
<option value="%s">It&#39;s a test</option> <option value="%s">It&#x27;s a test</option>
<option value="%s">Third test</option> <option value="%s">Third test</option>
</select></li> </select></li>
<li>Status: <select name="status"> <li>Status: <select name="status">
...@@ -1535,7 +1535,7 @@ class ModelFormBasicTests(TestCase): ...@@ -1535,7 +1535,7 @@ class ModelFormBasicTests(TestCase):
<li>Article: <textarea rows="10" cols="40" name="article" required></textarea></li> <li>Article: <textarea rows="10" cols="40" name="article" required></textarea></li>
<li>Categories: <select multiple name="categories"> <li>Categories: <select multiple name="categories">
<option value="%s">Entertainment</option> <option value="%s">Entertainment</option>
<option value="%s">It&#39;s a test</option> <option value="%s">It&#x27;s a test</option>
<option value="%s">Third test</option> <option value="%s">Third test</option>
</select> </li> </select> </li>
<li>Status: <select name="status"> <li>Status: <select name="status">
...@@ -1561,7 +1561,7 @@ class ModelFormBasicTests(TestCase): ...@@ -1561,7 +1561,7 @@ class ModelFormBasicTests(TestCase):
<li>Article: <textarea rows="10" cols="40" name="article" required></textarea></li> <li>Article: <textarea rows="10" cols="40" name="article" required></textarea></li>
<li>Categories: <select multiple name="categories"> <li>Categories: <select multiple name="categories">
<option value="%s">Entertainment</option> <option value="%s">Entertainment</option>
<option value="%s">It&#39;s a test</option> <option value="%s">It&#x27;s a test</option>
<option value="%s">Third test</option> <option value="%s">Third test</option>
<option value="%s">Fourth</option> <option value="%s">Fourth</option>
</select></li> </select></li>
......
...@@ -15,7 +15,7 @@ class AddslashesTests(SimpleTestCase): ...@@ -15,7 +15,7 @@ class AddslashesTests(SimpleTestCase):
@setup({'addslashes02': '{{ a|addslashes }} {{ b|addslashes }}'}) @setup({'addslashes02': '{{ a|addslashes }} {{ b|addslashes }}'})
def test_addslashes02(self): def test_addslashes02(self):
output = self.engine.render_to_string('addslashes02', {"a": "<a>'", "b": mark_safe("<a>'")}) output = self.engine.render_to_string('addslashes02', {"a": "<a>'", "b": mark_safe("<a>'")})
self.assertEqual(output, r"&lt;a&gt;\&#39; <a>\'") self.assertEqual(output, r"&lt;a&gt;\&#x27; <a>\'")
class FunctionTests(SimpleTestCase): class FunctionTests(SimpleTestCase):
......
...@@ -19,7 +19,7 @@ class MakeListTests(SimpleTestCase): ...@@ -19,7 +19,7 @@ class MakeListTests(SimpleTestCase):
@setup({'make_list02': '{{ a|make_list }}'}) @setup({'make_list02': '{{ a|make_list }}'})
def test_make_list02(self): def test_make_list02(self):
output = self.engine.render_to_string('make_list02', {"a": mark_safe("&")}) output = self.engine.render_to_string('make_list02', {"a": mark_safe("&")})
self.assertEqual(output, "[&#39;&amp;&#39;]") self.assertEqual(output, '[&#x27;&amp;&#x27;]')
@setup({'make_list03': '{% autoescape off %}{{ a|make_list|stringformat:"s"|safe }}{% endautoescape %}'}) @setup({'make_list03': '{% autoescape off %}{{ a|make_list|stringformat:"s"|safe }}{% endautoescape %}'})
def test_make_list03(self): def test_make_list03(self):
......
...@@ -9,7 +9,7 @@ class TitleTests(SimpleTestCase): ...@@ -9,7 +9,7 @@ class TitleTests(SimpleTestCase):
@setup({'title1': '{{ a|title }}'}) @setup({'title1': '{{ a|title }}'})
def test_title1(self): def test_title1(self):
output = self.engine.render_to_string('title1', {'a': 'JOE\'S CRAB SHACK'}) output = self.engine.render_to_string('title1', {'a': 'JOE\'S CRAB SHACK'})
self.assertEqual(output, 'Joe&#39;s Crab Shack') self.assertEqual(output, 'Joe&#x27;s Crab Shack')
@setup({'title2': '{{ a|title }}'}) @setup({'title2': '{{ a|title }}'})
def test_title2(self): def test_title2(self):
......
...@@ -52,7 +52,7 @@ class UrlizeTests(SimpleTestCase): ...@@ -52,7 +52,7 @@ class UrlizeTests(SimpleTestCase):
@setup({'urlize06': '{{ a|urlize }}'}) @setup({'urlize06': '{{ a|urlize }}'})
def test_urlize06(self): def test_urlize06(self):
output = self.engine.render_to_string('urlize06', {'a': "<script>alert('foo')</script>"}) output = self.engine.render_to_string('urlize06', {'a': "<script>alert('foo')</script>"})
self.assertEqual(output, '&lt;script&gt;alert(&#39;foo&#39;)&lt;/script&gt;') self.assertEqual(output, '&lt;script&gt;alert(&#x27;foo&#x27;)&lt;/script&gt;')
# mailto: testing for urlize # mailto: testing for urlize
@setup({'urlize07': '{{ a|urlize }}'}) @setup({'urlize07': '{{ a|urlize }}'})
...@@ -113,7 +113,7 @@ class FunctionTests(SimpleTestCase): ...@@ -113,7 +113,7 @@ class FunctionTests(SimpleTestCase):
) )
self.assertEqual( self.assertEqual(
urlize('www.server.com\'abc'), urlize('www.server.com\'abc'),
'<a href="http://www.server.com" rel="nofollow">www.server.com</a>&#39;abc', '<a href="http://www.server.com" rel="nofollow">www.server.com</a>&#x27;abc',
) )
self.assertEqual( self.assertEqual(
urlize('www.server.com<abc'), urlize('www.server.com<abc'),
...@@ -284,7 +284,7 @@ class FunctionTests(SimpleTestCase): ...@@ -284,7 +284,7 @@ class FunctionTests(SimpleTestCase):
('<>', ('&lt;', '&gt;')), ('<>', ('&lt;', '&gt;')),
('[]', ('[', ']')), ('[]', ('[', ']')),
('""', ('&quot;', '&quot;')), ('""', ('&quot;', '&quot;')),
("''", ('&#39;', '&#39;')), ("''", ('&#x27;', '&#x27;')),
) )
for wrapping_in, (start_out, end_out) in wrapping_chars: for wrapping_in, (start_out, end_out) in wrapping_chars:
with self.subTest(wrapping_in=wrapping_in): with self.subTest(wrapping_in=wrapping_in):
......
...@@ -78,7 +78,7 @@ class UrlTagTests(SimpleTestCase): ...@@ -78,7 +78,7 @@ class UrlTagTests(SimpleTestCase):
@setup({'url12': '{% url "client_action" id=client.id action="!$&\'()*+,;=~:@," %}'}) @setup({'url12': '{% url "client_action" id=client.id action="!$&\'()*+,;=~:@," %}'})
def test_url12(self): def test_url12(self):
output = self.engine.render_to_string('url12', {'client': {'id': 1}}) output = self.engine.render_to_string('url12', {'client': {'id': 1}})
self.assertEqual(output, '/client/1/!$&amp;&#39;()*+,;=~:@,/') self.assertEqual(output, '/client/1/!$&amp;&#x27;()*+,;=~:@,/')
@setup({'url13': '{% url "client_action" id=client.id action=arg|join:"-" %}'}) @setup({'url13': '{% url "client_action" id=client.id action=arg|join:"-" %}'})
def test_url13(self): def test_url13(self):
......
...@@ -27,7 +27,7 @@ class TestUtilsHtml(SimpleTestCase): ...@@ -27,7 +27,7 @@ class TestUtilsHtml(SimpleTestCase):
('<', '&lt;'), ('<', '&lt;'),
('>', '&gt;'), ('>', '&gt;'),
('"', '&quot;'), ('"', '&quot;'),
("'", '&#39;'), ("'", '&#x27;'),
) )
# Substitution patterns for testing the above items. # Substitution patterns for testing the above items.
patterns = ("%s", "asdf%sfdsa", "%s1", "1%sb") patterns = ("%s", "asdf%sfdsa", "%s1", "1%sb")
...@@ -70,6 +70,8 @@ class TestUtilsHtml(SimpleTestCase): ...@@ -70,6 +70,8 @@ class TestUtilsHtml(SimpleTestCase):
items = ( items = (
('<p>See: &#39;&eacute; is an apostrophe followed by e acute</p>', ('<p>See: &#39;&eacute; is an apostrophe followed by e acute</p>',
'See: &#39;&eacute; is an apostrophe followed by e acute'), 'See: &#39;&eacute; is an apostrophe followed by e acute'),
('<p>See: &#x27;&eacute; is an apostrophe followed by e acute</p>',
'See: &#x27;&eacute; is an apostrophe followed by e acute'),
('<adf>a', 'a'), ('<adf>a', 'a'),
('</adf>a', 'a'), ('</adf>a', 'a'),
('<asdf><asdf>e', 'e'), ('<asdf><asdf>e', 'e'),
......
...@@ -44,22 +44,22 @@ class CsrfViewTests(SimpleTestCase): ...@@ -44,22 +44,22 @@ class CsrfViewTests(SimpleTestCase):
self.assertContains( self.assertContains(
response, response,
'You are seeing this message because this HTTPS site requires a ' 'You are seeing this message because this HTTPS site requires a '
'&#39;Referer header&#39; to be sent by your Web browser, but ' '&#x27;Referer header&#x27; to be sent by your Web browser, but '
'none was sent.', 'none was sent.',
status_code=403, status_code=403,
) )
self.assertContains( self.assertContains(
response, response,
'If you have configured your browser to disable &#39;Referer&#39; ' 'If you have configured your browser to disable &#x27;Referer&#x27; '
'headers, please re-enable them, at least for this site, or for ' 'headers, please re-enable them, at least for this site, or for '
'HTTPS connections, or for &#39;same-origin&#39; requests.', 'HTTPS connections, or for &#x27;same-origin&#x27; requests.',
status_code=403, status_code=403,
) )
self.assertContains( self.assertContains(
response, response,
'If you are using the &lt;meta name=&quot;referrer&quot; ' 'If you are using the &lt;meta name=&quot;referrer&quot; '
'content=&quot;no-referrer&quot;&gt; tag or including the ' 'content=&quot;no-referrer&quot;&gt; tag or including the '
'&#39;Referrer-Policy: no-referrer&#39; header, please remove them.', '&#x27;Referrer-Policy: no-referrer&#x27; header, please remove them.',
status_code=403, status_code=403,
) )
......
...@@ -304,7 +304,7 @@ class ExceptionReporterTests(SimpleTestCase): ...@@ -304,7 +304,7 @@ class ExceptionReporterTests(SimpleTestCase):
reporter = ExceptionReporter(request, exc_type, exc_value, tb) reporter = ExceptionReporter(request, exc_type, exc_value, tb)
html = reporter.get_traceback_html() html = reporter.get_traceback_html()
self.assertInHTML('<h1>ValueError at /test_view/</h1>', html) self.assertInHTML('<h1>ValueError at /test_view/</h1>', html)
self.assertIn('<pre class="exception_value">Can&#39;t find my keys</pre>', html) self.assertIn('<pre class="exception_value">Can&#x27;t find my keys</pre>', html)
self.assertIn('<th>Request Method:</th>', html) self.assertIn('<th>Request Method:</th>', html)
self.assertIn('<th>Request URL:</th>', html) self.assertIn('<th>Request URL:</th>', html)
self.assertIn('<h3 id="user-info">USER</h3>', html) self.assertIn('<h3 id="user-info">USER</h3>', html)
...@@ -325,7 +325,7 @@ class ExceptionReporterTests(SimpleTestCase): ...@@ -325,7 +325,7 @@ class ExceptionReporterTests(SimpleTestCase):
reporter = ExceptionReporter(None, exc_type, exc_value, tb) reporter = ExceptionReporter(None, exc_type, exc_value, tb)
html = reporter.get_traceback_html() html = reporter.get_traceback_html()
self.assertInHTML('<h1>ValueError</h1>', html) self.assertInHTML('<h1>ValueError</h1>', html)
self.assertIn('<pre class="exception_value">Can&#39;t find my keys</pre>', html) self.assertIn('<pre class="exception_value">Can&#x27;t find my keys</pre>', html)
self.assertNotIn('<th>Request Method:</th>', html) self.assertNotIn('<th>Request Method:</th>', html)
self.assertNotIn('<th>Request URL:</th>', html) self.assertNotIn('<th>Request URL:</th>', html)
self.assertNotIn('<h3 id="user-info">USER</h3>', html) self.assertNotIn('<h3 id="user-info">USER</h3>', html)
...@@ -463,7 +463,7 @@ class ExceptionReporterTests(SimpleTestCase): ...@@ -463,7 +463,7 @@ class ExceptionReporterTests(SimpleTestCase):
reporter = ExceptionReporter(request, None, "I'm a little teapot", None) reporter = ExceptionReporter(request, None, "I'm a little teapot", None)
html = reporter.get_traceback_html() html = reporter.get_traceback_html()
self.assertInHTML('<h1>Report at /test_view/</h1>', html) self.assertInHTML('<h1>Report at /test_view/</h1>', html)
self.assertIn('<pre class="exception_value">I&#39;m a little teapot</pre>', html) self.assertIn('<pre class="exception_value">I&#x27;m a little teapot</pre>', html)
self.assertIn('<th>Request Method:</th>', html) self.assertIn('<th>Request Method:</th>', html)
self.assertIn('<th>Request URL:</th>', html) self.assertIn('<th>Request URL:</th>', html)
self.assertNotIn('<th>Exception Type:</th>', html) self.assertNotIn('<th>Exception Type:</th>', html)
...@@ -476,7 +476,7 @@ class ExceptionReporterTests(SimpleTestCase): ...@@ -476,7 +476,7 @@ class ExceptionReporterTests(SimpleTestCase):
reporter = ExceptionReporter(None, None, "I'm a little teapot", None) reporter = ExceptionReporter(None, None, "I'm a little teapot", None)
html = reporter.get_traceback_html() html = reporter.get_traceback_html()
self.assertInHTML('<h1>Report</h1>', html) self.assertInHTML('<h1>Report</h1>', html)
self.assertIn('<pre class="exception_value">I&#39;m a little teapot</pre>', html) self.assertIn('<pre class="exception_value">I&#x27;m a little teapot</pre>', html)
self.assertNotIn('<th>Request Method:</th>', html) self.assertNotIn('<th>Request Method:</th>', html)
self.assertNotIn('<th>Request URL:</th>', html) self.assertNotIn('<th>Request URL:</th>', html)
self.assertNotIn('<th>Exception Type:</th>', html) self.assertNotIn('<th>Exception Type:</th>', html)
...@@ -508,7 +508,7 @@ class ExceptionReporterTests(SimpleTestCase): ...@@ -508,7 +508,7 @@ class ExceptionReporterTests(SimpleTestCase):
except Exception: except Exception:
exc_type, exc_value, tb = sys.exc_info() exc_type, exc_value, tb = sys.exc_info()
html = ExceptionReporter(None, exc_type, exc_value, tb).get_traceback_html() html = ExceptionReporter(None, exc_type, exc_value, tb).get_traceback_html()
self.assertIn('<td class="code"><pre>&#39;&lt;p&gt;Local variable&lt;/p&gt;&#39;</pre></td>', html) self.assertIn('<td class="code"><pre>&#x27;&lt;p&gt;Local variable&lt;/p&gt;&#x27;</pre></td>', html)
def test_unprintable_values_handling(self): def test_unprintable_values_handling(self):
"Unprintable values should not make the output generation choke." "Unprintable values should not make the output generation choke."
...@@ -607,7 +607,7 @@ class ExceptionReporterTests(SimpleTestCase): ...@@ -607,7 +607,7 @@ class ExceptionReporterTests(SimpleTestCase):
An exception report can be generated for requests with 'items' in An exception report can be generated for requests with 'items' in
request GET, POST, FILES, or COOKIES QueryDicts. request GET, POST, FILES, or COOKIES QueryDicts.
""" """
value = '<td>items</td><td class="code"><pre>&#39;Oops&#39;</pre></td>' value = '<td>items</td><td class="code"><pre>&#x27;Oops&#x27;</pre></td>'
# GET # GET
request = self.rf.get('/test_view/?items=Oops') request = self.rf.get('/test_view/?items=Oops')
reporter = ExceptionReporter(request, None, None, None) reporter = ExceptionReporter(request, None, None, None)
...@@ -634,7 +634,7 @@ class ExceptionReporterTests(SimpleTestCase): ...@@ -634,7 +634,7 @@ class ExceptionReporterTests(SimpleTestCase):
request = rf.get('/test_view/') request = rf.get('/test_view/')
reporter = ExceptionReporter(request, None, None, None) reporter = ExceptionReporter(request, None, None, None)
html = reporter.get_traceback_html() html = reporter.get_traceback_html()
self.assertInHTML('<td>items</td><td class="code"><pre>&#39;Oops&#39;</pre></td>', html) self.assertInHTML('<td>items</td><td class="code"><pre>&#x27;Oops&#x27;</pre></td>', html)
def test_exception_fetching_user(self): def test_exception_fetching_user(self):
""" """
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment