示例#1
0
def test_collecting_plugins_and_context_per_empty_domain(domain,
        expected_context):
    container = PluginContainer([])
    result = getattr(container, domain)
    assert result.__class__ is PluginDomain
    assert result.ctx is expected_context
    assert result.plugins == []
示例#2
0
    def __init__(self, username, password, source='', wsdl_url=None, **kwargs):
        if not wsdl_url:
            wsdl_url = docmail.client.DOCMAIL_WSDL
        self.source = source
        self.username = username
        self.password = password

        self.return_format = 'XML'
        self.failure_return_format = 'XML'

        options = Options()
        options.transport = HttpAuthenticated()
        self.options = options
        options.cache = MemCache()
        self.set_options(**kwargs)
        reader = DefinitionsReader(options, Definitions)
        self.wsdl = reader.open(wsdl_url)
        plugins = PluginContainer(options.plugins)
        plugins.init.initialized(wsdl=self.wsdl)
        self.factory = Factory(self.wsdl)
        self.service = ServiceSelector(self, self.wsdl.services)
        self.sd = []
        for s in self.wsdl.services:
            sd = ServiceDefinition(self.wsdl, s)
            self.sd.append(sd)
        self.messages = dict(tx=None, rx=None)
 def __init__(self, options):
     """
     @param options: An options object.
     @type options: I{Options}
     """
     self.options = options
     self.plugins = PluginContainer(options.plugins)
示例#4
0
def test_exception_passing():
    class FailingPluginException(Exception):
        pass

    class FailingPlugin(MessagePlugin):
        def marshalled(self, context):
            raise FailingPluginException

    container = PluginContainer([FailingPlugin()])
    pytest.raises(FailingPluginException, container.message.marshalled)
示例#5
0
def test_invalid_plugin_domain():
    container = PluginContainer([])
    domain = "invalid_domain_name"
    e = pytest.raises(Exception, getattr, container, domain)
    try:
        e = e.value
        assert e.__class__ is Exception
        assert str(e) == "plugin domain (%s), invalid" % (domain,)
    finally:
        del e  # explicitly break circular reference chain in Python 3
示例#6
0
 def succeeded(self, reply):
     """
     Re-entry for processing a successful reply.
     @param reply: The reply soap envelope.
     @type reply: str
     @return: The returned value for the invoked method.
     @rtype: object
     """
     options = self.client.options
     plugins = PluginContainer(options.plugins)
     ctx = plugins.message.received(reply=reply)
     reply = ctx.reply
     return self.client.succeeded(self.binding, reply)
示例#7
0
文件: wsdl.py 项目: timofeic/bfbot
 def __init__(self, url, options):
     """
     @param url: A URL to the WSDL.
     @type url: str
     @param options: An options dictionary.
     @type options: L{options.Options}
     """
     log.debug('reading wsdl at: %s ...', url)
     reader = DocumentReader(options)
     d = reader.open(url)
     root = d.root()
     plugins = PluginContainer(options.plugins)
     plugins.loaded(root=root)
     WObject.__init__(self, root)
     self.id = objid(self)
     self.options = options
     self.url = url
     self.tns = self.mktns(root)
     self.types = []
     self.schema = None
     self.children = []
     self.imports = []
     self.messages = {}
     self.port_types = {}
     self.bindings = {}
     self.services = []
     self.add_children(self.root)
     self.children.sort()
     pmd = self.__metadata__.__print__
     pmd.excludes.append('children')
     pmd.excludes.append('wsdl')
     pmd.wrappers['schema'] = repr
     self.open_imports()
     self.resolve()
     self.build_schema()
     self.set_wrapped()
     for s in self.services:
         self.add_methods(s)
     log.debug("wsdl at '%s' loaded:\n%s", url, self)
