diff --git a/sphinxext/opengraph/_description_parser.py b/sphinxext/opengraph/_description_parser.py index 7ca9129..e3516fd 100644 --- a/sphinxext/opengraph/_description_parser.py +++ b/sphinxext/opengraph/_description_parser.py @@ -1,5 +1,6 @@ from __future__ import annotations +import html import string from typing import TYPE_CHECKING @@ -69,6 +70,9 @@ def dispatch_visit(self, node: nodes.Element) -> None: if len(node.children) == 0: text = node.astext().replace('\r', '').replace('\n', ' ').strip() + # Ensure string contains HTML-safe characters + text = html.escape(text, quote=True) + # Remove double spaces while text.find(' ') != -1: text = text.replace(' ', ' ') diff --git a/tests/roots/test-meta-name-description-escape/conf.py b/tests/roots/test-meta-name-description-escape/conf.py new file mode 100644 index 0000000..54b7be1 --- /dev/null +++ b/tests/roots/test-meta-name-description-escape/conf.py @@ -0,0 +1,12 @@ +from __future__ import annotations + +extensions = ['sphinxext.opengraph'] + +master_doc = 'index' +exclude_patterns = ['_build'] + +html_theme = 'basic' + +ogp_site_url = 'http://example.org/en/latest/' + +enable_meta_description = True diff --git a/tests/roots/test-meta-name-description-escape/index.rst b/tests/roots/test-meta-name-description-escape/index.rst new file mode 100644 index 0000000..a6ea7bf --- /dev/null +++ b/tests/roots/test-meta-name-description-escape/index.rst @@ -0,0 +1,4 @@ +Lorem dolor sit amet, "consectetur" adipiscing elit. +Suspendisse at lorem ornare, fringilla massa nec, venenatis mi. +Donec erat sapien, tincidunt nec rhoncus nec, scelerisque id diam. +Orci varius natoque penatibus et magnis dis parturient mauris. diff --git a/tests/test_options.py b/tests/test_options.py index 5b29686..c780435 100644 --- a/tests/test_options.py +++ b/tests/test_options.py @@ -19,6 +19,11 @@ def get_tag_content(tags, tag_type, kind='property', prefix='og'): return get_tag(tags, tag_type, kind, prefix).get('content', '') +def get_tag_content_text(tags, tag_type, kind='property', prefix='og'): + # Gets the content of a specific ogp tag + return get_tag(tags, tag_type, kind, prefix).get_text('content', '') + + def get_meta_description(tags): tag = next(tag for tag in tags if tag.get('name') == 'description') return tag.get('content', '') @@ -45,6 +50,15 @@ def test_meta_name_description(meta_tags): assert description == og_description +@pytest.mark.sphinx('html', testroot='meta-name-description-escape') +def test_meta_name_description_escape(meta_tags): + og_description = get_tag_content(meta_tags, 'description') + og_description_text = get_tag_content_text(meta_tags, 'description') + + assert '<' in og_description + assert '<' not in og_description_text + + @pytest.mark.sphinx('html', testroot='meta-name-description-manual-description') def test_meta_name_manual_description(meta_tags): og_description = get_tag_content(meta_tags, 'description')