Repository navigation
Conversation
MkDocs pre-escapes content, then Jinja's |e filter escapes again, producing &, <, >. Use html.unescape() in Python before template rendering so |e performs a single correct escape. - Add html_module.unescape() for title and description in plugin.py - Add test fixture with special characters - Add test verifying no double-encoded entities
|
Codecov Report✅ All modified and coverable lines are covered by tests. Additional details and impacted files@@ Coverage Diff @@
## main #456 +/- ##
==========================================
+ Coverage 83.16% 83.18% +0.02%
==========================================
Files 11 11
Lines 784 785 +1
Branches 133 133
==========================================
+ Hits 652 653 +1
Misses 86 86
Partials 46 46
Flags with carried forward coverage won't be shown. Click here to find out more.
🚀 New features to boost your workflow:
|
Guts
left a comment
There was a problem hiding this comment.
Thanks for this one.
The description part, however, introduces a regression, and the test doesn't exercise the bug:
-
descriptionis HTML, not text :get_description_or_abstract()returnspage.contentormarkdown.markdown(...)output in almost every branch, and the JSON Feed publishes it ascontent_html. In RSS,<description>carries that HTML escaped once for XML, so&lt;in the raw XML is the correct encoding of a<in the HTML. Unescaping it first turns code samples into real markup. WithUse `<script>` and `a < b` in code.:main: readers get<p>Use <code><script></code> and <code>a < b</code> in code.</p>- this PR: readers get
<p>Use <code><script></code> and <code>a < b</code> in code.</p>
For a docs plugin, where inline code is everywhere, that's a blocker. Please keep the unescape on
titleonly (see inline suggestions). -
fixture doesn't reproduce the bug because its title is set in the front-matter, which MkDocs returns verbatim; only H1-derived titles carry entities. Same for the
descriptionmeta, which|ealready escapes once. The new test passes onmainwithout the fix. I've suggested a fixture with an H1 title instead.
Please also rebase on main.
There was a problem hiding this comment.
This module can be removed: it duplicates a full build already done in test_build.py, and assertNotIn("&lt;") rejects the valid encoding of HTML descriptions. A single assertion in test_xml_escaping_in_author covers the title fix.
| guid=page.canonical_url, | ||
| link=page_url_full, | ||
| title=page.title, | ||
| title=html_module.unescape(page.title) if page.title else None, |
There was a problem hiding this comment.
Short comment to reùember why only the title gets this treatment:
| title=html_module.unescape(page.title) if page.title else None, | |
| # MkDocs keeps HTML entities in titles extracted from the H1 | |
| title=html_module.unescape(page.title) if page.title else None, |
| in_page=page, | ||
| chars_count=self.config.abstract_chars_count, | ||
| abstract_delimiter=self.config.abstract_delimiter, | ||
| description=html_module.unescape( |
There was a problem hiding this comment.
description is HTML (page.content / markdown.markdown() output, published as content_html in the JSON Feed): it must stay escaped once, so no unescape here.



Description
Resolve double-encoded HTML entities (e.g.
&amp;,&lt;,&gt;) in RSS feed title and description fields.MkDocs pre-escapes content, and then Jinja's
|efilter escapes again, producing double-encoded entities. Usinghtml.unescape()in Python before template rendering ensures|eperforms a single correct escape.Changes
html_module.unescape()for title and description inplugin.py& < >)Split from: #451