示例#8
0
文件: schema.py 项目: timofeic/bfbot
 def __init__(self, root, baseurl, options, container=None):
     """
     @param root: The xml root.
     @type root: L{sax.element.Element}
     @param baseurl: The base url used for importing.
     @type baseurl: basestring
     @param options: An options dictionary.
     @type options: L{options.Options}
     @param container: An optional container.
     @type container: L{SchemaCollection}
     """
     self.root = root
     self.id = objid(self)
     self.tns = self.mktns()
     self.baseurl = baseurl
     self.container = container
     self.children = []
     self.all = []
     self.types = {}
     self.imports = []
     self.elements = {}
     self.attributes = {}
     self.groups = {}
     self.agrps = {}
     plugins = PluginContainer(options.plugins)
     plugins.loaded(root=root)
     if options.doctor is not None:
         options.doctor.examine(root)
     form = self.root.get('elementFormDefault')
     if form is None:
         self.form_qualified = False
     else:
         self.form_qualified = ( form == 'qualified' )
     if container is None:
         self.build()
         self.open_imports(options)
         log.debug('built:\n%s', self)
         self.dereference()
         log.debug('dereferenced:\n%s', self)
示例#9
0
 def send(self, soapenv):
     """
     Send soap message.
     @param soapenv: A soap envelope to send.
     @type soapenv: L{Document}
     @return: The reply to the sent message.
     @rtype: I{builtin} or I{subclass of} L{Object}
     """
     result = None
     location = self.location()
     binding = self.method.binding.input
     transport = self.options.transport
     retxml = self.options.retxml
     nosend = self.options.nosend
     prettyxml = self.options.prettyxml
     timer = metrics.Timer()
     log.debug('sending to (%s)\nmessage:\n%s', location, soapenv)
     try:
         self.last_sent(soapenv)
         plugins = PluginContainer(self.options.plugins)
         plugins.message.marshalled(envelope=soapenv.root())
         if prettyxml:
             soapenv = soapenv.str()
         else:
             soapenv = soapenv.plain()
         soapenv = soapenv.encode('utf-8')
         ctx = plugins.message.sending(envelope=soapenv)
         soapenv = ctx.envelope
         if nosend:
             return RequestContext(self, binding, soapenv)
         request = Request(location, soapenv)
         request.headers = self.headers()
         timer.start()
         reply = transport.send(request)
         timer.stop()
         metrics.log.debug('waited %s on server reply', timer)
         ctx = plugins.message.received(reply=reply.message)
         reply.message = ctx.reply
         if retxml:
             result = reply.message
         else:
             result = self.succeeded(binding, reply.message)
     except TransportError as e:
         if e.httpcode in (202, 204):
             result = None
         else:
             log.error(self.last_sent())
             result = self.failed(binding, e)
     return result
示例#10
0
def _failed(self, binding, error):
    status, reason = (error.httpcode, str(error))
    reply = error.fp.read()
    if status == 500:
        if len(reply) > 0:
            reply, result = binding.get_reply(self.method, reply)
            self.last_received(reply)
            plugins = PluginContainer(self.options.plugins)
            ctx = plugins.message.unmarshalled(reply=result)
            result = ctx.reply
            return (status, result)
        else:
            return (status, None)
    if self.options.faults:
        raise Exception((status, reason))
    else:
        return (status, None)
示例#11
0
    def send(self, soapenv):
        """
        Send SOAP message.

        Depending on how the ``nosend`` & ``retxml`` options are set, may do
        one of the following:
          * Return a constructed web service operation request without sending
            it to the web service.
          * Invoke the web service operation and return its SOAP reply XML.
          * Invoke the web service operation, process its results and return
            the Python object representing the returned value.

        @param soapenv: A SOAP envelope to send.
        @type soapenv: L{Document}
        @return: SOAP request, SOAP reply or a web service return value.
        @rtype: L{RequestContext}|I{builtin}|I{subclass of} L{Object}|I{bytes}|
            I{None}

        """
        location = self.__location()
        log.debug("sending to (%s)\nmessage:\n%s", location, soapenv)
        plugins = PluginContainer(self.options.plugins)
        plugins.message.marshalled(envelope=soapenv.root())
        if self.options.prettyxml:
            soapenv = soapenv.str()
        else:
            soapenv = soapenv.plain()
        soapenv = soapenv.encode("utf-8")
        ctx = plugins.message.sending(envelope=soapenv)
        soapenv = ctx.envelope
        if self.options.nosend:
            return RequestContext(self.process_reply, soapenv)
        request = suds.transport.Request(location, soapenv)
        request.headers = self.__headers()
        try:
            timer = metrics.Timer()
            timer.start()
            reply = self.options.transport.send(request)
            timer.stop()
            metrics.log.debug("waited %s on server reply", timer)
        except suds.transport.TransportError as e:
            content = e.fp and e.fp.read() or ""
            return self.process_reply(content, e.httpcode, tostr(e))
        return self.process_reply(reply.message, None, None)
