diff options
-rw-r--r-- | ca/tests/xml-parse-test.py | 18 | ||||
-rw-r--r-- | rpki/left_right.py | 43 | ||||
-rw-r--r-- | rpki/xml_utils.py | 175 |
3 files changed, 8 insertions, 228 deletions
diff --git a/ca/tests/xml-parse-test.py b/ca/tests/xml-parse-test.py index 85f4453e..ac276eb4 100644 --- a/ca/tests/xml-parse-test.py +++ b/ca/tests/xml-parse-test.py @@ -30,7 +30,6 @@ import glob import lxml.etree -import lxml.sax import rpki.up_down import rpki.left_right import rpki.publication @@ -39,25 +38,24 @@ import rpki.relaxng verbose = False -def test(fileglob, rng, sax_handler, encoding, tester = None): +def test(fileglob, rng, parser, encoding, tester = None): files = glob.glob(fileglob) files.sort() for f in files: print "<!--", f, "-->" - handler = sax_handler() elt_in = lxml.etree.parse(f).getroot() if verbose: print "<!-- Input -->" print lxml.etree.tostring(elt_in, pretty_print = True, encoding = encoding, xml_declaration = True) rng.assertValid(elt_in) - lxml.sax.saxify(elt_in, handler) - elt_out = handler.result.toXML() + parsed = parser.fromXML(elt_in) + elt_out = parsed.toXML() if verbose: print "<!-- Output -->" print lxml.etree.tostring(elt_out, pretty_print = True, encoding = encoding, xml_declaration = True) rng.assertValid(elt_out) if tester: - tester(elt_in, elt_out, handler.result) + tester(elt_in, elt_out, parsed) if verbose: print @@ -108,24 +106,24 @@ def pc_tester(elt_in, elt_out, msg): test(fileglob = "up-down-protocol-samples/*.xml", rng = rpki.relaxng.up_down, - sax_handler = rpki.up_down.sax_handler, + parser = rpki.up_down.msg, encoding = "utf-8", tester = ud_tester) test(fileglob = "left-right-protocol-samples/*.xml", rng = rpki.relaxng.left_right, - sax_handler = rpki.left_right.sax_handler, + parser = rpki.left_right.msg, encoding = "us-ascii", tester = lr_tester) test(fileglob = "publication-protocol-samples/*.xml", rng = rpki.relaxng.publication, - sax_handler = rpki.publication.sax_handler, + parser = rpki.publication.msg, encoding = "us-ascii", tester = pp_tester) test(fileglob = "publication-control-protocol-samples/*.xml", rng = rpki.relaxng.publication_control, - sax_handler = rpki.publication_control.sax_handler, + parser = rpki.publication_control.msg, encoding = "us-ascii", tester = pc_tester) diff --git a/rpki/left_right.py b/rpki/left_right.py index c7517e26..2f1b7577 100644 --- a/rpki/left_right.py +++ b/rpki/left_right.py @@ -1302,16 +1302,6 @@ class list_resources_elt(rpki.xml_utils.base_elt, left_right_namespace): if self.ipv6 is not None: self.ipv6 = rpki.resource_set.resource_set_ipv6(self.ipv6) - def startElement(self, stack, name, attrs): - """ - Handle <list_resources/> element. This requires special handling - due to the data types of some of the attributes. - """ - - assert name == "list_resources", "Unexpected name %s, stack %s" % (name, stack) - self.read_attrs(attrs) - self.fix_attribute_types() - @classmethod def fromXML(cls, elt): """ @@ -1352,16 +1342,6 @@ class list_roa_requests_elt(rpki.xml_utils.base_elt, left_right_namespace): if self.ipv6 is not None: self.ipv6 = rpki.resource_set.roa_prefix_set_ipv6(self.ipv6) - def startElement(self, stack, name, attrs): - """ - Handle <list_roa_requests/> element. This requires special handling - due to the data types of some of the attributes. - """ - - assert name == "list_roa_requests", "Unexpected name %s, stack %s" % (name, stack) - self.read_attrs(attrs) - self.fix_attribute_types() - @classmethod def fromXML(self, elt): """ @@ -1424,17 +1404,6 @@ class list_ee_certificate_requests_elt(rpki.xml_utils.base_elt, left_right_names if self.eku is not None: self.eku = self.eku.split(",") - def startElement(self, stack, name, attrs): - """ - Handle <list_ee_certificate_requests/> element. This requires special - handling due to the data types of some of the attributes. - """ - - if name not in self.elements: - assert name == self.element_name, "Unexpected name %s, stack %s" % (name, stack) - self.read_attrs(attrs) - self.fix_attribute_types() - @classmethod def fromXML(cls, elt): """ @@ -1446,18 +1415,6 @@ class list_ee_certificate_requests_elt(rpki.xml_utils.base_elt, left_right_names self.fix_attribute_types() return self - def endElement(self, stack, name, text): - """ - Handle <pkcs10/> sub-element. - """ - - assert len(self.elements) == 1 - if name == self.elements[0]: - self.pkcs10 = rpki.x509.PKCS10(Base64 = text) - else: - assert name == self.element_name, "Unexpected name %s, stack %s" % (name, stack) - stack.pop() - def toXML(self): """ Generate <list_ee_certificate_requests/> element. This requires special diff --git a/rpki/xml_utils.py b/rpki/xml_utils.py index 99377e17..89a9095f 100644 --- a/rpki/xml_utils.py +++ b/rpki/xml_utils.py @@ -33,117 +33,12 @@ XML utilities. """ import logging -import xml.sax -import lxml.sax import lxml.etree import rpki.exceptions logger = logging.getLogger(__name__) -class sax_handler(xml.sax.handler.ContentHandler): - """ - SAX handler for RPKI protocols. - - This class provides some basic amenities for parsing protocol XML of - the kind we use in the RPKI protocols, including whacking all the - protocol element text into US-ASCII, simplifying accumulation of - text fields, and hiding some of the fun relating to XML namespaces. - - General assumption: by the time this parsing code gets invoked, the - XML has already passed RelaxNG validation, so we only have to check - for errors that the schema can't catch, and we don't have to play as - many XML namespace games. - """ - - # .pdu, .name, and .version are provided by subclass - - def __init__(self): - """ - Initialize SAX handler. - """ - - xml.sax.handler.ContentHandler.__init__(self) - self.text = "" - self.stack = [] - - def startElementNS(self, name, qname, attrs): - """ - Redirect startElementNS() events to startElement(). - """ - - return self.startElement(name[1], attrs) - - def endElementNS(self, name, qname): - """ - Redirect endElementNS() events to endElement(). - """ - - return self.endElement(name[1]) - - def characters(self, content): - """ - Accumulate a chuck of element content (text). - """ - - self.text += content - - def startElement(self, name, attrs): - """ - Handle startElement() events. - - We maintain a stack of nested elements under construction so that - we can feed events directly to the current element rather than - having to pass them through all the nesting elements. - - If the stack is empty, this event is for the outermost element, so - we call a virtual method to create the corresponding object and - that's the object we'll be returning as our final result. - """ - - a = dict() - for k, v in attrs.items(): - if isinstance(k, tuple): - if k == ("http://www.w3.org/XML/1998/namespace", "lang"): - k = "xml:lang" - else: - assert k[0] is None - k = k[1] - a[k.encode("ascii")] = v.encode("ascii") - if len(self.stack) == 0: - assert not hasattr(self, "result") - self.result = self.create_top_level(name, a) - self.stack.append(self.result) - self.stack[-1].startElement(self.stack, name, a) - - def endElement(self, name): - """ - Handle endElement() events. Mostly this means handling any - accumulated element text. - """ - - text = self.text.encode("ascii").strip() - self.text = "" - self.stack[-1].endElement(self.stack, name, text) - - @classmethod - def saxify(cls, elt): - """ - Create a one-off SAX parser, parse an ETree, return the result. - """ - - self = cls() - lxml.sax.saxify(elt, self) - return self.result - - def create_top_level(self, name, attrs): - """ - Handle top-level PDU for this protocol. - """ - - assert name == self.name and attrs["version"] == self.version - return self.pdu() - class base_elt(object): """ Virtual base class for XML message elements. The left-right and @@ -166,31 +61,12 @@ class base_elt(object): # Name of class attribute that tells us where to put text values, if any. text_attribute = None - def startElement(self, stack, name, attrs): - """ - Default startElement() handler: just process attributes. - """ - - if name not in self.elements: - assert name == self.element_name, "Unexpected name %s, stack %s" % (name, stack) - self.read_attrs(attrs) - - def endElement(self, stack, name, text): - """ - Default endElement() handler: just pop the stack. - """ - - assert name == self.element_name, "Unexpected name %s, stack %s" % (name, stack) - stack.pop() - @classmethod def fromXML(cls, elt): """ First cut at non-SAX message unpacker. This will probably change. """ - logger.warning("base_elt(): Element %r (len %s)", elt, len(elt)) - self = cls() for key in self.attributes: @@ -215,8 +91,6 @@ class base_elt(object): # so kludge it for now. for b64 in elt: - # XXX - logger.warning("base_elt(): XML tag %r, XML namespace %r", b64.tag, self.xmlns) assert b64.tag.startswith(self.xmlns) ename = b64.tag[len(self.xmlns):] etype = self.elements[ename] @@ -292,14 +166,6 @@ class text_elt(base_elt): Virtual base class for XML message elements that contain text. """ - def endElement(self, stack, name, text): - """ - Extract text from parsed XML. - """ - - base_elt.endElement(self, stack, name, text) - setattr(self, self.text_attribute, text) - def toXML(self): """ Insert text into generated XML. @@ -315,21 +181,6 @@ class data_elt(base_elt): all implement the create/set/get/list/destroy action attribute. """ - def endElement(self, stack, name, text): - """ - Default endElement handler for SQL-based objects. This assumes - that sub-elements are Base64-encoded using the sql_template - mechanism. - """ - - if name in self.elements: - elt_type = self.sql_template.map.get(name) - assert elt_type is not None, "Couldn't find element type for %s, stack %s" % (name, stack) - setattr(self, name, elt_type(Base64 = text)) - else: - assert name == self.element_name, "Unexpected name %s, stack %s" % (name, stack) - stack.pop() - def toXML(self): """ Default element generator for SQL-based objects. This assumes @@ -500,29 +351,6 @@ class msg(list): Generic top-level PDU. """ - def startElement(self, stack, name, attrs): - """ - Handle top-level PDU. - """ - - if name == "msg": - assert self.version == int(attrs["version"]) - self.type = attrs["type"] - else: - elt = self.pdus[name]() - self.append(elt) - stack.append(elt) - elt.startElement(stack, name, attrs) - - def endElement(self, stack, name, text): - """ - Handle top-level PDU. - """ - - assert name == "msg", "Unexpected name %s, stack %s" % (name, stack) - assert len(stack) == 1 - stack.pop() - def __str__(self): """ Convert msg object to string. @@ -586,10 +414,7 @@ class msg(list): # This could be simplified by including the namespace name in the .pdus[] key. for sub in elt: - # XXX - logger.warning("msg(): XML tag %r, XML namespace %r", sub.tag, self.xmlns) assert sub.tag.startswith(self.xmlns) self.append(self.pdus[sub.tag[len(self.xmlns):]].fromXML(sub)) - logger.warning("msg(): parsed %r", self) return self |