mirror of
https://github.com/django/django.git
synced 2025-04-12 03:22:21 +00:00
Fixed #36000 -- Deprecated HTTP as the default protocol in urlize and urlizetrunc.
This commit is contained in:
parent
ed1e7c02c9
commit
ec7044c706
@ -662,3 +662,8 @@ SECURE_REDIRECT_EXEMPT = []
|
||||
SECURE_REFERRER_POLICY = "same-origin"
|
||||
SECURE_SSL_HOST = None
|
||||
SECURE_SSL_REDIRECT = False
|
||||
|
||||
# RemovedInDjango70Warning: A transitional setting helpful in early adoption of
|
||||
# HTTPS as the default protocol in urlize and urlizetrunc when no protocol is
|
||||
# provided. Set to True to assume HTTPS during the Django 6.x release cycle.
|
||||
URLIZE_ASSUME_HTTPS = False
|
||||
|
@ -3,12 +3,15 @@
|
||||
import html
|
||||
import json
|
||||
import re
|
||||
import warnings
|
||||
from collections.abc import Mapping
|
||||
from html.parser import HTMLParser
|
||||
from urllib.parse import parse_qsl, quote, unquote, urlencode, urlsplit, urlunsplit
|
||||
|
||||
from django.conf import settings
|
||||
from django.core.exceptions import SuspiciousOperation, ValidationError
|
||||
from django.core.validators import EmailValidator
|
||||
from django.utils.deprecation import RemovedInDjango70Warning
|
||||
from django.utils.functional import Promise, cached_property, keep_lazy, keep_lazy_text
|
||||
from django.utils.http import RFC3986_GENDELIMS, RFC3986_SUBDELIMS
|
||||
from django.utils.regex_helper import _lazy_re_compile
|
||||
@ -343,7 +346,24 @@ class Urlizer:
|
||||
if len(middle) <= MAX_URL_LENGTH and self.simple_url_re.match(middle):
|
||||
url = smart_urlquote(html.unescape(middle))
|
||||
elif len(middle) <= MAX_URL_LENGTH and self.simple_url_2_re.match(middle):
|
||||
url = smart_urlquote("http://%s" % html.unescape(middle))
|
||||
unescaped_middle = html.unescape(middle)
|
||||
# RemovedInDjango70Warning: When the deprecation ends, replace with:
|
||||
# url = smart_urlquote(f"https://{unescaped_middle}")
|
||||
protocol = (
|
||||
"https"
|
||||
if getattr(settings, "URLIZE_ASSUME_HTTPS", False)
|
||||
else "http"
|
||||
)
|
||||
if not settings.URLIZE_ASSUME_HTTPS:
|
||||
warnings.warn(
|
||||
"The default protocol will be changed from HTTP to "
|
||||
"HTTPS in Django 7.0. Set the URLIZE_ASSUME_HTTPS "
|
||||
"transitional setting to True to opt into using HTTPS as the "
|
||||
"new default protocol.",
|
||||
RemovedInDjango70Warning,
|
||||
stacklevel=2,
|
||||
)
|
||||
url = smart_urlquote(f"{protocol}://{unescaped_middle}")
|
||||
elif ":" not in middle and self.is_email_simple(middle):
|
||||
local, domain = middle.rsplit("@", 1)
|
||||
# Encode per RFC 6068 Section 2 (items 1, 4, 5). Defer any IDNA
|
||||
|
@ -23,6 +23,11 @@ details on these changes.
|
||||
* The ``django.contrib.postgres.aggregates.mixins.OrderableAggMixin`` class
|
||||
will be removed.
|
||||
|
||||
* The default protocol in ``urlize`` and ``urlizetrunc`` template filters will
|
||||
change from HTTP to HTTPS.
|
||||
|
||||
* The ``URLIZE_ASSUME_HTTPS`` transitional setting will be removed.
|
||||
|
||||
.. _deprecation-removed-in-6.1:
|
||||
|
||||
6.1
|
||||
|
@ -2955,6 +2955,21 @@ enabled if a proxy which sets this header is in use.
|
||||
|
||||
:setting:`USE_X_FORWARDED_HOST` takes priority over this setting.
|
||||
|
||||
.. setting:: URLIZE_ASSUME_HTTPS
|
||||
|
||||
``URLIZE_ASSUME_HTTPS``
|
||||
-----------------------
|
||||
|
||||
.. versionadded:: 6.0
|
||||
.. deprecated:: 6.0
|
||||
|
||||
Default: ``False``
|
||||
|
||||
Set this transitional setting to ``True`` to opt into using HTTPS as the
|
||||
default protocol when none is provided in URLs processed by the
|
||||
:tfilter:`urlize` and :tfilter:`urlizetrunc` template filters during the Django
|
||||
6.x release cycle.
|
||||
|
||||
.. setting:: WSGI_APPLICATION
|
||||
|
||||
``WSGI_APPLICATION``
|
||||
@ -3766,6 +3781,7 @@ Security
|
||||
|
||||
* :setting:`SECRET_KEY`
|
||||
* :setting:`SECRET_KEY_FALLBACKS`
|
||||
* :setting:`URLIZE_ASSUME_HTTPS`
|
||||
* :setting:`X_FRAME_OPTIONS`
|
||||
|
||||
Serialization
|
||||
|
@ -2905,9 +2905,23 @@ For example:
|
||||
|
||||
{{ value|urlize }}
|
||||
|
||||
If ``value`` is ``"Check out www.djangoproject.com"``, the output will be
|
||||
``"Check out <a href="http://www.djangoproject.com"
|
||||
rel="nofollow">www.djangoproject.com</a>"``.
|
||||
If ``value`` is ``"Check out www.djangoproject.com"``, the output will be:
|
||||
|
||||
.. code-block:: html+django
|
||||
|
||||
Check out <a href="http://www.djangoproject.com" rel="nofollow">www.djangoproject.com</a>
|
||||
|
||||
.. deprecated:: 6.0
|
||||
|
||||
The default protocol when none is provided will change from HTTP to HTTPS
|
||||
in Django 7.0. Hence, the output will become:
|
||||
|
||||
.. code-block:: html+django
|
||||
|
||||
Check out <a href="https://www.djangoproject.com" rel="nofollow">www.djangoproject.com</a>
|
||||
|
||||
Set the transitional setting :setting:`URLIZE_ASSUME_HTTPS` to ``True`` to
|
||||
opt into using HTTPS during the Django 6.x release cycle.
|
||||
|
||||
In addition to web links, ``urlize`` also converts email addresses into
|
||||
``mailto:`` links. If ``value`` is
|
||||
@ -2942,9 +2956,23 @@ For example:
|
||||
|
||||
{{ value|urlizetrunc:15 }}
|
||||
|
||||
If ``value`` is ``"Check out www.djangoproject.com"``, the output would be
|
||||
``'Check out <a href="http://www.djangoproject.com"
|
||||
rel="nofollow">www.djangoproj…</a>'``.
|
||||
If ``value`` is ``"Check out www.djangoproject.com"``, the output would be:
|
||||
|
||||
.. code-block:: html+django
|
||||
|
||||
Check out <a href="http://www.djangoproject.com" rel="nofollow">www.djangoproj…</a>
|
||||
|
||||
.. deprecated:: 6.0
|
||||
|
||||
The default protocol when none is provided will change from HTTP to HTTPS
|
||||
in Django 7.0. Hence, the output will become:
|
||||
|
||||
.. code-block:: html+django
|
||||
|
||||
Check out <a href="https://www.djangoproject.com" rel="nofollow">www.djangoproj…</a>
|
||||
|
||||
Set the transitional setting :setting:`URLIZE_ASSUME_HTTPS` to ``True`` to
|
||||
opt into using HTTPS during the Django 6.x release cycle.
|
||||
|
||||
As with urlize_, this filter should only be applied to plain text.
|
||||
|
||||
|
@ -321,6 +321,13 @@ Miscellaneous
|
||||
* The PostgreSQL ``OrderableAggMixin`` is deprecated in favor of the
|
||||
``order_by`` attribute now available on the ``Aggregate`` class.
|
||||
|
||||
* The default protocol in :tfilter:`urlize` and :tfilter:`urlizetrunc` will
|
||||
change from HTTP to HTTPS in Django 7.0. Set the transitional setting
|
||||
``URLIZE_ASSUME_HTTPS`` to ``True`` to opt into assuming HTTPS during the
|
||||
Django 6.x release cycle.
|
||||
|
||||
* ``URLIZE_ASSUME_HTTPS`` transitional setting is deprecated.
|
||||
|
||||
Features removed in 6.0
|
||||
=======================
|
||||
|
||||
|
@ -2,6 +2,7 @@ from unittest import mock
|
||||
|
||||
from django.template.defaultfilters import urlize
|
||||
from django.test import SimpleTestCase
|
||||
from django.test.utils import override_settings
|
||||
from django.utils.functional import lazy
|
||||
from django.utils.html import Urlizer
|
||||
from django.utils.safestring import mark_safe
|
||||
@ -109,6 +110,7 @@ class UrlizeTests(SimpleTestCase):
|
||||
)
|
||||
|
||||
|
||||
@override_settings(URLIZE_ASSUME_HTTPS=True)
|
||||
class FunctionTests(SimpleTestCase):
|
||||
def test_urls(self):
|
||||
self.assertEqual(
|
||||
@ -121,15 +123,16 @@ class FunctionTests(SimpleTestCase):
|
||||
)
|
||||
self.assertEqual(
|
||||
urlize("www.google.com"),
|
||||
'<a href="http://www.google.com" rel="nofollow">www.google.com</a>',
|
||||
'<a href="https://www.google.com" rel="nofollow">www.google.com</a>',
|
||||
)
|
||||
self.assertEqual(
|
||||
urlize("djangoproject.org"),
|
||||
'<a href="http://djangoproject.org" rel="nofollow">djangoproject.org</a>',
|
||||
'<a href="https://djangoproject.org" rel="nofollow">djangoproject.org</a>',
|
||||
)
|
||||
self.assertEqual(
|
||||
urlize("djangoproject.org/"),
|
||||
'<a href="http://djangoproject.org/" rel="nofollow">djangoproject.org/</a>',
|
||||
'<a href="https://djangoproject.org/" rel="nofollow">'
|
||||
"djangoproject.org/</a>",
|
||||
)
|
||||
|
||||
def test_url_split_chars(self):
|
||||
@ -137,21 +140,21 @@ class FunctionTests(SimpleTestCase):
|
||||
# part of URLs.
|
||||
self.assertEqual(
|
||||
urlize('www.server.com"abc'),
|
||||
'<a href="http://www.server.com" rel="nofollow">www.server.com</a>"'
|
||||
'<a href="https://www.server.com" rel="nofollow">www.server.com</a>"'
|
||||
"abc",
|
||||
)
|
||||
self.assertEqual(
|
||||
urlize("www.server.com'abc"),
|
||||
'<a href="http://www.server.com" rel="nofollow">www.server.com</a>''
|
||||
'<a href="https://www.server.com" rel="nofollow">www.server.com</a>''
|
||||
"abc",
|
||||
)
|
||||
self.assertEqual(
|
||||
urlize("www.server.com<abc"),
|
||||
'<a href="http://www.server.com" rel="nofollow">www.server.com</a><abc',
|
||||
'<a href="https://www.server.com" rel="nofollow">www.server.com</a><abc',
|
||||
)
|
||||
self.assertEqual(
|
||||
urlize("www.server.com>abc"),
|
||||
'<a href="http://www.server.com" rel="nofollow">www.server.com</a>>abc',
|
||||
'<a href="https://www.server.com" rel="nofollow">www.server.com</a>>abc',
|
||||
)
|
||||
|
||||
def test_email(self):
|
||||
@ -184,7 +187,7 @@ class FunctionTests(SimpleTestCase):
|
||||
def test_urlencoded(self):
|
||||
self.assertEqual(
|
||||
urlize("www.mystore.com/30%OffCoupons!"),
|
||||
'<a href="http://www.mystore.com/30%25OffCoupons" rel="nofollow">'
|
||||
'<a href="https://www.mystore.com/30%25OffCoupons" rel="nofollow">'
|
||||
"www.mystore.com/30%OffCoupons</a>!",
|
||||
)
|
||||
self.assertEqual(
|
||||
@ -222,7 +225,7 @@ class FunctionTests(SimpleTestCase):
|
||||
self.assertEqual(
|
||||
urlize("foo@bar.com or www.bar.com"),
|
||||
'<a href="mailto:foo@bar.com">foo@bar.com</a> or '
|
||||
'<a href="http://www.bar.com" rel="nofollow">www.bar.com</a>',
|
||||
'<a href="https://www.bar.com" rel="nofollow">www.bar.com</a>',
|
||||
)
|
||||
|
||||
def test_idn(self):
|
||||
@ -236,11 +239,11 @@ class FunctionTests(SimpleTestCase):
|
||||
)
|
||||
self.assertEqual(
|
||||
urlize("www.c✶.ws"),
|
||||
'<a href="http://www.c%E2%9C%B6.ws" rel="nofollow">www.c✶.ws</a>',
|
||||
'<a href="https://www.c%E2%9C%B6.ws" rel="nofollow">www.c✶.ws</a>',
|
||||
)
|
||||
self.assertEqual(
|
||||
urlize("c✶.org"),
|
||||
'<a href="http://c%E2%9C%B6.org" rel="nofollow">c✶.org</a>',
|
||||
'<a href="https://c%E2%9C%B6.org" rel="nofollow">c✶.org</a>',
|
||||
)
|
||||
self.assertEqual(
|
||||
urlize("info@c✶.org"),
|
||||
@ -250,12 +253,12 @@ class FunctionTests(SimpleTestCase):
|
||||
# Pre-encoded IDNA is urlized but not re-encoded.
|
||||
self.assertEqual(
|
||||
urlize("www.xn--iny-zx5a.com/idna2003"),
|
||||
'<a href="http://www.xn--iny-zx5a.com/idna2003"'
|
||||
'<a href="https://www.xn--iny-zx5a.com/idna2003"'
|
||||
' rel="nofollow">www.xn--iny-zx5a.com/idna2003</a>',
|
||||
)
|
||||
self.assertEqual(
|
||||
urlize("www.xn--fa-hia.com/idna2008"),
|
||||
'<a href="http://www.xn--fa-hia.com/idna2008"'
|
||||
'<a href="https://www.xn--fa-hia.com/idna2008"'
|
||||
' rel="nofollow">www.xn--fa-hia.com/idna2008</a>',
|
||||
)
|
||||
|
||||
@ -272,7 +275,7 @@ class FunctionTests(SimpleTestCase):
|
||||
#16656 - Check urlize accepts more TLDs
|
||||
"""
|
||||
self.assertEqual(
|
||||
urlize("usa.gov"), '<a href="http://usa.gov" rel="nofollow">usa.gov</a>'
|
||||
urlize("usa.gov"), '<a href="https://usa.gov" rel="nofollow">usa.gov</a>'
|
||||
)
|
||||
|
||||
def test_invalid_email(self):
|
||||
@ -351,11 +354,12 @@ class FunctionTests(SimpleTestCase):
|
||||
"""
|
||||
self.assertEqual(
|
||||
urlize("[see www.example.com]"),
|
||||
'[see <a href="http://www.example.com" rel="nofollow">www.example.com</a>]',
|
||||
'[see <a href="https://www.example.com" rel="nofollow">'
|
||||
"www.example.com</a>]",
|
||||
)
|
||||
self.assertEqual(
|
||||
urlize("see test[at[example.com"),
|
||||
'see <a href="http://test[at[example.com" rel="nofollow">'
|
||||
'see <a href="https://test[at[example.com" rel="nofollow">'
|
||||
"test[at[example.com</a>",
|
||||
)
|
||||
self.assertEqual(
|
||||
@ -443,22 +447,22 @@ class FunctionTests(SimpleTestCase):
|
||||
"""
|
||||
self.assertEqual(
|
||||
urlize("Go to djangoproject.com! and enjoy."),
|
||||
'Go to <a href="http://djangoproject.com" rel="nofollow">djangoproject.com'
|
||||
'Go to <a href="https://djangoproject.com" rel="nofollow">djangoproject.com'
|
||||
"</a>! and enjoy.",
|
||||
)
|
||||
self.assertEqual(
|
||||
urlize("Search for google.com/?q=! and see."),
|
||||
'Search for <a href="http://google.com/?q=" rel="nofollow">google.com/?q='
|
||||
'Search for <a href="https://google.com/?q=" rel="nofollow">google.com/?q='
|
||||
"</a>! and see.",
|
||||
)
|
||||
self.assertEqual(
|
||||
urlize("Search for google.com/?q=dj!`? and see."),
|
||||
'Search for <a href="http://google.com/?q=dj%21%60%3F" rel="nofollow">'
|
||||
'Search for <a href="https://google.com/?q=dj%21%60%3F" rel="nofollow">'
|
||||
"google.com/?q=dj!`?</a> and see.",
|
||||
)
|
||||
self.assertEqual(
|
||||
urlize("Search for google.com/?q=dj!`?! and see."),
|
||||
'Search for <a href="http://google.com/?q=dj%21%60%3F" rel="nofollow">'
|
||||
'Search for <a href="https://google.com/?q=dj%21%60%3F" rel="nofollow">'
|
||||
"google.com/?q=dj!`?</a>! and see.",
|
||||
)
|
||||
|
||||
@ -468,14 +472,14 @@ class FunctionTests(SimpleTestCase):
|
||||
def test_autoescape(self):
|
||||
self.assertEqual(
|
||||
urlize('foo<a href=" google.com ">bar</a>buz'),
|
||||
'foo<a href=" <a href="http://google.com" rel="nofollow">google.com'
|
||||
"</a> ">bar</a>buz",
|
||||
'foo<a href=" <a href="https://google.com" rel="nofollow">'
|
||||
"google.com</a> ">bar</a>buz",
|
||||
)
|
||||
|
||||
def test_autoescape_off(self):
|
||||
self.assertEqual(
|
||||
urlize('foo<a href=" google.com ">bar</a>buz', autoescape=False),
|
||||
'foo<a href=" <a href="http://google.com" rel="nofollow">google.com</a> ">'
|
||||
'foo<a href=" <a href="https://google.com" rel="nofollow">google.com</a> ">'
|
||||
"bar</a>buz",
|
||||
)
|
||||
|
||||
@ -483,7 +487,7 @@ class FunctionTests(SimpleTestCase):
|
||||
prepend_www = lazy(lambda url: "www." + url, str)
|
||||
self.assertEqual(
|
||||
urlize(prepend_www("google.com")),
|
||||
'<a href="http://www.google.com" rel="nofollow">www.google.com</a>',
|
||||
'<a href="https://www.google.com" rel="nofollow">www.google.com</a>',
|
||||
)
|
||||
|
||||
@mock.patch.object(Urlizer, "handle_word", return_value="test")
|
||||
|
@ -1,5 +1,6 @@
|
||||
from django.template.defaultfilters import urlizetrunc
|
||||
from django.test import SimpleTestCase
|
||||
from django.test.utils import override_settings
|
||||
from django.utils.safestring import mark_safe
|
||||
|
||||
from ..utils import setup
|
||||
@ -48,6 +49,7 @@ class UrlizetruncTests(SimpleTestCase):
|
||||
)
|
||||
|
||||
|
||||
@override_settings(URLIZE_ASSUME_HTTPS=True)
|
||||
class FunctionTests(SimpleTestCase):
|
||||
def test_truncate(self):
|
||||
uri = "http://31characteruri.com/test/"
|
||||
@ -93,13 +95,13 @@ class FunctionTests(SimpleTestCase):
|
||||
def test_autoescape(self):
|
||||
self.assertEqual(
|
||||
urlizetrunc('foo<a href=" google.com ">bar</a>buz', 10),
|
||||
'foo<a href=" <a href="http://google.com" rel="nofollow">google.com'
|
||||
"</a> ">bar</a>buz",
|
||||
'foo<a href=" <a href="https://google.com" rel="nofollow">'
|
||||
"google.com</a> ">bar</a>buz",
|
||||
)
|
||||
|
||||
def test_autoescape_off(self):
|
||||
self.assertEqual(
|
||||
urlizetrunc('foo<a href=" google.com ">bar</a>buz', 9, autoescape=False),
|
||||
'foo<a href=" <a href="http://google.com" rel="nofollow">google.c…</a> ">'
|
||||
'foo<a href=" <a href="https://google.com" rel="nofollow">google.c…</a> ">'
|
||||
"bar</a>buz",
|
||||
)
|
||||
|
@ -4,6 +4,8 @@ from datetime import datetime
|
||||
from django.core.exceptions import SuspiciousOperation
|
||||
from django.core.serializers.json import DjangoJSONEncoder
|
||||
from django.test import SimpleTestCase
|
||||
from django.test.utils import override_settings
|
||||
from django.utils.deprecation import RemovedInDjango70Warning
|
||||
from django.utils.functional import lazystr
|
||||
from django.utils.html import (
|
||||
conditional_escape,
|
||||
@ -22,6 +24,7 @@ from django.utils.html import (
|
||||
from django.utils.safestring import mark_safe
|
||||
|
||||
|
||||
@override_settings(URLIZE_ASSUME_HTTPS=True)
|
||||
class TestUtilsHtml(SimpleTestCase):
|
||||
def check_output(self, function, value, output=None):
|
||||
"""
|
||||
@ -369,17 +372,17 @@ class TestUtilsHtml(SimpleTestCase):
|
||||
tests = (
|
||||
(
|
||||
"Search for google.com/?q=! and see.",
|
||||
'Search for <a href="http://google.com/?q=">google.com/?q=</a>! and '
|
||||
'Search for <a href="https://google.com/?q=">google.com/?q=</a>! and '
|
||||
"see.",
|
||||
),
|
||||
(
|
||||
"Search for google.com/?q=1<! and see.",
|
||||
'Search for <a href="http://google.com/?q=1%3C">google.com/?q=1<'
|
||||
'Search for <a href="https://google.com/?q=1%3C">google.com/?q=1<'
|
||||
"</a>! and see.",
|
||||
),
|
||||
(
|
||||
lazystr("Search for google.com/?q=!"),
|
||||
'Search for <a href="http://google.com/?q=">google.com/?q=</a>!',
|
||||
'Search for <a href="https://google.com/?q=">google.com/?q=</a>!',
|
||||
),
|
||||
(
|
||||
"http://www.foo.bar/",
|
||||
@ -388,7 +391,7 @@ class TestUtilsHtml(SimpleTestCase):
|
||||
(
|
||||
"Look on www.نامهای.com.",
|
||||
"Look on <a "
|
||||
'href="http://www.%D9%86%D8%A7%D9%85%D9%87%E2%80%8C%D8%A7%DB%8C.com"'
|
||||
'href="https://www.%D9%86%D8%A7%D9%85%D9%87%E2%80%8C%D8%A7%DB%8C.com"'
|
||||
">www.نامهای.com</a>.",
|
||||
),
|
||||
("foo@example.com", '<a href="mailto:foo@example.com">foo@example.com</a>'),
|
||||
@ -422,6 +425,19 @@ class TestUtilsHtml(SimpleTestCase):
|
||||
with self.subTest(value=value):
|
||||
self.assertEqual(urlize(value), output)
|
||||
|
||||
@override_settings(URLIZE_ASSUME_HTTPS=False)
|
||||
def test_urlize_http_default_warning(self):
|
||||
msg = (
|
||||
"The default protocol will be changed from HTTP to HTTPS in Django 7.0. "
|
||||
"Set the URLIZE_ASSUME_HTTPS transitional setting to True to opt into "
|
||||
"using HTTPS as the new default protocol."
|
||||
)
|
||||
with self.assertWarnsMessage(RemovedInDjango70Warning, msg):
|
||||
self.assertEqual(
|
||||
urlize("Visit example.com"),
|
||||
'Visit <a href="http://example.com">example.com</a>',
|
||||
)
|
||||
|
||||
def test_urlize_unchanged_inputs(self):
|
||||
tests = (
|
||||
("a" + "@a" * 50000) + "a", # simple_email_re catastrophic test
|
||||
|
Loading…
x
Reference in New Issue
Block a user