示例#12
0
def test_collecting_plugins_per_domain(domain, plugin_class):
    plugins = [
        MyDocumentPlugin(),
        MyDocumentPlugin(),
        MyMessagePlugin(),
        MyDocumentPlugin(),
        MyInitPlugin(),
        MyInitPlugin(),
        MyMessagePlugin(),
        InitPlugin(),
        MyMessagePlugin(),
        MyMessagePlugin(),
        None,
        MessagePlugin(),
        DocumentPlugin(),
        MyMessagePlugin(),
        MyDocumentPlugin(),
        InitPlugin(),
        InitPlugin(),
        MyInitPlugin(),
        MyInitPlugin(),
        None,
        MyDocumentPlugin(),
        DocumentPlugin(),
        MessagePlugin(),
        DocumentPlugin(),
        MessagePlugin(),
        DocumentPlugin(),
        InitPlugin(),
        MessagePlugin(),
        object(),
        DocumentPlugin(),
        MessagePlugin(),
        object(),
        InitPlugin(),
        Plugin(),
        Plugin(),
        MyInitPlugin()]
    container = PluginContainer(plugins)
    expected_plugins = [p for p in plugins if isinstance(p, plugin_class)]
    result = getattr(container, domain).plugins
    assert result == expected_plugins
示例#13
0
 def get_reply(self, method, reply):
     """
     Process the I{reply} for the specified I{method} by sax parsing the
     I{reply} and then unmarshalling into Python object(s).
     @param method: The name of the invoked method.
     @type method: str
     @param reply: The reply XML received after invoking the specified
         method.
     @type reply: str
     @return: The unmarshalled reply.  The returned value is an L{Object}
         for a I{list} depending on whether the service returns a single
         object or a collection.
     @rtype: tuple ( L{Element}, L{Object} )
     """
     reply = self.replyfilter(reply)
     sax = Parser()
     replyroot = sax.parse(string=reply)
     plugins = PluginContainer(self.options().plugins)
     plugins.message.parsed(reply=replyroot)
     soapenv = replyroot.getChild('Envelope')
     soapenv.promotePrefixes()
     soapbody = soapenv.getChild('Body')
     self.detect_fault(soapbody)
     soapbody = self.multiref.process(soapbody)
     nodes = self.replycontent(method, soapbody)
     rtypes = self.returned_types(method)
     if len(rtypes) > 1:
         result = self.replycomposite(rtypes, nodes)
         return (replyroot, result)
     if len(rtypes) == 1:
         if rtypes[0].multi_occurrence():
             result = self.replylist(rtypes[0], nodes)
             return (replyroot, result)
         if len(nodes):
             unmarshaller = self.unmarshaller()
             resolved = rtypes[0].resolve(nobuiltin=True)
             result = unmarshaller.process(nodes[0], resolved)
             return (replyroot, result)
     return (replyroot, None)
