Drop urlize_quoted_links (#7548)

This commit is contained in:
Tom Christie 2020-09-23 15:39:06 +01:00 committed by GitHub
parent c6e24521da
commit ae649336b1
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
4 changed files with 21 additions and 96 deletions

View File

@ -418,7 +418,7 @@ class BrowsableAPIRenderer(BaseRenderer):
if render_style == 'binary': if render_style == 'binary':
return '[%d bytes of binary content]' % len(content) return '[%d bytes of binary content]' % len(content)
return content return content.decode('utf-8') if isinstance(content, bytes) else content
def show_form_for_method(self, view, method, request, obj): def show_form_for_method(self, view, method, request, obj):
""" """

View File

@ -176,9 +176,9 @@
<div class="response-info" aria-label="{% trans "response info" %}"> <div class="response-info" aria-label="{% trans "response info" %}">
<pre class="prettyprint"><span class="meta nocode"><b>HTTP {{ response.status_code }} {{ response.status_text }}</b>{% for key, val in response_headers|items %} <pre class="prettyprint"><span class="meta nocode"><b>HTTP {{ response.status_code }} {{ response.status_text }}</b>{% for key, val in response_headers|items %}
<b>{{ key }}:</b> <span class="lit">{{ val|break_long_headers|urlize_quoted_links }}</span>{% endfor %} <b>{{ key }}:</b> <span class="lit">{{ val|break_long_headers|urlize }}</span>{% endfor %}
</span>{{ content|urlize_quoted_links }}</pre> </span>{{ content|urlize }}</pre>
</div> </div>
</div> </div>

View File

@ -4,9 +4,9 @@ from collections import OrderedDict
from django import template from django import template
from django.template import loader from django.template import loader
from django.urls import NoReverseMatch, reverse from django.urls import NoReverseMatch, reverse
from django.utils.encoding import force_str, iri_to_uri from django.utils.encoding import iri_to_uri
from django.utils.html import escape, format_html, smart_urlquote from django.utils.html import escape, format_html, smart_urlquote
from django.utils.safestring import SafeData, mark_safe from django.utils.safestring import mark_safe
from rest_framework.compat import apply_markdown, pygments_highlight from rest_framework.compat import apply_markdown, pygments_highlight
from rest_framework.renderers import HTMLFormRenderer from rest_framework.renderers import HTMLFormRenderer
@ -311,85 +311,6 @@ def smart_urlquote_wrapper(matched_url):
return None return None
@register.filter(needs_autoescape=True)
def urlize_quoted_links(text, trim_url_limit=None, nofollow=True, autoescape=True):
"""
Converts any URLs in text into clickable links.
Works on http://, https://, www. links, and also on links ending in one of
the original seven gTLDs (.com, .edu, .gov, .int, .mil, .net, and .org).
Links can have trailing punctuation (periods, commas, close-parens) and
leading punctuation (opening parens) and it'll still do the right thing.
If trim_url_limit is not None, the URLs in link text longer than this limit
will truncated to trim_url_limit-3 characters and appended with an ellipsis.
If nofollow is True, the URLs in link text will get a rel="nofollow"
attribute.
If autoescape is True, the link text and URLs will get autoescaped.
"""
def trim_url(x, limit=trim_url_limit):
return limit is not None and (len(x) > limit and ('%s...' % x[:max(0, limit - 3)])) or x
safe_input = isinstance(text, SafeData)
# Unfortunately, Django built-in cannot be used here, because escaping
# is to be performed on words, which have been forcibly coerced to text
def conditional_escape(text):
return escape(text) if autoescape and not safe_input else text
words = word_split_re.split(force_str(text))
for i, word in enumerate(words):
if '.' in word or '@' in word or ':' in word:
# Deal with punctuation.
lead, middle, trail = '', word, ''
for punctuation in TRAILING_PUNCTUATION:
if middle.endswith(punctuation):
middle = middle[:-len(punctuation)]
trail = punctuation + trail
for opening, closing in WRAPPING_PUNCTUATION:
if middle.startswith(opening):
middle = middle[len(opening):]
lead = lead + opening
# Keep parentheses at the end only if they're balanced.
if (
middle.endswith(closing) and
middle.count(closing) == middle.count(opening) + 1
):
middle = middle[:-len(closing)]
trail = closing + trail
# Make URL we want to point to.
url = None
nofollow_attr = ' rel="nofollow"' if nofollow else ''
if simple_url_re.match(middle):
url = smart_urlquote_wrapper(middle)
elif simple_url_2_re.match(middle):
url = smart_urlquote_wrapper('http://%s' % middle)
elif ':' not in middle and simple_email_re.match(middle):
local, domain = middle.rsplit('@', 1)
try:
domain = domain.encode('idna').decode('ascii')
except UnicodeError:
continue
url = 'mailto:%s@%s' % (local, domain)
nofollow_attr = ''
# Make link.
if url:
trimmed = trim_url(middle)
lead, trail = conditional_escape(lead), conditional_escape(trail)
url, trimmed = conditional_escape(url), conditional_escape(trimmed)
middle = '<a href="%s"%s>%s</a>' % (url, nofollow_attr, trimmed)
words[i] = '%s%s%s' % (lead, middle, trail)
else:
words[i] = conditional_escape(word)
else:
words[i] = conditional_escape(word)
return mark_safe(''.join(words))
@register.filter @register.filter
def break_long_headers(header): def break_long_headers(header):
""" """

View File

@ -2,13 +2,14 @@ import unittest
from django.template import Context, Template from django.template import Context, Template
from django.test import TestCase from django.test import TestCase
from django.utils.html import urlize
from rest_framework.compat import coreapi, coreschema from rest_framework.compat import coreapi, coreschema
from rest_framework.relations import Hyperlink from rest_framework.relations import Hyperlink
from rest_framework.templatetags import rest_framework from rest_framework.templatetags import rest_framework
from rest_framework.templatetags.rest_framework import ( from rest_framework.templatetags.rest_framework import (
add_nested_class, add_query_param, as_string, break_long_headers, add_nested_class, add_query_param, as_string, break_long_headers,
format_value, get_pagination_html, schema_links, urlize_quoted_links format_value, get_pagination_html, schema_links
) )
from rest_framework.test import APIRequestFactory from rest_framework.test import APIRequestFactory
@ -246,7 +247,7 @@ class Issue1386Tests(TestCase):
def test_issue_1386(self): def test_issue_1386(self):
""" """
Test function urlize_quoted_links with different args Test function urlize with different args
""" """
correct_urls = [ correct_urls = [
"asdf.com", "asdf.com",
@ -255,7 +256,7 @@ class Issue1386Tests(TestCase):
"as.d8f.ghj8.gov", "as.d8f.ghj8.gov",
] ]
for i in correct_urls: for i in correct_urls:
res = urlize_quoted_links(i) res = urlize(i)
self.assertNotEqual(res, i) self.assertNotEqual(res, i)
self.assertIn(i, res) self.assertIn(i, res)
@ -264,11 +265,11 @@ class Issue1386Tests(TestCase):
"asdf.netnet", "asdf.netnet",
] ]
for i in incorrect_urls: for i in incorrect_urls:
res = urlize_quoted_links(i) res = urlize(i)
self.assertEqual(i, res) self.assertEqual(i, res)
# example from issue #1386, this shouldn't raise an exception # example from issue #1386, this shouldn't raise an exception
urlize_quoted_links("asdf:[/p]zxcv.com") urlize("asdf:[/p]zxcv.com")
def test_smart_urlquote_wrapper_handles_value_error(self): def test_smart_urlquote_wrapper_handles_value_error(self):
def mock_smart_urlquote(url): def mock_smart_urlquote(url):
@ -289,7 +290,10 @@ class URLizerTests(TestCase):
For all items in dict test assert that the value is urlized key For all items in dict test assert that the value is urlized key
""" """
for original, urlized in data.items(): for original, urlized in data.items():
assert urlize_quoted_links(original, nofollow=False) == urlized print('====')
print(repr(urlize(original, nofollow=False)))
print(repr(urlized))
assert urlize(original, nofollow=False) == urlized
def test_json_with_url(self): def test_json_with_url(self):
""" """
@ -297,26 +301,26 @@ class URLizerTests(TestCase):
""" """
data = {} data = {}
data['"url": "http://api/users/1/", '] = \ data['"url": "http://api/users/1/", '] = \
'&quot;url&quot;: &quot;<a href="http://api/users/1/">http://api/users/1/</a>&quot;, ' '"url": "<a href="http://api/users/1/">http://api/users/1/</a>", '
data['"foo_set": [\n "http://api/foos/1/"\n], '] = \ data['"foo_set": [\n "http://api/foos/1/"\n], '] = \
'&quot;foo_set&quot;: [\n &quot;<a href="http://api/foos/1/">http://api/foos/1/</a>&quot;\n], ' '"foo_set": [\n "<a href="http://api/foos/1/">http://api/foos/1/</a>"\n], '
self._urlize_dict_check(data) self._urlize_dict_check(data)
def test_template_render_with_autoescape(self): def test_template_render_with_autoescape(self):
""" """
Test that HTML is correctly escaped in Browsable API views. Test that HTML is correctly escaped in Browsable API views.
""" """
template = Template("{% load rest_framework %}{{ content|urlize_quoted_links }}") template = Template("{% load rest_framework %}{{ content|urlize }}")
rendered = template.render(Context({'content': '<script>alert()</script> http://example.com'})) rendered = template.render(Context({'content': '<script>alert()</script> http://example.com'}))
assert rendered == '&lt;script&gt;alert()&lt;/script&gt;' \ assert rendered == '&lt;script&gt;alert()&lt;/script&gt;' \
' <a href="http://example.com" rel="nofollow">http://example.com</a>' ' <a href="http://example.com" rel="nofollow">http://example.com</a>'
def test_template_render_with_noautoescape(self): def test_template_render_with_noautoescape(self):
""" """
Test if the autoescape value is getting passed to urlize_quoted_links filter. Test if the autoescape value is getting passed to urlize filter.
""" """
template = Template("{% load rest_framework %}" template = Template("{% load rest_framework %}"
"{% autoescape off %}{{ content|urlize_quoted_links }}" "{% autoescape off %}{{ content|urlize }}"
"{% endautoescape %}") "{% endautoescape %}")
rendered = template.render(Context({'content': '<b> "http://example.com" </b>'})) rendered = template.render(Context({'content': '<b> "http://example.com" </b>'}))
assert rendered == '<b> "<a href="http://example.com" rel="nofollow">http://example.com</a>" </b>' assert rendered == '<b> "<a href="http://example.com" rel="nofollow">http://example.com</a>" </b>'