1
0
mirror of https://github.com/django/django.git synced 2025-05-22 06:46:27 +00:00

Fixed #36000 -- Deprecated HTTP as the default protocol in urlize and urlizetrunc.

This commit is contained in:
Ahmed Nassar 2025-03-08 16:35:10 +02:00 committed by Sarah Boyce
parent ed1e7c02c9
commit ec7044c706
9 changed files with 141 additions and 38 deletions

View File

@ -662,3 +662,8 @@ SECURE_REDIRECT_EXEMPT = []
SECURE_REFERRER_POLICY = "same-origin" SECURE_REFERRER_POLICY = "same-origin"
SECURE_SSL_HOST = None SECURE_SSL_HOST = None
SECURE_SSL_REDIRECT = False 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

View File

@ -3,12 +3,15 @@
import html import html
import json import json
import re import re
import warnings
from collections.abc import Mapping from collections.abc import Mapping
from html.parser import HTMLParser from html.parser import HTMLParser
from urllib.parse import parse_qsl, quote, unquote, urlencode, urlsplit, urlunsplit 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.exceptions import SuspiciousOperation, ValidationError
from django.core.validators import EmailValidator 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.functional import Promise, cached_property, keep_lazy, keep_lazy_text
from django.utils.http import RFC3986_GENDELIMS, RFC3986_SUBDELIMS from django.utils.http import RFC3986_GENDELIMS, RFC3986_SUBDELIMS
from django.utils.regex_helper import _lazy_re_compile 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): if len(middle) <= MAX_URL_LENGTH and self.simple_url_re.match(middle):
url = smart_urlquote(html.unescape(middle)) url = smart_urlquote(html.unescape(middle))
elif len(middle) <= MAX_URL_LENGTH and self.simple_url_2_re.match(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): elif ":" not in middle and self.is_email_simple(middle):
local, domain = middle.rsplit("@", 1) local, domain = middle.rsplit("@", 1)
# Encode per RFC 6068 Section 2 (items 1, 4, 5). Defer any IDNA # Encode per RFC 6068 Section 2 (items 1, 4, 5). Defer any IDNA

View File

@ -23,6 +23,11 @@ details on these changes.
* The ``django.contrib.postgres.aggregates.mixins.OrderableAggMixin`` class * The ``django.contrib.postgres.aggregates.mixins.OrderableAggMixin`` class
will be removed. 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: .. _deprecation-removed-in-6.1:
6.1 6.1

View File