示例#14
0
 def send(self, soapenv):
     """
     Send soap message.
     @param soapenv: A soap envelope to send.
     @type soapenv: L{Document}
     @return: The reply to the sent message.
     @rtype: I{builtin} or I{subclass of} L{Object}
     """
     location = self.location()
     log.debug('sending to (%s)\nmessage:\n%s', location, soapenv)
     original_soapenv = soapenv
     plugins = PluginContainer(self.options.plugins)
     plugins.message.marshalled(envelope=soapenv.root())
     if self.options.prettyxml:
         soapenv = soapenv.str()
     else:
         soapenv = soapenv.plain()
     soapenv = soapenv.encode('utf-8')
     ctx = plugins.message.sending(envelope=soapenv)
     soapenv = ctx.envelope
     if self.options.nosend:
         return RequestContext(self, soapenv, original_soapenv)
     request = Request(location, soapenv)
     request.headers = self.headers()
     try:
         timer = metrics.Timer()
         timer.start()
         reply = self.options.transport.send(request)
         timer.stop()
         metrics.log.debug('waited %s on server reply', timer)
     except TransportError as e:
         content = e.fp and e.fp.read() or ''
         return self.process_reply(reply=content,
                                   status=e.httpcode,
                                   description=tostr(e),
                                   original_soapenv=original_soapenv)
     return self.process_reply(reply=reply.message,
                               original_soapenv=original_soapenv)
示例#15
0
 def __init__(self, url, **kwargs):
     """
     @param url: The URL for the WSDL.
     @type url: str
     @param kwargs: keyword arguments.
     @see: L{Options}
     """
     options = Options()
     options.transport = HttpAuthenticated()
     self.options = options
     options.cache = ObjectCache(days=1)
     self.set_options(**kwargs)
     reader = DefinitionsReader(options, Definitions)
     self.wsdl = reader.open(url)
     plugins = PluginContainer(options.plugins)
     plugins.init.initialized(wsdl=self.wsdl)
     self.factory = Factory(self.wsdl)
     self.service = ServiceSelector(self, self.wsdl.services)
     self.sd = []
     for s in self.wsdl.services:
         sd = ServiceDefinition(self.wsdl, s)
         self.sd.append(sd)
     self.messages = dict(tx=None, rx=None)
示例#16
0
 def succeeded(self, binding, reply):
     """
     Request succeeded, process the reply
     @param binding: The binding to be used to process the reply.
     @type binding: L{bindings.binding.Binding}
     @param reply: The raw reply text.
     @type reply: str
     @return: The method result.
     @rtype: I{builtin}, L{Object}
     @raise WebFault: On server.
     """
     log.debug('http succeeded:\n%s', reply)
     plugins = PluginContainer(self.options.plugins)
     if len(reply) > 0:
         reply, result = binding.get_reply(self.method, reply)
         self.last_received(reply)
     else:
         result = None
     ctx = plugins.message.unmarshalled(reply=result)
     result = ctx.reply
     if self.options.faults:
         return result
     else:
         return (200, result)
示例#17
0
    def process_reply(self,
                      reply,
                      status=None,
                      description=None,
                      original_soapenv=None):
        if status is None:
            status = http.client.OK
        if status in (http.client.ACCEPTED, http.client.NO_CONTENT):
            return
        failed = True
        try:
            if status == http.client.OK:
                log.debug('HTTP succeeded:\n%s', reply)
            else:
                log.debug('HTTP failed - %d - %s:\n%s', status, description,
                          reply)

            # (todo)
            #   Consider whether and how to allow plugins to handle error,
            # httplib.ACCEPTED & httplib.NO_CONTENT replies as well as
            # successful ones.
            #                                 (todo) (27.03.2013.) (Jurko)
            plugins = PluginContainer(self.options.plugins)
            ctx = plugins.message.received(reply=reply)
            reply = ctx.reply

            # SOAP standard states that SOAP errors must be accompanied by HTTP
            # status code 500 - internal server error:
            #
            # From SOAP 1.1 Specification:
            #   In case of a SOAP error while processing the request, the SOAP
            # HTTP server MUST issue an HTTP 500 "Internal Server Error"
            # response and include a SOAP message in the response containing a
            # SOAP Fault element (see section 4.4) indicating the SOAP
            # processing error.
            #
            # From WS-I Basic profile:
            #   An INSTANCE MUST use a "500 Internal Server Error" HTTP status
            # code if the response message is a SOAP Fault.
            replyroot = None
            if status in (http.client.OK, http.client.INTERNAL_SERVER_ERROR):
                replyroot = _parse(reply)
                plugins.message.parsed(reply=replyroot)
                fault = self.get_fault(replyroot)
                if fault:
                    if status != http.client.INTERNAL_SERVER_ERROR:
                        log.warn(
                            "Web service reported a SOAP processing "
                            "fault using an unexpected HTTP status code %d. "
                            "Reporting as an internal server error.", status)
                    if self.options.faults:
                        raise WebFault(fault, replyroot)
                    return (http.client.INTERNAL_SERVER_ERROR, fault)
            if status != http.client.OK:
                if self.options.faults:
                    # (todo)
                    #   Use a more specific exception class here.
                    #                         (27.03.2013.) (Jurko)
                    raise Exception((status, description))
                return (status, description)

            if self.options.retxml:
                failed = False
                return reply

            result = replyroot and self.method.binding.output.get_reply(
                self.method, replyroot)
            ctx = plugins.message.unmarshalled(reply=result)
            result = ctx.reply
            failed = False
            if self.options.faults:
                return result
            return (http.client.OK, result)
        finally:
            if failed and original_soapenv:
                log.error(original_soapenv)
