diff --git a/django/utils/html.py b/django/utils/html.py index d914234d60..25605bea04 100644 --- a/django/utils/html.py +++ b/django/utils/html.py @@ -150,13 +150,17 @@ fix_ampersands = allow_lazy(fix_ampersands, six.text_type) def smart_urlquote(url): "Quotes a URL if it isn't already quoted." # Handle IDN before quoting. - scheme, netloc, path, query, fragment = urlsplit(url) try: - netloc = netloc.encode('idna').decode('ascii') # IDN -> ACE - except UnicodeError: # invalid domain part + scheme, netloc, path, query, fragment = urlsplit(url) + try: + netloc = netloc.encode('idna').decode('ascii') # IDN -> ACE + except UnicodeError: # invalid domain part + pass + else: + url = urlunsplit((scheme, netloc, path, query, fragment)) + except ValueError: + # invalid IPv6 URL (normally square brackets in hostname part). pass - else: - url = urlunsplit((scheme, netloc, path, query, fragment)) # An URL is considered unquoted if it contains no % characters or # contains a % not followed by two hexadecimal digits. See #9655. diff --git a/tests/regressiontests/defaultfilters/tests.py b/tests/regressiontests/defaultfilters/tests.py index 52268da2ec..8596f8c801 100644 --- a/tests/regressiontests/defaultfilters/tests.py +++ b/tests/regressiontests/defaultfilters/tests.py @@ -310,6 +310,10 @@ class DefaultFiltersTests(TestCase): self.assertEqual(urlize('[see www.example.com]'), '[see www.example.com]' ) + # Check urlize doesn't crash when square bracket is prepended to url (#19070) + self.assertEqual(urlize('see test[at[example.com'), + 'see test[at[example.com' ) + def test_wordcount(self): self.assertEqual(wordcount(''), 0)