Esempio n. 1
0
    def parse_response(self,
                       action_name,
                       content,
                       encoding=None,
                       envelope_attrib=None,
                       typed=None):
        """
            Parses a response from the server with the given action name and content.
        """
        register_namespace('', None)

        if encoding is None:
            encoding = self._encoding
        if envelope_attrib is None:
            envelope_attrib = self._envelope_attrib
        if typed is None:
            typed = self._typed

        try:
            docNode = xml_fromstring(content)
        except ParseError:
            # Try removing any extra XML declarations in case there are more than one.
            # This sometimes happens when a device sends its own XML config files.
            content = remove_extraneous_xml_declarations(content)
            docNode = xml_fromstring(content)
        except ValueError:
            # This can occur when requests returns a `str` (unicode) but there's also an XML
            # declaration, which lxml doesn't like.
            docNode = xml_fromstring(content.encode('utf8'))

        resp_body = None
        if typed:
            resp_body = docNode.find(".//{%s}%sResponse" %
                                     (typed, action_name))
        else:
            resp_body = docNode.find(".//%sResponse" % action_name)

        if resp_body is None:
            msg = (
                'Returned XML did not include an element which matches namespace %r and tag name'
                ' \'%sResponse\'.' % (typed, action_name))
            print(msg + '\n' + xml_tostring(
                docNode, short_empty_elements=False).decode('utf8'))
            raise SOAPProtocolError(msg)

        # Sometimes devices return XML strings as their argument values without escaping them with
        # CDATA. This checks to see if the argument has been parsed as XML and un-parses it if so.
        resp_dict = {}
        for arg in resp_body.getchildren():
            children = arg.getchildren()
            if children:
                resp_dict[arg.tag] = "\n".join(
                    xml_tostring(x) for x in children)
            else:
                if arg.text is None:
                    resp_dict[arg.tag] = ""
                else:
                    resp_dict[arg.tag] = arg.text

        return resp_dict
Esempio n. 2
0
    def create_response(self,
                        action_name: str,
                        arguments: dict,
                        encoding=None,
                        envelope_attrib=None,
                        typed=None):
        """
            Creates a Soap response to the action with the specified arguments.
        """
        register_namespace('', None)

        if encoding is None:
            encoding = self._encoding
        if envelope_attrib is None:
            envelope_attrib = self._envelope_attrib
        if typed is None:
            typed = self._typed

        envelope = Element("s:Envelope")
        if envelope_attrib:
            for eakey, eaval in envelope_attrib:
                envelope.attrib.update({eakey: eaval})
        else:
            envelope.attrib.update({'xmlns:s': NS_SOAP_ENV})
            envelope.attrib.update({'s:encodingStyle': encoding})

        body = SubElement(envelope, "s:Body")

        action_name_tag_name = action_name + "Response"
        methElement = SubElement(body, action_name_tag_name)
        if encoding:
            methElement.set(NS_SOAP_ENV + "encodingStyle", encoding)

        if arguments:
            for arg_name, arg_val in arguments.items():
                py_type = type(arg_val)
                soap_type = PYTHON_TO_SOAP_TYPE_MAP[py_type]

                if soap_type == 'xsd:string':
                    arg_val = arg_val  # pylint: disable=self-assigning-variable
                elif soap_type == 'xsd:int' or soap_type == 'xsd:float':
                    arg_val = str(arg_val)
                elif soap_type == 'xsd:boolean':
                    arg_val = "1" if arg_val else "0"

                argElement = SubElement(methElement, arg_name)
                if typed and soap_type:
                    if not isinstance(type, QName):
                        arg_type = QName(NS_XSD, soap_type)
                    argElement.set(NS_XSI + "type", soap_type)

                argElement.text = arg_val
        else:
            methElement.text = ""

        envelope_content = xml_tostring(envelope, short_empty_elements=False)
        content = XML_DOCUMENT_DECLARATION + "\n" + str_cast(envelope_content)

        return content
Esempio n. 3
0
def xml_dump(obj, root=None, encoding='us-ascii'):

    """

    Dispatch function to turn a python object into
    an xml string.

    @param obj: python container or xml root object
    @param root: Element instance to act as the root
    """

    if isinstance(obj, dict):
        obj = _dict_toxml(obj, root)
    elif isinstance(obj, Iterable) and not isinstance(obj, str):
        obj = _iter_toxml(root, "Response", obj)
    return xml_tostring(obj, encoding)
Esempio n. 4
0
 def commit(self):
     if self._done:
         raise RuntimeError("Can't commit twice or after close")
     self._done = True
     data = xml_tostring(self.xml)
     result = yield from self.bucket._request(Request("POST",
         '/' + self.key, {
             'uploadId': self.upload_id,
         }, headers={
             'CONTENT-LENGTH': str(len(data)),
             'HOST': self.bucket._host,
             'CONTENT-TYPE': 'application/xml',
         }, payload=data))
     try:
         xml = yield from result.read()
         if result.status != 200:
             raise errors.AWSException.from_bytes(result.status, xml)
         xml = parse_xml(xml)
         return xml.find('s3:ETag', namespaces=NS)
     finally:
         result.close()