示例#18
0
    def process_reply(self, reply, status, description):
        """
        Process a web service operation SOAP reply.

        Depending on how the ``retxml`` option is set, may return the SOAP
        reply XML or process it and return the Python object representing the
        returned value.

        @param reply: The SOAP reply envelope.
        @type reply: I{bytes}
        @param status: The HTTP status code (None indicates httplib.OK).
        @type status: int|I{None}
        @param description: Additional status description.
        @type description: str
        @return: The invoked web service operation return value.
        @rtype: I{builtin}|I{subclass of} L{Object}|I{bytes}|I{None}

        """
        if status is None:
            status = http.client.OK
        debug_message = "Reply HTTP status - %d" % (status, )
        if status in (http.client.ACCEPTED, http.client.NO_CONTENT):
            log.debug(debug_message)
            return
        # TODO: Consider whether and how to allow plugins to handle error,
        # httplib.ACCEPTED & httplib.NO_CONTENT replies as well as successful
        # ones.
        if status == http.client.OK:
            log.debug("%s\n%s", debug_message, reply)
        else:
            log.debug("%s - %s\n%s", debug_message, description, reply)

        plugins = PluginContainer(self.options.plugins)
        ctx = plugins.message.received(reply=reply)
        reply = ctx.reply

        # SOAP standard states that SOAP errors must be accompanied by HTTP
        # status code 500 - internal server error:
        #
        # From SOAP 1.1 specification:
        #   In case of a SOAP error while processing the request, the SOAP HTTP
        # server MUST issue an HTTP 500 "Internal Server Error" response and
        # include a SOAP message in the response containing a SOAP Fault
        # element (see section 4.4) indicating the SOAP processing error.
        #
        # From WS-I Basic profile:
        #   An INSTANCE MUST use a "500 Internal Server Error" HTTP status code
        # if the response message is a SOAP Fault.
        replyroot = None
        if status in (http.client.OK, http.client.INTERNAL_SERVER_ERROR):
            replyroot = _parse(reply)
            plugins.message.parsed(reply=replyroot)
            fault = self.__get_fault(replyroot)
            if fault:
                if status != http.client.INTERNAL_SERVER_ERROR:
                    log.warn(
                        "Web service reported a SOAP processing fault "
                        "using an unexpected HTTP status code %d. Reporting "
                        "as an internal server error.", status)
                if self.options.faults:
                    raise WebFault(fault, replyroot)
                return http.client.INTERNAL_SERVER_ERROR, fault
        if status != http.client.OK:
            if self.options.faults:
                # TODO: Use a more specific exception class here.
                raise Exception((status, description))
            return status, description

        if self.options.retxml:
            return reply

        result = replyroot and self.method.binding.output.get_reply(
            self.method, replyroot)
        ctx = plugins.message.unmarshalled(reply=result)
        result = ctx.reply
        if self.options.faults:
            return result
        return http.client.OK, result