Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
20 changes: 20 additions & 0 deletions Lib/test/test_sax.py
Original file line number Diff line number Diff line change
Expand Up @@ -1039,6 +1039,26 @@ def test_expat_entityresolver_enabled(self):
self.assertEqual(result.getvalue(), start +
b"<doc><entity></entity></doc>")

def test_expat_entityresolver_not_well_formed(self):
# gh-156796: the parser of an external entity was never finalized,
# so errors only detectable at the end of its input, such as an
# unclosed element, were silently ignored.
class NotWellFormedEntityResolver:
def resolveEntity(self, publicId, systemId):
inpsrc = InputSource()
inpsrc.setByteStream(BytesIO(b"<entity>"))
return inpsrc

parser = create_parser()
parser.setFeature(feature_external_ges, True)
parser.setEntityResolver(NotWellFormedEntityResolver())
parser.setContentHandler(XMLGenerator(BytesIO()))

with self.assertRaises(SAXParseException):
parser.feed('<!DOCTYPE doc [<!ENTITY test SYSTEM "whatever">]>'
'<doc>&test;</doc>')
parser.close()

def test_expat_entityresolver_default(self):
parser = create_parser()
self.assertEqual(parser.getFeature(feature_external_ges), False)
Expand Down
11 changes: 8 additions & 3 deletions Lib/xml/sax/expatreader.py
Original file line number Diff line number Diff line change
Expand Up @@ -238,9 +238,14 @@ def _close_source(self):
file.close()

def close(self):
if (self._entity_stack or self._parser is None or
isinstance(self._parser, _ClosedParser)):
# If we are completing an external entity, do nothing here
if self._parser is None or isinstance(self._parser, _ClosedParser):
return
if self._entity_stack:
# We are completing an external entity. Finalize its parser so
# that errors which are only detectable at the end of the input,
# such as an unclosed element, are reported, but do not end the
# document: the enclosing parse is still in progress.
self.feed(b"", isFinal=True)
return
try:
self.feed(b"", isFinal=True)
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
Fix :mod:`xml.sax` not reporting an external entity whose content is not
well-formed. The parser created for the entity was never finalized, so errors
which are only detectable at the end of its input, such as an unclosed
element, were silently ignored.
Comment on lines +1 to +4

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Perhaps the second sentence could be ommited, since it's an implementation detail?

Suggested change
Fix :mod:`xml.sax` not reporting an external entity whose content is not
well-formed. The parser created for the entity was never finalized, so errors
which are only detectable at the end of its input, such as an unclosed
element, were silently ignored.
Fix :mod:`xml.sax` silently accepting an external entity whose content is not
well-formed.

Loading