浏览代码

Fixed #23269 -- Deprecated django.utils.remove_tags() and removetags filter.

Also the unused, undocumented django.utils.html.strip_entities() function.
Tim Graham 10 年之前
父节点
当前提交
e122facbd8

+ 11 - 0
django/utils/html.py

@@ -4,7 +4,9 @@ from __future__ import unicode_literals
 
 import re
 import sys
+import warnings
 
+from django.utils.deprecation import RemovedInDjango20Warning
 from django.utils.encoding import force_text, force_str
 from django.utils.functional import allow_lazy
 from django.utils.http import RFC3986_GENDELIMS, RFC3986_SUBDELIMS
@@ -177,6 +179,11 @@ strip_tags = allow_lazy(strip_tags)
 
 def remove_tags(html, tags):
     """Returns the given HTML with given tags removed."""
+    warnings.warn(
+        "django.utils.html.remove_tags() and the removetags template filter "
+        "are deprecated. Consider using the bleach library instead.",
+        RemovedInDjango20Warning, stacklevel=3
+    )
     tags = [re.escape(tag) for tag in tags.split()]
     tags_re = '(%s)' % '|'.join(tags)
     starttag_re = re.compile(r'<%s(/?>|(\s+[^>]*>))' % tags_re, re.U)
@@ -195,6 +202,10 @@ strip_spaces_between_tags = allow_lazy(strip_spaces_between_tags, six.text_type)
 
 def strip_entities(value):
     """Returns the given HTML with all entities (&something;) stripped."""
+    warnings.warn(
+        "django.utils.html.strip_entities() is deprecated.",
+        RemovedInDjango20Warning, stacklevel=2
+    )
     return re.sub(r'&(?:\w+|#\d+);', '', force_text(value))
 strip_entities = allow_lazy(strip_entities, six.text_type)
 

+ 5 - 0
docs/internals/deprecation.txt

@@ -49,6 +49,11 @@ about each item can often be found in the release notes of two versions prior.
 * The backward compatible shim  to rename ``django.forms.Form._has_changed()``
   to ``has_changed()`` will be removed.
 
+* The ``removetags`` template filter will be removed.
+
+* The ``remove_tags()`` and ``strip_entities()`` functions in
+  ``django.utils.html`` will be removed.
+
 .. _deprecation-removed-in-1.9:
 
 1.9

+ 7 - 0
docs/ref/templates/builtins.txt

@@ -1918,6 +1918,13 @@ If ``value`` is the list ``['a', 'b', 'c', 'd']``, the output could be ``"b"``.
 removetags
 ^^^^^^^^^^
 
+.. deprecated:: 1.8
+
+    ``removetags`` cannot guarantee HTML safe output and has been deprecated due
+    to security concerns. Consider using `bleach`_ instead.
+
+.. _bleach: http://bleach.readthedocs.org/en/latest/
+
 Removes a space-separated list of [X]HTML tags from the output.
 
 For example::

+ 6 - 2
docs/ref/utils.txt

@@ -630,10 +630,13 @@ escaping HTML.
     If you are looking for a more robust solution, take a look at the `bleach`_
     Python library.
 
-    .. _bleach: https://pypi.python.org/pypi/bleach
-
 .. function:: remove_tags(value, tags)
 
+    .. deprecated:: 1.8
+
+        ``remove_tags()`` cannot guarantee HTML safe output and has been
+        deprecated due to security concerns. Consider using `bleach`_ instead.
+
     Removes a space-separated list of [X]HTML tag names from the output.
 
     Absolutely NO guarantee is provided about the resulting string being HTML
@@ -656,6 +659,7 @@ escaping HTML.
     the return value will be ``"<B>Joel</B> <button>is</button> a slug"``.
 
 .. _str.format: http://docs.python.org/library/stdtypes.html#str.format
+.. _bleach: https://pypi.python.org/pypi/bleach
 
 ``django.utils.http``
 =====================

+ 11 - 0
docs/releases/1.8.txt

@@ -682,3 +682,14 @@ Using the new syntax, this becomes::
 
 Rename this method to :meth:`~django.forms.Field.has_changed` by removing the
 leading underscore. The old name will still work until Django 2.0.