@ -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:`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 .. setting:: WSGI_APPLICATION
``WSGI_APPLICATION`` ``WSGI_APPLICATION``
@ -3766,6 +3781,7 @@ Security
* :setting:`SECRET_KEY` * :setting:`SECRET_KEY`
* :setting:`SECRET_KEY_FALLBACKS` * :setting:`SECRET_KEY_FALLBACKS`
* :setting:`URLIZE_ASSUME_HTTPS`
* :setting:`X_FRAME_OPTIONS` * :setting:`X_FRAME_OPTIONS`
Serialization Serialization

View File

@ -2905,9 +2905,23 @@ For example:
{{ value|urlize }} {{ value|urlize }}
If ``value`` is ``"Check out www.djangoproject.com"``, the output will be 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>"``. .. 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 In addition to web links, ``urlize`` also converts email addresses into
``mailto:`` links. If ``value`` is ``mailto:`` links. If ``value`` is
@ -2942,9 +2956,23 @@ For example:
{{ value|urlizetrunc:15 }} {{ value|urlizetrunc:15 }}
If ``value`` is ``"Check out www.djangoproject.com"``, the output would be 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>'``. .. 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. As with urlize_, this filter should only be applied to plain text.

View File

@ -321,6 +321,13 @@ Miscellaneous
* The PostgreSQL ``OrderableAggMixin`` is deprecated in favor of the * The PostgreSQL ``OrderableAggMixin`` is deprecated in favor of the
``order_by`` attribute now available on the ``Aggregate`` class. ``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 Features removed in 6.0
======================= =======================

View File

@ -2,6 +2,7 @@ from unittest import mock
from django.template.defaultfilters import urlize from django.template.defaultfilters import urlize
from django.test import SimpleTestCase from django.test import SimpleTestCase
from django.test.utils import override_settings
from django.utils.functional import lazy from django.utils.functional import lazy
from django.utils.html import Urlizer from django.utils.html import Urlizer
from django.utils.safestring import mark_safe from django.utils.safestring import mark_safe
@ -109,6 +110,7 @@ class UrlizeTests(SimpleTestCase):
) )
@override_settings(URLIZE_ASSUME_HTTPS=True)
class FunctionTests(SimpleTestCase): class FunctionTests(SimpleTestCase):
def test_urls(self): def test_urls(self):
self.assertEqual( self.assertEqual(
@ -121,15 +123,16 @@ class FunctionTests(SimpleTestCase):
) )
self.assertEqual( self.assertEqual(
urlize("www.google.com"), 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( self.assertEqual(
urlize("djangoproject.org"), 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( self.assertEqual(
urlize("djangoproject.org/"), 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): def test_url_split_chars(self):
@ -137,21 +140,21 @@ class FunctionTests(SimpleTestCase):
# part of URLs. # part of URLs.
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>&quot;' '<a href="https://www.server.com" rel="nofollow">www.server.com</a>&quot;'
"abc", "abc",
) )
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>&#x27;' '<a href="https://www.server.com" rel="nofollow">www.server.com</a>&#x27;'
"abc", "abc",
) )
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>&lt;abc', '<a href="https://www.server.com" rel="nofollow">www.server.com</a>&lt;abc',
) )
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>&gt;abc', '<a href="https://www.server.com" rel="nofollow">www.server.com</a>&gt;abc',
) )
def test_email(self): def test_email(self):
@ -184,7 +187,7 @@ class FunctionTests(SimpleTestCase):
def test_urlencoded(self): def test_urlencoded(self):
self.assertEqual( self.assertEqual(
urlize("www.mystore.com/30%OffCoupons!"), 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>!", "www.mystore.com/30%OffCoupons</a>!",
) )
self.assertEqual( self.assertEqual(
@ -222,7 +225,7 @@ class FunctionTests(SimpleTestCase):
self.assertEqual( self.assertEqual(
urlize("foo@bar.com or www.bar.com"), urlize("foo@bar.com or www.bar.com"),
'<a href="mailto:foo@bar.com">foo@bar.com</a> or ' '<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): def test_idn(self):
@ -236,11 +239,11 @@ class FunctionTests(SimpleTestCase):
) )
self.assertEqual( self.assertEqual(
urlize("www.c✶.ws"), 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( self.assertEqual(
urlize("c✶.org"), 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( self.assertEqual(
urlize("info@c✶.org"), urlize("info@c✶.org"),
@ -250,12 +253,12 @@ class FunctionTests(SimpleTestCase):
# Pre-encoded IDNA is urlized but not re-encoded. # Pre-encoded IDNA is urlized but not re-encoded.
self.assertEqual( self.assertEqual(
urlize("www.xn--iny-zx5a.com/idna2003"), 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>', ' rel="nofollow">www.xn--iny-zx5a.com/idna2003</a>',
) )
self.assertEqual( self.assertEqual(
urlize("www.xn--fa-hia.com/idna2008"), 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>', ' rel="nofollow">www.xn--fa-hia.com/idna2008</a>',
) )
@ -272,7 +275,7 @@ class FunctionTests(SimpleTestCase):
#16656 - Check urlize accepts more TLDs #16656 - Check urlize accepts more TLDs
""" """
self.assertEqual( 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): def test_invalid_email(self):
@ -351,11 +354,12 @@ class FunctionTests(SimpleTestCase):
""" """
self.assertEqual( self.assertEqual(
urlize("[see www.example.com]"), 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( self.assertEqual(
urlize("see test[at[example.com"), 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>", "test[at[example.com</a>",
) )
self.assertEqual( self.assertEqual(
@ -443,22 +447,22 @@ class FunctionTests(SimpleTestCase):
""" """
self.assertEqual( self.assertEqual(
urlize("Go to djangoproject.com! and enjoy."), 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.", "</a>! and enjoy.",
) )
self.assertEqual( self.assertEqual(
urlize("Search for google.com/?q=! and see."), 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.", "</a>! and see.",
) )
self.assertEqual( self.assertEqual(
urlize("Search for google.com/?q=dj!`? and see."), 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.", "google.com/?q=dj!`?</a> and see.",
) )
self.assertEqual( self.assertEqual(
urlize("Search for google.com/?q=dj!`?! and see."), 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.", "google.com/?q=dj!`?</a>! and see.",
) )
@ -468,14 +472,14 @@ class FunctionTests(SimpleTestCase):
def test_autoescape(self): def test_autoescape(self):
self.assertEqual( self.assertEqual(
urlize('foo<a href=" google.com ">bar</a>buz'), urlize('foo<a href=" google.com ">bar</a>buz'),
'foo&lt;a href=&quot; <a href="http://google.com" rel="nofollow">google.com' 'foo&lt;a href=&quot; <a href="https://google.com" rel="nofollow">'
"</a> &quot;&gt;bar&lt;/a&gt;buz", "google.com</a> &quot;&gt;bar&lt;/a&gt;buz",
) )
def test_autoescape_off(self): def test_autoescape_off(self):
self.assertEqual( self.assertEqual(
urlize('foo<a href=" google.com ">bar</a>buz', autoescape=False), 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", "bar</a>buz",
) )
@ -483,7 +487,7 @@ class FunctionTests(SimpleTestCase):
prepend_www = lazy(lambda url: "www." + url, str) prepend_www = lazy(lambda url: "www." + url, str)
self.assertEqual( self.assertEqual(
urlize(prepend_www("google.com")), 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") @mock.patch.object(Urlizer, "handle_word", return_value="test")

View File

@ -1,5 +1,6 @@
from django.template.defaultfilters import urlizetrunc from django.template.defaultfilters import urlizetrunc
from django.test import SimpleTestCase from django.test import SimpleTestCase
from django.test.utils import override_settings
from django.utils.safestring import mark_safe from django.utils.safestring import mark_safe
from ..utils import setup from ..utils import setup
@ -48,6 +49,7 @@ class UrlizetruncTests(SimpleTestCase):
) )
@override_settings(URLIZE_ASSUME_HTTPS=True)
class FunctionTests(SimpleTestCase): class FunctionTests(SimpleTestCase):
def test_truncate(self): def test_truncate(self):
uri = "http://31characteruri.com/test/" uri = "http://31characteruri.com/test/"
@ -93,13 +95,13 @@ class FunctionTests(SimpleTestCase):
def test_autoescape(self): def test_autoescape(self):
self.assertEqual( self.assertEqual(
urlizetrunc('foo<a href=" google.com ">bar</a>buz', 10), urlizetrunc('foo<a href=" google.com ">bar</a>buz', 10),
'foo&lt;a href=&quot; <a href="http://google.com" rel="nofollow">google.com' 'foo&lt;a href=&quot; <a href="https://google.com" rel="nofollow">'
"</a> &quot;&gt;bar&lt;/a&gt;buz", "google.com</a> &quot;&gt;bar&lt;/a&gt;buz",
) )
def test_autoescape_off(self): def test_autoescape_off(self):
self.assertEqual( self.assertEqual(
urlizetrunc('foo<a href=" google.com ">bar</a>buz', 9, autoescape=False), 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", "bar</a>buz",
) )

View File

@ -4,6 +4,8 @@ from datetime import datetime
from django.core.exceptions import SuspiciousOperation from django.core.exceptions import SuspiciousOperation
from django.core.serializers.json import DjangoJSONEncoder from django.core.serializers.json import DjangoJSONEncoder
from django.test import SimpleTestCase 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.functional import lazystr
from django.utils.html import ( from django.utils.html import (
conditional_escape, conditional_escape,
@ -22,6 +24,7 @@ from django.utils.html import (
from django.utils.safestring import mark_safe from django.utils.safestring import mark_safe
@override_settings(URLIZE_ASSUME_HTTPS=True)
class TestUtilsHtml(SimpleTestCase): class TestUtilsHtml(SimpleTestCase):
def check_output(self, function, value, output=None): def check_output(self, function, value, output=None):
""" """
@ -369,17 +372,17 @@ class TestUtilsHtml(SimpleTestCase):
tests = ( tests = (
( (
"Search for google.com/?q=! and see.", "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.", "see.",
), ),
( (
"Search for google.com/?q=1&lt! and see.", "Search for google.com/?q=1&lt! and see.",
'Search for <a href="http://google.com/?q=1%3C">google.com/?q=1&lt' 'Search for <a href="https://google.com/?q=1%3C">google.com/?q=1&lt'
"</a>! and see.", "</a>! and see.",
), ),
( (
lazystr("Search for google.com/?q=!"), 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/", "http://www.foo.bar/",
@ -388,7 +391,7 @@ class TestUtilsHtml(SimpleTestCase):
( (
"Look on www.نامه‌ای.com.", "Look on www.نامه‌ای.com.",
"Look on <a " "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>.", ">www.نامه‌ای.com</a>.",
), ),
("foo@example.com", '<a href="mailto:foo@example.com">foo@example.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): with self.subTest(value=value):
self.assertEqual(urlize(value), output) 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): def test_urlize_unchanged_inputs(self):
tests = ( tests = (
("a" + "@a" * 50000) + "a", # simple_email_re catastrophic test ("a" + "@a" * 50000) + "a", # simple_email_re catastrophic test