|
13 | 13 | from xml.sax.saxutils import XMLGenerator, escape, unescape, quoteattr, \ |
14 | 14 | XMLFilterBase, prepare_input_source |
15 | 15 | from xml.sax.expatreader import create_parser |
16 | | -from xml.sax.handler import feature_namespaces |
| 16 | +from xml.sax.handler import feature_namespaces, feature_external_ges |
17 | 17 | from xml.sax.xmlreader import InputSource, AttributesImpl, AttributesNSImpl |
18 | 18 | from io import BytesIO, StringIO |
19 | 19 | import codecs |
20 | 20 | import gc |
21 | 21 | import os.path |
22 | 22 | import shutil |
| 23 | +from urllib.error import URLError |
23 | 24 | from test import support |
24 | 25 | from test.support import findfile, run_unittest, TESTFN |
25 | 26 |
|
@@ -911,6 +912,18 @@ def notationDecl(self, name, publicId, systemId): |
911 | 912 | def unparsedEntityDecl(self, name, publicId, systemId, ndata): |
912 | 913 | self._entities.append((name, publicId, systemId, ndata)) |
913 | 914 |
|
| 915 | + |
| 916 | + class TestEntityRecorder: |
| 917 | + def __init__(self): |
| 918 | + self.entities = [] |
| 919 | + |
| 920 | + def resolveEntity(self, publicId, systemId): |
| 921 | + self.entities.append((publicId, systemId)) |
| 922 | + source = InputSource() |
| 923 | + source.setPublicId(publicId) |
| 924 | + source.setSystemId(systemId) |
| 925 | + return source |
| 926 | + |
914 | 927 | def test_expat_dtdhandler(self): |
915 | 928 | parser = create_parser() |
916 | 929 | handler = self.TestDTDHandler() |
@@ -927,6 +940,32 @@ def test_expat_dtdhandler(self): |
927 | 940 | [("GIF", "-//CompuServe//NOTATION Graphics Interchange Format 89a//EN", None)]) |
928 | 941 | self.assertEqual(handler._entities, [("img", None, "expat.gif", "GIF")]) |
929 | 942 |
|
| 943 | + def test_expat_external_dtd_enabled(self): |
| 944 | + parser = create_parser() |
| 945 | + parser.setFeature(feature_external_ges, True) |
| 946 | + resolver = self.TestEntityRecorder() |
| 947 | + parser.setEntityResolver(resolver) |
| 948 | + |
| 949 | + with self.assertRaises(URLError): |
| 950 | + parser.feed( |
| 951 | + '<!DOCTYPE external SYSTEM "unsupported://non-existing">\n' |
| 952 | + ) |
| 953 | + self.assertEqual( |
| 954 | + resolver.entities, [(None, 'unsupported://non-existing')] |
| 955 | + ) |
| 956 | + |
| 957 | + def test_expat_external_dtd_default(self): |
| 958 | + parser = create_parser() |
| 959 | + resolver = self.TestEntityRecorder() |
| 960 | + parser.setEntityResolver(resolver) |
| 961 | + |
| 962 | + parser.feed( |
| 963 | + '<!DOCTYPE external SYSTEM "unsupported://non-existing">\n' |
| 964 | + ) |
| 965 | + parser.feed('<doc />') |
| 966 | + parser.close() |
| 967 | + self.assertEqual(resolver.entities, []) |
| 968 | + |
930 | 969 | # ===== EntityResolver support |
931 | 970 |
|
932 | 971 | class TestEntityResolver: |
@@ -936,8 +975,9 @@ def resolveEntity(self, publicId, systemId): |
936 | 975 | inpsrc.setByteStream(BytesIO(b"<entity/>")) |
937 | 976 | return inpsrc |
938 | 977 |
|
939 | | - def test_expat_entityresolver(self): |
| 978 | + def test_expat_entityresolver_enabled(self): |
940 | 979 | parser = create_parser() |
| 980 | + parser.setFeature(feature_external_ges, True) |
941 | 981 | parser.setEntityResolver(self.TestEntityResolver()) |
942 | 982 | result = BytesIO() |
943 | 983 | parser.setContentHandler(XMLGenerator(result)) |
@@ -951,6 +991,22 @@ def test_expat_entityresolver(self): |
951 | 991 | self.assertEqual(result.getvalue(), start + |
952 | 992 | b"<doc><entity></entity></doc>") |
953 | 993 |
|
| 994 | + def test_expat_entityresolver_default(self): |
| 995 | + parser = create_parser() |
| 996 | + self.assertEqual(parser.getFeature(feature_external_ges), False) |
| 997 | + parser.setEntityResolver(self.TestEntityResolver()) |
| 998 | + result = BytesIO() |
| 999 | + parser.setContentHandler(XMLGenerator(result)) |
| 1000 | + |
| 1001 | + parser.feed('<!DOCTYPE doc [\n') |
| 1002 | + parser.feed(' <!ENTITY test SYSTEM "whatever">\n') |
| 1003 | + parser.feed(']>\n') |
| 1004 | + parser.feed('<doc>&test;</doc>') |
| 1005 | + parser.close() |
| 1006 | + |
| 1007 | + self.assertEqual(result.getvalue(), start + |
| 1008 | + b"<doc></doc>") |
| 1009 | + |
954 | 1010 | # ===== Attributes support |
955 | 1011 |
|
956 | 1012 | class AttrGatherer(ContentHandler): |
|