Skip to content

Commit

Permalink
Merge pull request #363 from vnitinv/sax-parser-rfc-compliant
Browse files Browse the repository at this point in the history
Sax parser rfc compliant
  • Loading branch information
vnitinv committed Dec 23, 2019
2 parents 8d4cc71 + fd80401 commit fbaa400
Showing 1 changed file with 17 additions and 16 deletions.
33 changes: 17 additions & 16 deletions ncclient/transport/third_party/junos/parser.py
Original file line number Diff line number Diff line change
Expand Up @@ -33,12 +33,10 @@
import logging
logger = logging.getLogger("ncclient.transport.third_party.junos.parser")

from ncclient.xml_ import BASE_NS_1_0

class RPCTags:
RPC_REPLY_END_TAG = "</rpc-reply>"
RPC_REPLY_END_TAG_LEN = len(RPC_REPLY_END_TAG)
RPC_REPLY_START_TAG = "<rpc-reply"
NAMESPACES = {"nc": "urn:ietf:params:xml:ns:netconf:base:1.0"}
RPC_REPLY_END_TAG = "</rpc-reply>"
RFC_RPC_REPLY_END_TAG = "</nc:rpc-reply>"


class JunosXMLParser(DefaultXMLParser):
Expand All @@ -47,7 +45,6 @@ def __init__(self, session):
self._session = session
self.sax_parser = make_parser()
self.sax_parser.setContentHandler(SAXParser(session))
self.rpc_tags = RPCTags

def parse(self, data):
try:
Expand Down Expand Up @@ -82,9 +79,11 @@ def _delimiter_check(self, data):
# we need to renew parser, as old parser is gone.
self.sax_parser = make_parser()
self.sax_parser.setContentHandler(SAXParser(self._session))
elif self.rpc_tags.RPC_REPLY_END_TAG in data:
elif RPC_REPLY_END_TAG in data or RFC_RPC_REPLY_END_TAG in data:
tag = RPC_REPLY_END_TAG if RPC_REPLY_END_TAG in data else \
RFC_RPC_REPLY_END_TAG
logger.warning("Check for rpc reply end tag within data received: %s" % data)
msg, delim, remaining = data.partition(self.rpc_tags.RPC_REPLY_END_TAG)
msg, delim, remaining = data.partition(tag)
self._session._buffer.seek(0, os.SEEK_END)
self._session._buffer.write(remaining.encode())
else:
Expand All @@ -94,9 +93,13 @@ def _delimiter_check(self, data):
# if then, wait for next iteration of data and do a recursive call to
# _delimiter_check for MSG_DELIM check
buf = self._session._buffer
buf.seek(buf.tell() - self.rpc_tags.RPC_REPLY_END_TAG_LEN - MSG_DELIM_LEN)
buf.seek(buf.tell() - len(RFC_RPC_REPLY_END_TAG) - MSG_DELIM_LEN)
rpc_response_last_msg = buf.read().decode('UTF-8').replace('\n', '')
if self.rpc_tags.RPC_REPLY_END_TAG in rpc_response_last_msg:
if RPC_REPLY_END_TAG in rpc_response_last_msg or \
RFC_RPC_REPLY_END_TAG in rpc_response_last_msg:
tag = RPC_REPLY_END_TAG if RPC_REPLY_END_TAG in \
rpc_response_last_msg else \
RFC_RPC_REPLY_END_TAG
# rpc_response_last_msg and data can be overlapping
match_obj = difflib.SequenceMatcher(None, rpc_response_last_msg,
data).get_matching_blocks()
Expand All @@ -114,9 +117,7 @@ def _delimiter_check(self, data):
# as first if condition will add full delimiter, so clean
# it off
clean_up = len(rpc_response_last_msg) - (
rpc_response_last_msg.find(
self.rpc_tags.RPC_REPLY_END_TAG) +
self.rpc_tags.RPC_REPLY_END_TAG_LEN)
rpc_response_last_msg.find(tag) + len(tag))
self._session._buffer.truncate(buf.tell() - clean_up)
self._delimiter_check(data.encode())
else:
Expand Down Expand Up @@ -193,12 +194,12 @@ def __init__(self, session):
self._session = session
self._validate_reply_and_sax_tag = False
self._lock = Lock()
self.nc_namespace = None

def startElement(self, tag, attributes):
if tag in ['rpc-reply', 'nc:rpc-reply']:
if tag == 'nc:rpc-reply':
RPCTags.RPC_REPLY_END_TAG = "</nc:rpc-reply>"
RPCTags.RPC_REPLY_START_TAG = "<nc:rpc-reply"
self.nc_namespace = BASE_NS_1_0
# in case last rpc called used sax parsing and error'd out
# without resetting use_filer in endElement rpc-reply check
with self._lock:
Expand All @@ -222,7 +223,7 @@ def startElement(self, tag, attributes):
if self._cur == self._root and self._cur.tag == tag:
node = self._root
else:
node = self._cur.find(tag, namespaces=RPCTags.NAMESPACES)
node = self._cur.find(tag, namespaces={"nc": self.nc_namespace})

if self._validate_reply_and_sax_tag:
if tag != self._root.tag:
Expand Down

0 comments on commit fbaa400

Please sign in to comment.