Esempio n. 5
0
    def _find_value(self, path, namespaces) -> Union[str, None]:
        """
            Lookup a node using the path specified and then get its text value.

            :param path: The path to the node that is being found.
            :param namespaces: A dictionary of namespaces to use when processing the XML elements.

            :returns: The text value of the node associated with the specified path or None.
        """
        # pylint: disable=broad-except
        rtnval = None

        try:
            valNode = self._ref_node.find(path, namespaces=namespaces)
            if valNode is not None:
                rtnval = valNode.text
        except Exception as err:
            print(str(err))
            register_namespace('', None)
            xmlcontent = xml_tostring(self._ref_node)
            print(xmlcontent)
            print("")

        return rtnval
Esempio n. 6
0
 def commit(self):
     if self._done:
         raise RuntimeError("Can't commit twice or after close")
     self._done = True
     data = xml_tostring(self.xml)
     result = yield from self.bucket._request(
         Request("POST",
                 '/' + self.key, {
                     'uploadId': self.upload_id,
                 },
                 headers={
                     'CONTENT-LENGTH': str(len(data)),
                     'HOST': self.bucket._host,
                     'CONTENT-TYPE': 'application/xml',
                 },
                 payload=data))
     try:
         xml = yield from result.read()
         if result.status != 200:
             raise errors.AWSException.from_bytes(result.status, xml)
         xml = parse_xml(xml)
         return xml.find('s3:ETag', namespaces=NS)
     finally:
         result.close()
Esempio n. 7
0
    def parse_response_error_for_upnp(self,
                                      action_name,
                                      content,
                                      status_code,
                                      extra=None,
                                      encoding=None,
                                      envelope_attrib=None,
                                      typed=None):
        """
            Parse response error for a upnp response.
        """
        register_namespace('', None)

        if encoding is None:
            encoding = self._encoding
        if envelope_attrib is None:
            envelope_attrib = self._envelope_attrib
        if typed is None:
            typed = self._typed

        try:
            docNode = xml_fromstring(content)
        except ParseError:
            # Try removing any extra XML declarations in case there are more than one.
            # This sometimes happens when a device sends its own XML config files.
            content = remove_extraneous_xml_declarations(content)
            docNode = xml_fromstring(content)
        except ValueError:
            # This can occur when requests returns a `str` (unicode) but there's also an XML
            # declaration, which lxml doesn't like.
            docNode = xml_fromstring(content.encode('utf8'))

        resp_body = None
        if typed:
            resp_body = docNode.find(".//{%s}Fault" % (NS_SOAP_ENV, ))
        else:
            resp_body = docNode.find(".//Fault")

        if resp_body is None:
            msg = (
                'Returned XML did not include an element which matches namespace %r and tag name'
                ' \'%sFault\'.' % (typed, action_name))
            print(msg + '\n' + xml_tostring(
                docNode, short_empty_elements=False).decode('utf8'))
            raise SOAPProtocolError(msg)

        # Lets try to extract the XML response error information
        try:
            faultCode = resp_body.find(".//faultcode").text
            faultString = resp_body.find(".//faultstring").text
            detail = resp_body.find(".//detail")
            upnpErrorNode = detail.find(".//{%s}UPnPError" % NS_UPNP_CONTROL)
            errorCode = int(
                upnpErrorNode.find(".//{%s}errorCode" % NS_UPNP_CONTROL).text)
            errorDescription = upnpErrorNode.find(".//{%s}errorDescription" %
                                                  NS_UPNP_CONTROL)
            if errorDescription is None:
                errorDescription = UPNP_ERROR_TEST_LOOKUP.get(
                    errorCode, "Unknown error.")

        except Exception as xcpt:
            errmsg = "Unable to process xml response: status=%r\n%s" % (
                status_code, content)
            if extra is not None:
                errmsg += "EXTRA:\n%s" % extra
            raise SOAPProtocolError(errmsg) from xcpt

        return errorCode, errorDescription
