From 96db015e77be8a75459111684eda1fdd484ad181 Mon Sep 17 00:00:00 2001 From: Don Yin Date: Mon, 26 Oct 2026 14:20:27 +0000 Subject: [PATCH 1/3] URL-encode link-patterns destinations Fixes #55 Signed-off-by: Don Yin --- lib/markdown2.py | 3 ++- test/test_markdown2.py | 8 ++++++++ 2 files changed, 10 insertions(+), 1 deletion(-) diff --git a/lib/markdown2.py b/lib/markdown2.py index a55f7098..76303fb3 100755 --- a/lib/markdown2.py +++ b/lib/markdown2.py @@ -131,6 +131,7 @@ from collections.abc import Collection from enum import IntEnum, auto from os import urandom +from urllib.parse import quote # ---- type defs _safe_mode = Literal['replace', 'escape'] @@ -3888,7 +3889,7 @@ def run(self, text: str): continue escaped_href = ( - href.replace('"', '"') # b/c of attr quote + quote(href, safe=":/?#[]@!$&'()*+,;=%") # To avoid markdown and : .replace('*', self.md._escape_table['*']) .replace('_', self.md._escape_table['_'])) diff --git a/test/test_markdown2.py b/test/test_markdown2.py index f4d105ac..c908c6f5 100755 --- a/test/test_markdown2.py +++ b/test/test_markdown2.py @@ -220,6 +220,14 @@ class DirectTestCase(_MarkdownTestCase): Python-markdown (markdown.py). """ + def test_link_pattern_url_encoding(self): + pattern = re.compile(r"^(.*)$") + html = markdown2.markdown( + "foo bar", extras=["link-patterns"], + link_patterns=[(pattern, r"lorem \1 ipsum")]) + self.assertEqual( + html, '

foo bar

\n') + def test_header_ids_from_file_vars(self): md = markdown2.Markdown(use_file_vars=True) modeline = "\n" From 3c0a6f40795f8b1f499b69e393fe233ae5c64df4 Mon Sep 17 00:00:00 2001 From: Don Yin Date: Mon, 26 Oct 2026 14:21:39 +0000 Subject: [PATCH 2/3] Add the change note Signed-off-by: Don Yin --- CHANGES.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGES.md b/CHANGES.md index 90f815ec..5a6fdba0 100644 --- a/CHANGES.md +++ b/CHANGES.md @@ -2,6 +2,7 @@ ## python-markdown2 2.5.6 (not yet released) +- [pull #749] URL-encode destinations generated by the `link-patterns` extra (#55) - [pull #739] Fix `header-ids` extra putting sanitized HTML into header ids in safe mode, which allowed attribute injection (#649) - [pull #732] Fix excessive CPU use in the inline HTML tokenizer on repeated unclosed tag fragments (#707) - [pull #736] Clarify how to enable file variables in the Python API and command-line help (#269, #365). From ab8351b2030f19a548b37393f809f4822b56a83b Mon Sep 17 00:00:00 2001 From: Don Yin Date: Tue, 27 Oct 2026 09:58:25 +0000 Subject: [PATCH 3/3] Move the link-patterns encoding test to tm-cases Signed-off-by: Don Yin --- test/test_markdown2.py | 8 -------- test/tm-cases/link_patterns_url_encoding.html | 1 + test/tm-cases/link_patterns_url_encoding.opts | 5 +++++ test/tm-cases/link_patterns_url_encoding.text | 1 + 4 files changed, 7 insertions(+), 8 deletions(-) create mode 100644 test/tm-cases/link_patterns_url_encoding.html create mode 100644 test/tm-cases/link_patterns_url_encoding.opts create mode 100644 test/tm-cases/link_patterns_url_encoding.text diff --git a/test/test_markdown2.py b/test/test_markdown2.py index c908c6f5..f4d105ac 100755 --- a/test/test_markdown2.py +++ b/test/test_markdown2.py @@ -220,14 +220,6 @@ class DirectTestCase(_MarkdownTestCase): Python-markdown (markdown.py). """ - def test_link_pattern_url_encoding(self): - pattern = re.compile(r"^(.*)$") - html = markdown2.markdown( - "foo bar", extras=["link-patterns"], - link_patterns=[(pattern, r"lorem \1 ipsum")]) - self.assertEqual( - html, '

foo bar

\n') - def test_header_ids_from_file_vars(self): md = markdown2.Markdown(use_file_vars=True) modeline = "\n" diff --git a/test/tm-cases/link_patterns_url_encoding.html b/test/tm-cases/link_patterns_url_encoding.html new file mode 100644 index 00000000..e571a7b4 --- /dev/null +++ b/test/tm-cases/link_patterns_url_encoding.html @@ -0,0 +1 @@ +

foo bar

diff --git a/test/tm-cases/link_patterns_url_encoding.opts b/test/tm-cases/link_patterns_url_encoding.opts new file mode 100644 index 00000000..f95094df --- /dev/null +++ b/test/tm-cases/link_patterns_url_encoding.opts @@ -0,0 +1,5 @@ +{"extras": ["link-patterns"], + "link_patterns": [ + (re.compile(r"^(.*)$"), r"lorem \1 ipsum"), + ], +} diff --git a/test/tm-cases/link_patterns_url_encoding.text b/test/tm-cases/link_patterns_url_encoding.text new file mode 100644 index 00000000..d675fa44 --- /dev/null +++ b/test/tm-cases/link_patterns_url_encoding.text @@ -0,0 +1 @@ +foo bar