aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--ca/tests/xml-parse-test.py18
-rw-r--r--rpki/left_right.py43
-rw-r--r--rpki/xml_utils.py175
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