diff --git a/ansible_collections/netapp/ontap/plugins/module_utils/netapp.py b/ansible_collections/netapp/ontap/plugins/module_utils/netapp.py index fcb3d9a4..8a577780 100644 --- a/ansible_collections/netapp/ontap/plugins/module_utils/netapp.py +++ b/ansible_collections/netapp/ontap/plugins/module_utils/netapp.py @@ -377,7 +377,13 @@ def _parse_response(self, response): new_response = new_response.replace(b'\x07\r\n', b'') # And 9.7 may send backspaces for code_point in get_feature(self.module, 'sanitize_code_points'): - new_response = new_response.replace(bytes([code_point]), b'.') + if bytes([8]) == b'\x08': # python 3 + byte = bytes([code_point]) + elif chr(8) == b'\x08': # python 2 + byte = chr(code_point) + else: # very unlikely, noop + byte = b'.' + new_response = new_response.replace(byte, b'.') try: return super(OntapZAPICx, self)._parse_response(new_response) except Exception: diff --git a/ansible_collections/netapp/ontap/tests/unit/plugins/module_utils/test_netapp.py b/ansible_collections/netapp/ontap/tests/unit/plugins/module_utils/test_netapp.py index 5c768400..f0d25206 100644 --- a/ansible_collections/netapp/ontap/tests/unit/plugins/module_utils/test_netapp.py +++ b/ansible_collections/netapp/ontap/tests/unit/plugins/module_utils/test_netapp.py @@ -136,8 +136,11 @@ def create_restapi_object(args): return restApi -def create_OntapZAPICx_object(args): - module = create_module(args) +def create_OntapZAPICx_object(args, feature_flags=None): + module_args = dict(args) + if feature_flags is not None: + module_args['feature_flags'] = feature_flags + module = create_module(module_args) module.fail_json = fail_json my_args = dict(args) my_args.update(dict(module=module)) @@ -385,3 +388,47 @@ def test_classify_zapi_exception_other_error(): kind, new_message = netapp_utils.classify_zapi_exception(zapi_exception) assert kind == 'other_error' assert new_message == error_message + + +def test_zapi_parse_response_sanitized(): + ''' should not fail when trying to read invalid XML characters (\x08) ''' + args = mock_args() + zapi_cx = create_OntapZAPICx_object(args) + response = b"\n\n" + response += b"\n" + response += b" (cluster log-forwarding create)\n\n" + response += b"Testing network connectivity to the destination host 10.10.10.10. \x08\x08\x08\x08\x08\x08\x08\x08\x08\x08\x08\x08\x08\x08\n\n" + response += b"Error: command failed: Cannot contact destination host (10.10.10.10) from node\n" + response += b" "laurentn-vsim1". Verify connectivity to desired host or skip the\n" + response += b" connectivity check with the "-force" parameter." + response += b"0\n" + # Manually extract cli-output contents + cli_output = response.split(b'')[1] + cli_output = cli_output.split(b'')[0] + cli_output = cli_output.replace(b'"', b'"') + # the XML parser would chole on \x08, zapi_cx._parse_response replaces them with '.' + cli_output = cli_output.replace(b'\x08', b'.') + # Use xml parser to extract cli-output contents + xml = zapi_cx._parse_response(response) + results = xml.get_child_by_name('results') + new_cli_output = results.get_child_content('cli-output') + assert cli_output.decode() == new_cli_output + + +def test_zapi_parse_response_unsanitized(): + ''' should fail when trying to read invalid XML characters (\x08) ''' + args = mock_args() + # use feature_flags to disable sanitization + zapi_cx = create_OntapZAPICx_object(args, dict(sanitize_xml=False)) + response = b"\n\n" + response += b"\n" + response += b" (cluster log-forwarding create)\n\n" + response += b"Testing network connectivity to the destination host 10.10.10.10. \x08\x08\x08\x08\x08\x08\x08\x08\x08\x08\x08\x08\x08\x08\n\n" + response += b"Error: command failed: Cannot contact destination host (10.10.10.10) from node\n" + response += b" "laurentn-vsim1". Verify connectivity to desired host or skip the\n" + response += b" connectivity check with the "-force" parameter." + response += b"0\n" + with pytest.raises(netapp_utils.zapi.etree.XMLSyntaxError) as exc: + zapi_cx._parse_response(response) + msg = 'PCDATA invalid Char value 8' + assert exc.value.msg.startswith(msg)