diff --git a/nova/tests/test_utils.py b/nova/tests/test_utils.py
index 940ddf6ec489..2c2c58db9e5d 100644
--- a/nova/tests/test_utils.py
+++ b/nova/tests/test_utils.py
@@ -23,6 +23,7 @@ import os
import os.path
import StringIO
import tempfile
+from xml.dom import minidom
import mox
import netaddr
@@ -1059,3 +1060,47 @@ class StringLengthTestCase(test.TestCase):
self.assertRaises(exception.InvalidInput,
utils.check_string_length,
'a' * 256, 'name', max_length=255)
+
+
+class SafeParserTestCase(test.TestCase):
+ def test_external_dtd(self):
+ xml_string = ("""
+
+
+
html with dtd
+ """)
+
+ parser = utils.ProtectedExpatParser(forbid_dtd=False,
+ forbid_entities=True)
+ self.assertRaises(ValueError,
+ minidom.parseString,
+ xml_string, parser)
+
+ def test_external_file(self):
+ xml_string = """
+ ]>
+ ⅇ"""
+
+ parser = utils.ProtectedExpatParser(forbid_dtd=False,
+ forbid_entities=True)
+ self.assertRaises(ValueError,
+ minidom.parseString,
+ xml_string, parser)
+
+ def test_notation(self):
+ xml_string = """
+
+
+ ]>
+
+ """
+
+ parser = utils.ProtectedExpatParser(forbid_dtd=False,
+ forbid_entities=True)
+ self.assertRaises(ValueError,
+ minidom.parseString,
+ xml_string, parser)
diff --git a/nova/utils.py b/nova/utils.py
index 2c7d0b427023..764fa9070c67 100644
--- a/nova/utils.py
+++ b/nova/utils.py
@@ -672,19 +672,33 @@ class ProtectedExpatParser(expatreader.ExpatParser):
def entity_decl(self, entityName, is_parameter_entity, value, base,
systemId, publicId, notationName):
- raise ValueError(" forbidden")
+ raise ValueError(" entity declaration forbidden")
def unparsed_entity_decl(self, name, base, sysid, pubid, notation_name):
# expat 1.2
- raise ValueError(" forbidden")
+ raise ValueError(" unparsed entity forbidden")
+
+ def external_entity_ref(self, context, base, systemId, publicId):
+ raise ValueError(" external entity forbidden")
+
+ def notation_decl(self, name, base, sysid, pubid):
+ raise ValueError(" notation forbidden")
def reset(self):
expatreader.ExpatParser.reset(self)
if self.forbid_dtd:
self._parser.StartDoctypeDeclHandler = self.start_doctype_decl
+ self._parser.EndDoctypeDeclHandler = None
if self.forbid_entities:
self._parser.EntityDeclHandler = self.entity_decl
self._parser.UnparsedEntityDeclHandler = self.unparsed_entity_decl
+ self._parser.ExternalEntityRefHandler = self.external_entity_ref
+ self._parser.NotationDeclHandler = self.notation_decl
+ try:
+ self._parser.SkippedEntityHandler = None
+ except AttributeError:
+ # some pyexpat versions do not support SkippedEntity
+ pass
def safe_minidom_parse_string(xml_string):