+
+``django.utils.html.remove_tags()`` and ``removetags`` template filter
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+``django.utils.html.remove_tags()`` as well as the template filter
+``removetags`` have been deprecated as they cannot guarantee safe output. Their
+existence is likely to lead to their use in security-sensitive contexts where
+they are not actually safe.
+
+The unused and undocumented ``django.utils.html.strip_entities()`` function has
+also been deprecated.

+ 10 - 4
tests/defaultfilters/tests.py

@@ -433,9 +433,13 @@ class DefaultFiltersTests(TestCase):
                          'line 1<br />line 2')
 
     def test_removetags(self):
-        self.assertEqual(removetags('some <b>html</b> with <script>alert'
-            '("You smell")</script> disallowed <img /> tags', 'script img'),
-            'some <b>html</b> with alert("You smell") disallowed  tags')
+        with warnings.catch_warnings(record=True):
+            warnings.simplefilter("always")
+            self.assertEqual(removetags('some <b>html</b> with <script>alert'
+                '("You smell")</script> disallowed <img /> tags', 'script img'),
+                'some <b>html</b> with alert("You smell") disallowed  tags')
+
+    def test_striptags(self):
         self.assertEqual(striptags('some <b>html</b> with <script>alert'
             '("You smell")</script> disallowed <img /> tags'),
             'some html with alert("You smell") disallowed  tags')
@@ -713,7 +717,9 @@ class DefaultFiltersTests(TestCase):
         self.assertEqual(escape(123), '123')
         self.assertEqual(linebreaks_filter(123), '<p>123</p>')
         self.assertEqual(linebreaksbr(123), '123')
-        self.assertEqual(removetags(123, 'a'), '123')
+        with warnings.catch_warnings(record=True):
+            warnings.simplefilter("always")
+            self.assertEqual(removetags(123, 'a'), '123')
         self.assertEqual(striptags(123), '123')
 
 

+ 2 - 1
tests/template_tests/tests.py

@@ -590,7 +590,8 @@ class TemplateTests(TestCase):
                                             # Ignore deprecations of using the wrong number of variables with the 'for' tag.
                                             # and warnings for {% url %} reversing by dotted path
                                             warnings.filterwarnings("ignore", category=RemovedInDjango20Warning, module="django.template.defaulttags")
-                                            # Ignore deprecations of old style unordered_list.
+                                            # Ignore deprecations of old style unordered_list
+                                            # and removetags.
                                             warnings.filterwarnings("ignore", category=RemovedInDjango20Warning, module="django.template.defaultfilters")
                                             output = self.render(test_template, vals)
                                     except ShouldNotExecuteException:

+ 10 - 3
tests/utils_tests/test_html.py

@@ -4,6 +4,7 @@ from __future__ import unicode_literals
 from datetime import datetime
 import os
 from unittest import TestCase
+import warnings
 
 from django.utils import html, safestring
 from django.utils._os import upath
@@ -124,7 +125,9 @@ class TestUtilsHtml(TestCase):
         # Strings that should come out untouched.
         values = ("&", "&a", "&a", "a&#a")
         for value in values:
-            self.check_output(f, value)
+            with warnings.catch_warnings(record=True):
+                warnings.simplefilter("always")
+                self.check_output(f, value)
         # Valid entities that should be stripped from the patterns.
         entities = ("&#1;", "&#12;", "&a;", "&fdasdfasdfasdf;")
         patterns = (
@@ -135,7 +138,9 @@ class TestUtilsHtml(TestCase):
         )
         for entity in entities:
             for in_pattern, output in patterns:
-                self.check_output(f, in_pattern % {'entity': entity}, output)
+                with warnings.catch_warnings(record=True):
+                    warnings.simplefilter("always")
+                    self.check_output(f, in_pattern % {'entity': entity}, output)
 
     def test_escapejs(self):
         f = html.escapejs
@@ -156,7 +161,9 @@ class TestUtilsHtml(TestCase):
             ("<a>x</a> <p><b>y</b></p>", "a b", "x <p>y</p>"),
         )
         for value, tags, output in items:
-            self.assertEqual(f(value, tags), output)
+            with warnings.catch_warnings(record=True):
+                warnings.simplefilter("always")
+                self.assertEqual(f(value, tags), output)
 
     def test_smart_urlquote(self):
         quote = html.smart_urlquote