Skip to content

Commit f423704

Browse files
fix: only HTML-escape URLs when rendering to HTML
1 parent 0772c78 commit f423704

File tree

5 files changed

+44
-6
lines changed

5 files changed

+44
-6
lines changed

Diff for: src/mistune/directives/image.py

+2-2
Original file line numberDiff line numberDiff line change
@@ -64,7 +64,7 @@ def render_block_image(
6464
height: Optional[str] = None,
6565
**attrs: Any,
6666
) -> str:
67-
img = '<img src="' + src + '"'
67+
img = '<img src="' + escape_text(src) + '"'
6868
style = ''
6969
if alt:
7070
img += ' alt="' + escape_text(alt) + '"'
@@ -90,7 +90,7 @@ def render_block_image(
9090

9191
target = attrs.get('target')
9292
if target:
93-
href = escape_text(self.safe_url(target))
93+
href = self.safe_url(target)
9494
outer = '<a class="' + _cls + '" href="' + href + '">'
9595
return outer + img + '</a>\n'
9696
else:

Diff for: src/mistune/renderers/html.py

+3-3
Original file line numberDiff line numberDiff line change
@@ -53,17 +53,17 @@ def safe_url(self, url: str) -> str:
5353
links, images, and etc.
5454
"""
5555
if self._allow_harmful_protocols is True:
56-
return url
56+
return escape_text(url)
5757

5858
_url = url.lower()
5959
if self._allow_harmful_protocols and \
6060
_url.startswith(tuple(self._allow_harmful_protocols)):
61-
return url
61+
return escape_text(url)
6262

6363
if _url.startswith(self.HARMFUL_PROTOCOLS) and \
6464
not _url.startswith(self.GOOD_DATA_PROTOCOLS):
6565
return '#harmful-link'
66-
return url
66+
return escape_text(url)
6767

6868
def text(self, text: str) -> str:
6969
if self._escape:

Diff for: src/mistune/util.py

+1-1
Original file line numberDiff line numberDiff line change
@@ -36,7 +36,7 @@ def escape_url(link: str) -> str:
3636
'!$&()*+,;=' # sub-delims - "'" (rfc3986)
3737
'%' # leave already-encoded octets alone
3838
)
39-
return escape(quote(unescape(link), safe=safe))
39+
return quote(unescape(link), safe=safe)
4040

4141

4242
def safe_entity(s: str) -> str:

Diff for: tests/fixtures/fenced_image.txt

+19
Original file line numberDiff line numberDiff line change
@@ -81,3 +81,22 @@
8181
.
8282
<a class="block-image align-left" href="https://lepture.com"><img src="picture.png" alt="description" width="100" height="50" /></a>
8383
````````````````````````````````
84+
85+
## ampersand in source
86+
87+
```````````````````````````````` example
88+
~~~{image} https://example.com/picture.png?foo=qux&test=me
89+
~~~
90+
.
91+
<div class="block-image"><img src="https://example.com/picture.png?foo=qux&amp;test=me" /></div>
92+
````````````````````````````````
93+
94+
## ampersand in target
95+
96+
```````````````````````````````` example
97+
~~~{image} picture.png
98+
:target: https://example.com/rickroll?a=1&b=2
99+
~~~
100+
.
101+
<a class="block-image" href="https://example.com/rickroll?a=1&amp;b=2"><img src="picture.png" /></a>
102+
````````````````````````````````

Diff for: tests/test_misc.py

+19
Original file line numberDiff line numberDiff line change
@@ -97,6 +97,25 @@ def test_ast_output(self):
9797
]
9898
self.assertEqual(result, expected)
9999

100+
def test_ast_url(self):
101+
md = mistune.create_markdown(escape=False, renderer=None)
102+
label = 'hi &<>"'
103+
url = 'https://example.com/foo?a=1&b=2'
104+
text = '[{}]({})'.format(label, url)
105+
result = md(text)
106+
expected = [
107+
{
108+
'type': 'paragraph',
109+
'children': [
110+
{
111+
'type': 'link',
112+
'children': [{'type': 'text', 'raw': label}],
113+
'attrs': {'url': url},
114+
},
115+
],
116+
},
117+
]
118+
self.assertEqual(result, expected)
100119

101120
def test_emsp(self):
102121
md = mistune.create_markdown(escape=False, hard_wrap=True)

0 commit comments

Comments
 (0)