diff --git a/django/utils/html.py b/django/utils/html.py
index 2687eb5..4f74a74 100644
a
|
b
|
TRAILING_PUNCTUATION = ['.', ',', ')', '>', '\n', '>']
|
17 | 17 | DOTS = [u'·', u'*', u'\u2022', u'•', u'•', u'•'] |
18 | 18 | |
19 | 19 | unencoded_ampersands_re = re.compile(r'&(?!(\w+|#\d+);)') |
| 20 | unquoted_percents_re = re.compile(r'%(?![0-9A-Fa-f]{2})') |
20 | 21 | word_split_re = re.compile(r'(\s+)') |
21 | 22 | punctuation_re = re.compile('^(?P<lead>(?:%s)*)(?P<middle>.*?)(?P<trail>(?:%s)*)$' % \ |
22 | 23 | ('|'.join([re.escape(x) for x in LEADING_PUNCTUATION]), |
… |
… |
def fix_ampersands(value):
|
100 | 101 | return unencoded_ampersands_re.sub('&', force_unicode(value)) |
101 | 102 | fix_ampersands = allow_lazy(fix_ampersands, unicode) |
102 | 103 | |
| 104 | def smart_urlquote(url): |
| 105 | """Quotes an URL if it isn't already quoted.""" |
| 106 | # An URL is considered unquoted if it contains no % character, or if it |
| 107 | # contains a % not followed by two hexadecimal digits. See #9655. |
| 108 | if '%' not in url or unquoted_percents_re.search(url): |
| 109 | # See http://bugs.python.org/issue2637 |
| 110 | return urlquote(url, safe='!*\'();:@&=+$,/?#[]~') |
| 111 | return url |
| 112 | |
103 | 113 | def urlize(text, trim_url_limit=None, nofollow=False, autoescape=False): |
104 | 114 | """ |
105 | 115 | Converts any URLs in text into clickable links. |
… |
… |
def urlize(text, trim_url_limit=None, nofollow=False, autoescape=False):
|
130 | 140 | # Make URL we want to point to. |
131 | 141 | url = None |
132 | 142 | if middle.startswith('http://') or middle.startswith('https://'): |
133 | | url = urlquote(middle, safe='/&=:;#?+*') |
| 143 | url = smart_urlquote(middle) |
134 | 144 | elif middle.startswith('www.') or ('@' not in middle and \ |
135 | 145 | middle and middle[0] in string.ascii_letters + string.digits and \ |
136 | 146 | (middle.endswith('.org') or middle.endswith('.net') or middle.endswith('.com'))): |
137 | | url = urlquote('http://%s' % middle, safe='/&=:;#?+*') |
| 147 | url = smart_urlquote('http://%s' % middle) |
138 | 148 | elif '@' in middle and not ':' in middle and simple_email_re.match(middle): |
139 | 149 | url = 'mailto:%s' % middle |
140 | 150 | nofollow_attr = '' |
diff --git a/tests/regressiontests/defaultfilters/tests.py b/tests/regressiontests/defaultfilters/tests.py
index 5e8c8f1..b27b1df 100644
a
|
b
|
class DefaultFiltersTests(TestCase):
|
238 | 238 | # Check urlize with https addresses |
239 | 239 | self.assertEqual(urlize('https://google.com'), |
240 | 240 | u'<a href="https://google.com" rel="nofollow">https://google.com</a>') |
| 241 | # Check urlize doesn't overquote already quoted urls |
| 242 | self.assertEqual(urlize('http://hi.baidu.com/%D6%D8%D0%C2%BF'), |
| 243 | u'<a href="http://hi.baidu.com/%D6%D8%D0%C2%BF" rel="nofollow">' |
| 244 | u'http://hi.baidu.com/%D6%D8%D0%C2%BF</a>') |
| 245 | self.assertEqual(urlize('www.mystore.com/30%OffCoupons!'), |
| 246 | u'<a href="http://www.mystore.com/30%25OffCoupons!" rel="nofollow">' |
| 247 | u'www.mystore.com/30%OffCoupons!</a>') |
241 | 248 | |
242 | 249 | def test_wordcount(self): |
243 | 250 | self.assertEqual(wordcount(''), 0) |