Esempio n. 8
0
    def record_description(self,
                           ip_addr: str,
                           urlBase: str,
                           manufacturer: str,
                           modelName: str,
                           docTree: ElementTree,
                           devNode: Element,
                           namespaces: str,
                           upnp_recording: bool = False):
        """
            Called to record a description of a UPNP root device.

            :param urlBase: The base url as detailed in the description document or if not specified as determined by looking at the host information.
            :param manufacturer: The manufacturer of the device.
            :param modelName: The model name of the device.
            :param docTree: The XML document tree from the root of the device description.
            :param devNode: The 'device' element node from the device description.
            :param namespaces: A dictionary of namespaced to use when processing the XML document.
            :param upnp_recording: Force the recording of the device description and will overwrite existing device descriptions.
        """
        manufacturerNormalized = normalize_name_for_path(manufacturer)
        modelName = normalize_name_for_path(modelName)

        root_dev_dir = os.path.join(DIR_UPNP_SCAN_INTEGRATION_ROOTDEVICES,
                                    manufacturerNormalized)
        if not os.path.exists(root_dev_dir):
            os.makedirs(root_dev_dir)

        root_dev_def_file = os.path.join(root_dev_dir, modelName + ".xml")

        if upnp_recording:
            console_msg_lines = [
                "================================================================",
                " Recording Device: {}".format(ip_addr),
                "------------------------- Detail -------------------------------",
                "     Manufacturer: {}".format(manufacturer),
                "            Model: {}".format(modelName),
                "      Device File: {}".format(root_dev_def_file)
            ]
            console_msg = os.linesep.join(console_msg_lines)
            print(console_msg)

        if upnp_recording or not os.path.exists(root_dev_def_file):
            docNode = docTree.getroot()
            register_namespace('', namespaces[''])
            pretty_dev_content = xml_tostring(docNode,
                                              short_empty_elements=False)
            with open(root_dev_def_file, 'wb') as rddf:
                rddf.write(pretty_dev_content)

        indent = "    "
        next_indent = indent + "    "
        embDevList = devNode.find("deviceList", namespaces=namespaces)
        if embDevList is not None:
            if upnp_recording:
                print("{}[ Embedded Devices ]".format(indent))

            for embDevNode in embDevList:
                self._record_embedded_device(urlBase,
                                             manufacturerNormalized,
                                             embDevNode,
                                             namespaces,
                                             upnp_recording=upnp_recording,
                                             indent=next_indent)

            if upnp_recording:
                print("")

        svcList = devNode.find("serviceList", namespaces=namespaces)
        if svcList is not None:
            if upnp_recording:
                print("{}[ Services ]".format(indent))

            for svcNode in svcList:
                self._record_service(urlBase,
                                     manufacturerNormalized,
                                     svcNode,
                                     namespaces,
                                     upnp_recording=upnp_recording,
                                     indent=next_indent)

            if upnp_recording:
                print("")

        if upnp_recording:
            print()

        return
Esempio n. 9
0
    def _record_embedded_device(self,
                                urlBase: str,
                                manufacturer: str,
                                embDevNode: Element,
                                namespaces: Optional[dict] = None,
                                upnp_recording: bool = False,
                                indent="    "):
        """
            Method called for recording the description of an embedded device from a device description.

            :param manufacturer: The manufacturer of the device.
            :param embDevNode: The XML element node of the embedded device.
            :param namespaces: A dictionary of namespaces to use when processing the device description.
            :param upnp_recording: A boolean value indicating if the embedded device description should be recorded regardless of whether
                                    an existing description has been recorded.
        """
        # pylint: disable=no-self-use

        deviceTypeNode = embDevNode.find("deviceType", namespaces=namespaces)
        if deviceTypeNode is not None:
            deviceType = deviceTypeNode.text

            dyn_dev_dir = os.path.join(
                DIR_UPNP_SCAN_INTEGRATION_EMBEDDEDDEVICES, manufacturer)
            if not os.path.exists(dyn_dev_dir):
                os.makedirs(dyn_dev_dir)

            dyn_dev_filename = os.path.join(dyn_dev_dir, deviceType + ".xml")
            if upnp_recording or not os.path.exists(dyn_dev_filename):
                if upnp_recording:
                    dev_msg_lines = [
                        "{}Embedded Device Type: {}".format(
                            indent, deviceType),
                        "{}Embedded Device File: {}".format(
                            indent, dyn_dev_filename)
                    ]
                    dev_msg = os.linesep.join(dev_msg_lines)
                    print(dev_msg)

                pretty_sl_content = ""

                srcSvcListNode = embDevNode.find("serviceList",
                                                 namespaces=namespaces)
                if srcSvcListNode is not None:
                    svcs_indent = indent + "    "
                    if upnp_recording:
                        print("{}[ Embedded Services ]".format(indent))

                    for svcNode in srcSvcListNode:
                        self._record_service(urlBase,
                                             manufacturer,
                                             svcNode,
                                             namespaces,
                                             upnp_recording=upnp_recording,
                                             indent=svcs_indent)

                    if upnp_recording:
                        print("")

                    register_namespace('', namespaces[''])
                    pretty_sl_content = xml_tostring(srcSvcListNode)

                with open(dyn_dev_filename, 'wb') as edf:
                    edf.write(b"<device>\n")
                    edf.write(pretty_sl_content)
                    edf.write(b"</device\n")

        return