codekingpro/portable-devtools
114k
1# defusedxml2#3# Copyright (c) 2013 by Christian Heimes <christian@python.org>4# Licensed to PSF under a Contributor Agreement.5# See https://www.python.org/psf/license for licensing details.6"""Defused xml.dom.expatbuilder7"""8from __future__ import print_function, absolute_import9 10from xml.dom.expatbuilder import ExpatBuilder as _ExpatBuilder11from xml.dom.expatbuilder import Namespaces as _Namespaces12 13from .common import DTDForbidden, EntitiesForbidden, ExternalReferenceForbidden14 15__origin__ = "xml.dom.expatbuilder"16 17 18class DefusedExpatBuilder(_ExpatBuilder):19 """Defused document builder"""20 21 def __init__(22 self, options=None, forbid_dtd=False, forbid_entities=True, forbid_external=True23 ):24 _ExpatBuilder.__init__(self, options)25 self.forbid_dtd = forbid_dtd26 self.forbid_entities = forbid_entities27 self.forbid_external = forbid_external28 29 def defused_start_doctype_decl(self, name, sysid, pubid, has_internal_subset):30 raise DTDForbidden(name, sysid, pubid)31 32 def defused_entity_decl(33 self, name, is_parameter_entity, value, base, sysid, pubid, notation_name34 ):35 raise EntitiesForbidden(name, value, base, sysid, pubid, notation_name)36 37 def defused_unparsed_entity_decl(self, name, base, sysid, pubid, notation_name):38 # expat 1.239 raise EntitiesForbidden(name, None, base, sysid, pubid, notation_name) # pragma: no cover40 41 def defused_external_entity_ref_handler(self, context, base, sysid, pubid):42 raise ExternalReferenceForbidden(context, base, sysid, pubid)43 44 def install(self, parser):45 _ExpatBuilder.install(self, parser)46 47 if self.forbid_dtd:48 parser.StartDoctypeDeclHandler = self.defused_start_doctype_decl49 if self.forbid_entities:50 # if self._options.entities:51 parser.EntityDeclHandler = self.defused_entity_decl52 parser.UnparsedEntityDeclHandler = self.defused_unparsed_entity_decl53 if self.forbid_external:54 parser.ExternalEntityRefHandler = self.defused_external_entity_ref_handler55 56 57class DefusedExpatBuilderNS(_Namespaces, DefusedExpatBuilder):58 """Defused document builder that supports namespaces."""59 60 def install(self, parser):61 DefusedExpatBuilder.install(self, parser)62 if self._options.namespace_declarations:63 parser.StartNamespaceDeclHandler = self.start_namespace_decl_handler64 65 def reset(self):66 DefusedExpatBuilder.reset(self)67 self._initNamespaces()68 69 70def parse(file, namespaces=True, forbid_dtd=False, forbid_entities=True, forbid_external=True):71 """Parse a document, returning the resulting Document node.72 73 'file' may be either a file name or an open file object.74 """75 if namespaces:76 build_builder = DefusedExpatBuilderNS77 else:78 build_builder = DefusedExpatBuilder79 builder = build_builder(80 forbid_dtd=forbid_dtd, forbid_entities=forbid_entities, forbid_external=forbid_external81 )82 83 if isinstance(file, str):84 fp = open(file, "rb")85 try:86 result = builder.parseFile(fp)87 finally:88 fp.close()89 else:90 result = builder.parseFile(file)91 return result92 93 94def parseString(95 string, namespaces=True, forbid_dtd=False, forbid_entities=True, forbid_external=True96):97 """Parse a document from a string, returning the resulting98 Document node.99 """100 if namespaces:101 build_builder = DefusedExpatBuilderNS102 else:103 build_builder = DefusedExpatBuilder104 builder = build_builder(105 forbid_dtd=forbid_dtd, forbid_entities=forbid_entities, forbid_external=forbid_external106 )107 return builder.parseString(string)108 