mirror of
https://github.com/django/django.git
synced 2026-02-09 02:49:25 +08:00
[6.0.x] Fixed #36733 -- Escaped attributes in Stylesheet.__str__().
Thanks Mustafa Barakat for the report, Baptiste Mispelon for
the triage, and Jake Howard for the review.
Backport of e05f2a7569 from main.
This commit is contained in:
@@ -28,6 +28,7 @@ import mimetypes
|
||||
from io import StringIO
|
||||
from urllib.parse import urlparse
|
||||
|
||||
from django.forms.utils import flatatt
|
||||
from django.utils.encoding import iri_to_uri
|
||||
from django.utils.xmlutils import SimplerXMLGenerator
|
||||
|
||||
@@ -95,12 +96,12 @@ class Stylesheet:
|
||||
return self._mimetype
|
||||
|
||||
def __str__(self):
|
||||
data = [f'href="{self.url}"']
|
||||
if self.mimetype is not None:
|
||||
data.append(f'type="{self.mimetype}"')
|
||||
if self.media is not None:
|
||||
data.append(f'media="{self.media}"')
|
||||
return " ".join(data)
|
||||
attrs = {
|
||||
"href": iri_to_uri(self._url),
|
||||
"type": self.mimetype,
|
||||
"media": self.media,
|
||||
}
|
||||
return flatatt(attrs).strip()
|
||||
|
||||
def __repr__(self):
|
||||
return repr((self.url, self.mimetype, self.media))
|
||||
|
||||
@@ -9,4 +9,7 @@ Django 5.2.9 fixes several bugs in 5.2.8.
|
||||
Bugfixes
|
||||
========
|
||||
|
||||
* ...
|
||||
* Fixed a bug in Django 5.2 where
|
||||
``django.utils.feedgenerator.Stylesheet.__str__()`` did not escape
|
||||
the ``url``, ``mimetype``, and ``media`` attributes, potentially leading
|
||||
to invalid XML markup (:ticket:`36733`).
|
||||
|
||||
@@ -578,51 +578,51 @@ class SyndicationFeedTest(FeedTestCase):
|
||||
def test_stylesheets(self):
|
||||
testdata = [
|
||||
# Plain strings.
|
||||
("/test.xsl", 'href="/test.xsl" type="text/xsl" media="screen"'),
|
||||
("/test.xslt", 'href="/test.xslt" type="text/xsl" media="screen"'),
|
||||
("/test.css", 'href="/test.css" type="text/css" media="screen"'),
|
||||
("/test.xsl", 'href="/test.xsl" media="screen" type="text/xsl"'),
|
||||
("/test.xslt", 'href="/test.xslt" media="screen" type="text/xsl"'),
|
||||
("/test.css", 'href="/test.css" media="screen" type="text/css"'),
|
||||
("/test", 'href="/test" media="screen"'),
|
||||
(
|
||||
"https://example.com/test.xsl",
|
||||
'href="https://example.com/test.xsl" type="text/xsl" media="screen"',
|
||||
'href="https://example.com/test.xsl" media="screen" type="text/xsl"',
|
||||
),
|
||||
(
|
||||
"https://example.com/test.css",
|
||||
'href="https://example.com/test.css" type="text/css" media="screen"',
|
||||
'href="https://example.com/test.css" media="screen" type="text/css"',
|
||||
),
|
||||
(
|
||||
"https://example.com/test",
|
||||
'href="https://example.com/test" media="screen"',
|
||||
),
|
||||
("/♥.xsl", 'href="/%E2%99%A5.xsl" type="text/xsl" media="screen"'),
|
||||
("/♥.xsl", 'href="/%E2%99%A5.xsl" media="screen" type="text/xsl"'),
|
||||
(
|
||||
static("stylesheet.xsl"),
|
||||
'href="/static/stylesheet.xsl" type="text/xsl" media="screen"',
|
||||
'href="/static/stylesheet.xsl" media="screen" type="text/xsl"',
|
||||
),
|
||||
(
|
||||
static("stylesheet.css"),
|
||||
'href="/static/stylesheet.css" type="text/css" media="screen"',
|
||||
'href="/static/stylesheet.css" media="screen" type="text/css"',
|
||||
),
|
||||
(static("stylesheet"), 'href="/static/stylesheet" media="screen"'),
|
||||
(
|
||||
reverse("syndication-xsl-stylesheet"),
|
||||
'href="/syndication/stylesheet.xsl" type="text/xsl" media="screen"',
|
||||
'href="/syndication/stylesheet.xsl" media="screen" type="text/xsl"',
|
||||
),
|
||||
(
|
||||
reverse_lazy("syndication-xsl-stylesheet"),
|
||||
'href="/syndication/stylesheet.xsl" type="text/xsl" media="screen"',
|
||||
'href="/syndication/stylesheet.xsl" media="screen" type="text/xsl"',
|
||||
),
|
||||
# Stylesheet objects.
|
||||
(
|
||||
Stylesheet("/test.xsl"),
|
||||
'href="/test.xsl" type="text/xsl" media="screen"',
|
||||
'href="/test.xsl" media="screen" type="text/xsl"',
|
||||
),
|
||||
(Stylesheet("/test.xsl", mimetype=None), 'href="/test.xsl" media="screen"'),
|
||||
(Stylesheet("/test.xsl", media=None), 'href="/test.xsl" type="text/xsl"'),
|
||||
(Stylesheet("/test.xsl", mimetype=None, media=None), 'href="/test.xsl"'),
|
||||
(
|
||||
Stylesheet("/test.xsl", mimetype="text/xml"),
|
||||
'href="/test.xsl" type="text/xml" media="screen"',
|
||||
'href="/test.xsl" media="screen" type="text/xml"',
|
||||
),
|
||||
]
|
||||
for stylesheet, expected in testdata:
|
||||
@@ -642,12 +642,12 @@ class SyndicationFeedTest(FeedTestCase):
|
||||
self.assertEqual(doc.childNodes[0].nodeName, "xml-stylesheet")
|
||||
self.assertEqual(
|
||||
doc.childNodes[0].data,
|
||||
'href="/stylesheet1.xsl" type="text/xsl" media="screen"',
|
||||
'href="/stylesheet1.xsl" media="screen" type="text/xsl"',
|
||||
)
|
||||
self.assertEqual(doc.childNodes[1].nodeName, "xml-stylesheet")
|
||||
self.assertEqual(
|
||||
doc.childNodes[1].data,
|
||||
'href="/stylesheet2.xsl" type="text/xsl" media="screen"',
|
||||
'href="/stylesheet2.xsl" media="screen" type="text/xsl"',
|
||||
)
|
||||
|
||||
def test_stylesheets_typeerror_if_str_or_stylesheet(self):
|
||||
|
||||
@@ -156,6 +156,20 @@ class FeedgeneratorTests(SimpleTestCase):
|
||||
stylesheet = feedgenerator.Stylesheet(SimpleLazyObject(m))
|
||||
m.assert_not_called()
|
||||
self.assertEqual(
|
||||
str(stylesheet), 'href="test.css" type="text/css" media="screen"'
|
||||
str(stylesheet), 'href="test.css" media="screen" type="text/css"'
|
||||
)
|
||||
m.assert_called_once()
|
||||
|
||||
def test_stylesheet_attribute_escaping(self):
|
||||
style = feedgenerator.Stylesheet(
|
||||
url='http://example.com/style.css?foo="bar"&baz=<>',
|
||||
mimetype='text/css; charset="utf-8"',
|
||||
media='screen and (max-width: "600px")',
|
||||
)
|
||||
|
||||
self.assertEqual(
|
||||
str(style),
|
||||
'href="http://example.com/style.css?foo=%22bar%22&baz=%3C%3E" '
|
||||
'media="screen and (max-width: "600px")" '
|
||||
'type="text/css; charset="utf-8""',
|
||||
)
|
||||
|
||||
Reference in New Issue
Block a user