common.py 5.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163
  1. # defusedxml
  2. #
  3. # Copyright (c) 2013 by Christian Heimes <christian@python.org>
  4. # Licensed to PSF under a Contributor Agreement.
  5. # See http://www.python.org/psf/license for licensing details.
  6. """Common constants, exceptions and helpe functions
  7. """
  8. import sys
  9. from types import MethodType
  10. PY3 = sys.version_info[0] == 3
  11. PY26 = sys.version_info[:2] == (2, 6)
  12. PY31 = sys.version_info[:2] == (3, 1)
  13. class DefusedXmlException(ValueError):
  14. """Base exception
  15. """
  16. def __repr__(self):
  17. return str(self)
  18. class DTDForbidden(DefusedXmlException):
  19. """Document type definition is forbidden
  20. """
  21. def __init__(self, name, sysid, pubid):
  22. super(DTDForbidden, self).__init__()
  23. self.name = name
  24. self.sysid = sysid
  25. self.pubid = pubid
  26. def __str__(self):
  27. tpl = "DTDForbidden(name='{}', system_id={!r}, public_id={!r})"
  28. return tpl.format(self.name, self.sysid, self.pubid)
  29. class EntitiesForbidden(DefusedXmlException):
  30. """Entity definition is forbidden
  31. """
  32. def __init__(self, name, value, base, sysid, pubid, notation_name):
  33. super(EntitiesForbidden, self).__init__()
  34. self.name = name
  35. self.value = value
  36. self.base = base
  37. self.sysid = sysid
  38. self.pubid = pubid
  39. self.notation_name = notation_name
  40. def __str__(self):
  41. tpl = "EntitiesForbidden(name='{}', system_id={!r}, public_id={!r})"
  42. return tpl.format(self.name, self.sysid, self.pubid)
  43. class ExternalReferenceForbidden(DefusedXmlException):
  44. """Resolving an external reference is forbidden
  45. """
  46. def __init__(self, context, base, sysid, pubid):
  47. super(ExternalReferenceForbidden, self).__init__()
  48. self.context = context
  49. self.base = base
  50. self.sysid = sysid
  51. self.pubid = pubid
  52. def __str__(self):
  53. tpl = "ExternalReferenceForbidden(system_id='{}', public_id={})"
  54. return tpl.format(self.sysid, self.pubid)
  55. class NotSupportedError(DefusedXmlException):
  56. """The operation is not supported
  57. """
  58. def _apply_defusing(defused_mod):
  59. assert defused_mod is sys.modules[defused_mod.__name__]
  60. stdlib_name = defused_mod.__origin__
  61. __import__(stdlib_name, {}, {}, ["*"])
  62. stdlib_mod = sys.modules[stdlib_name]
  63. stdlib_names = set(dir(stdlib_mod))
  64. for name, obj in vars(defused_mod).items():
  65. if name.startswith("_") or name not in stdlib_names:
  66. continue
  67. setattr(stdlib_mod, name, obj)
  68. return stdlib_mod
  69. def _generate_etree_functions(DefusedXMLParser, _TreeBuilder,
  70. _IterParseIterator, _parse, _iterparse):
  71. """Factory for functions needed by etree, dependent on whether
  72. cElementTree or ElementTree is used."""
  73. def parse(source, parser=None, forbid_dtd=False, forbid_entities=True,
  74. forbid_external=True):
  75. if parser is None:
  76. parser = DefusedXMLParser(target=_TreeBuilder(),
  77. forbid_dtd=forbid_dtd,
  78. forbid_entities=forbid_entities,
  79. forbid_external=forbid_external)
  80. return _parse(source, parser)
  81. if PY26 or PY31:
  82. def bind(xmlparser, funcname, hookname):
  83. func = getattr(DefusedXMLParser, funcname)
  84. if PY26:
  85. # unbound -> function
  86. func = func.__func__
  87. method = MethodType(func, xmlparser, xmlparser.__class__)
  88. else:
  89. method = MethodType(func, xmlparser)
  90. # set hook
  91. setattr(xmlparser._parser, hookname, method)
  92. def iterparse(source, events=None, forbid_dtd=False,
  93. forbid_entities=True, forbid_external=True):
  94. it = _iterparse(source, events)
  95. xmlparser = it._parser
  96. if forbid_dtd:
  97. bind(xmlparser, "defused_start_doctype_decl",
  98. "StartDoctypeDeclHandler")
  99. if forbid_entities:
  100. bind(xmlparser, "defused_entity_decl",
  101. "EntityDeclHandler")
  102. bind(xmlparser, "defused_unparsed_entity_decl",
  103. "UnparsedEntityDeclHandler")
  104. if forbid_external:
  105. bind(xmlparser, "defused_external_entity_ref_handler",
  106. "ExternalEntityRefHandler")
  107. return it
  108. elif PY3:
  109. def iterparse(source, events=None, parser=None, forbid_dtd=False,
  110. forbid_entities=True, forbid_external=True):
  111. close_source = False
  112. if not hasattr(source, "read"):
  113. source = open(source, "rb")
  114. close_source = True
  115. if not parser:
  116. parser = DefusedXMLParser(target=_TreeBuilder(),
  117. forbid_dtd=forbid_dtd,
  118. forbid_entities=forbid_entities,
  119. forbid_external=forbid_external)
  120. return _IterParseIterator(source, events, parser, close_source)
  121. else:
  122. # Python 2.7
  123. def iterparse(source, events=None, parser=None, forbid_dtd=False,
  124. forbid_entities=True, forbid_external=True):
  125. if parser is None:
  126. parser = DefusedXMLParser(target=_TreeBuilder(),
  127. forbid_dtd=forbid_dtd,
  128. forbid_entities=forbid_entities,
  129. forbid_external=forbid_external)
  130. return _iterparse(source, events, parser)
  131. def fromstring(text, forbid_dtd=False, forbid_entities=True,
  132. forbid_external=True):
  133. parser = DefusedXMLParser(target=_TreeBuilder(),
  134. forbid_dtd=forbid_dtd,
  135. forbid_entities=forbid_entities,
  136. forbid_external=forbid_external)
  137. parser.feed(text)
  138. return parser.close()
  139. return parse, iterparse, fromstring