mirror of
https://github.com/encode/django-rest-framework.git
synced 2025-01-24 08:14:16 +03:00
Drop urlize_quoted_links (#7548)
This commit is contained in:
parent
c6e24521da
commit
ae649336b1
|
@ -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):
|
||||||
"""
|
"""
|
||||||
|
|
|
@ -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>
|
||||||
|
|
||||||
|
|
|
@ -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):
|
||||||
"""
|
"""
|
||||||
|
|
|
@ -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/", '] = \
|
||||||
'"url": "<a href="http://api/users/1/">http://api/users/1/</a>", '
|
'"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], '] = \
|
||||||
'"foo_set": [\n "<a href="http://api/foos/1/">http://api/foos/1/</a>"\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 == '<script>alert()</script>' \
|
assert rendered == '<script>alert()</script>' \
|
||||||
' <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>'
|
||||||
|
|
Loading…
Reference in New Issue
Block a user