Ejemplo n.º 1
0
def test_errback_cancel_exception(framework):
    '''
    reject a future with a CancelledError
    '''
    f = txaio.create_future()
    errors = []

    def err(f):
        errors.append(f)

    txaio.add_callbacks(f, None, err)
    txaio.cancel(f, msg="future cancelled")

    run_once()

    assert len(errors) == 1
    assert isinstance(errors[0], txaio.IFailedFuture)
    tb = txaio.failure_format_traceback(errors[0])

    assert 'CancelledError' in tb
    if txaio.using_asyncio and sys.version_info >= (3, 9):
        assert txaio.failure_message(
            errors[0]) == 'CancelledError: future cancelled'
        assert 'future cancelled' in str(errors[0])
    else:
        assert txaio.failure_message(errors[0]) == 'CancelledError: '
Ejemplo n.º 2
0
            def handle_connect_error(fail):
                unrecoverable_error = False

                # FIXME - make txaio friendly
                # Can connect_f ever be in a cancelled state?
                # if txaio.using_asyncio and isinstance(fail.value, asyncio.CancelledError):
                #     unrecoverable_error = True

                self.log.debug(u'component failed: {error}',
                               error=txaio.failure_message(fail))
                self.log.debug(u'{tb}',
                               tb=txaio.failure_format_traceback(fail))
                # If this is a "fatal error" that will never work,
                # we bail out now
                if isinstance(fail.value, ApplicationError):
                    if fail.value.error in [
                            u'wamp.error.no_such_realm',
                            u'wamp.error.no_auth_method'
                    ]:
                        unrecoverable_error = True
                        self.log.error(u"Fatal error, not reconnecting")

                    self.log.error(u"{msg}", msg=fail.value.error_message())

                elif isinstance(fail.value, OSError):
                    # failed to connect entirely, like nobody
                    # listening etc.
                    self.log.info(u"Connection failed: {msg}",
                                  msg=txaio.failure_message(fail))

                elif self._is_ssl_error(fail.value):
                    # Quoting pyOpenSSL docs: "Whenever
                    # [SSL.Error] is raised directly, it has a
                    # list of error messages from the OpenSSL
                    # error queue, where each item is a tuple
                    # (lib, function, reason). Here lib, function
                    # and reason are all strings, describing where
                    # and what the problem is. See err(3) for more
                    # information."
                    self.log.error(u"TLS failure: {reason}",
                                   reason=fail.value.args[1])
                    self.log.error(u"Marking this transport as failed")
                    transport_candidate[0].failed()
                else:
                    # This is some unknown failure, e.g. could
                    # be SyntaxError etc so we're aborting the
                    # whole mission
                    self.log.error(
                        u'Connection failed: {error}',
                        error=txaio.failure_message(fail),
                    )
                    unrecoverable_error = True

                if unrecoverable_error:
                    txaio.reject(done_f, fail)
                    return

                txaio.call_later(0, transport_check, None)
                return
Ejemplo n.º 3
0
                    def connect_error(fail):
                        if isinstance(fail.value, asyncio.CancelledError):
                            reconnect[0] = False
                            txaio.reject(done_f, fail)
                            return

                        self.log.debug(u'component failed: {error}',
                                       error=txaio.failure_message(fail))
                        self.log.debug(u'{tb}',
                                       tb=txaio.failure_format_traceback(fail))
                        # If this is a "fatal error" that will never work,
                        # we bail out now
                        if isinstance(fail.value, ApplicationError):
                            if fail.value.error in [
                                    u'wamp.error.no_such_realm'
                            ]:
                                reconnect[0] = False
                                self.log.error(
                                    u"Fatal error, not reconnecting")
                                txaio.reject(done_f, fail)
                                return

                            self.log.error(u"{msg}",
                                           msg=fail.value.error_message())
                            return one_reconnect_loop(None)

                        elif isinstance(fail.value, OSError):
                            # failed to connect entirely, like nobody
                            # listening etc.
                            self.log.info(u"Connection failed: {msg}",
                                          msg=txaio.failure_message(fail))
                            return one_reconnect_loop(None)

                        elif _is_ssl_error(fail.value):
                            # Quoting pyOpenSSL docs: "Whenever
                            # [SSL.Error] is raised directly, it has a
                            # list of error messages from the OpenSSL
                            # error queue, where each item is a tuple
                            # (lib, function, reason). Here lib, function
                            # and reason are all strings, describing where
                            # and what the problem is. See err(3) for more
                            # information."
                            self.log.error(u"TLS failure: {reason}",
                                           reason=fail.value.args[1])
                            self.log.error(u"Marking this transport as failed")
                            transport.failed()
                        else:
                            self.log.error(
                                u'Connection failed: {error}',
                                error=txaio.failure_message(fail),
                            )
                            # some types of errors should probably have
                            # stacktraces logged immediately at error
                            # level, e.g. SyntaxError?
                            self.log.debug(
                                u'{tb}',
                                tb=txaio.failure_format_traceback(fail))
                            return one_reconnect_loop(None)
Ejemplo n.º 4
0
            def handle_connect_error(fail):
                # FIXME - make txaio friendly
                # Can connect_f ever be in a cancelled state?
                # if txaio.using_asyncio and isinstance(fail.value, asyncio.CancelledError):
                #     unrecoverable_error = True

                self.log.debug(u'component failed: {error}',
                               error=txaio.failure_message(fail))
                self.log.debug(u'{tb}',
                               tb=txaio.failure_format_traceback(fail))
                # If this is a "fatal error" that will never work,
                # we bail out now
                if isinstance(fail.value, ApplicationError):
                    self.log.error(u"{msg}", msg=fail.value.error_message())

                elif isinstance(fail.value, OSError):
                    # failed to connect entirely, like nobody
                    # listening etc.
                    self.log.info(u"Connection failed: {msg}",
                                  msg=txaio.failure_message(fail))

                elif self._is_ssl_error(fail.value):
                    # Quoting pyOpenSSL docs: "Whenever
                    # [SSL.Error] is raised directly, it has a
                    # list of error messages from the OpenSSL
                    # error queue, where each item is a tuple
                    # (lib, function, reason). Here lib, function
                    # and reason are all strings, describing where
                    # and what the problem is. See err(3) for more
                    # information."
                    # (and 'args' is a 1-tuple containing the above
                    # 3-tuple...)
                    ssl_lib, ssl_func, ssl_reason = fail.value.args[0][0]
                    self.log.error(u"TLS failure: {reason}", reason=ssl_reason)
                else:
                    self.log.error(
                        u'Connection failed: {error}',
                        error=txaio.failure_message(fail),
                    )

                if self._is_fatal is None:
                    is_fatal = False
                else:
                    is_fatal = self._is_fatal(fail.value)
                if is_fatal:
                    self.log.info("Error was fatal; failing transport")
                    transport_candidate[0].failed()

                txaio.call_later(0, transport_check, None)
                return
                    def connect_error(fail):
                        if isinstance(fail.value, asyncio.CancelledError):
                            reconnect[0] = False
                            txaio.reject(done_f, fail)
                            return

                        self.log.debug(u'component failed: {error}', error=txaio.failure_message(fail))
                        self.log.debug(u'{tb}', tb=txaio.failure_format_traceback(fail))
                        # If this is a "fatal error" that will never work,
                        # we bail out now
                        if isinstance(fail.value, ApplicationError):
                            if fail.value.error in [u'wamp.error.no_such_realm']:
                                reconnect[0] = False
                                self.log.error(u"Fatal error, not reconnecting")
                                txaio.reject(done_f, fail)
                                return

                            self.log.error(u"{msg}", msg=fail.value.error_message())
                            return one_reconnect_loop(None)

                        elif isinstance(fail.value, OSError):
                            # failed to connect entirely, like nobody
                            # listening etc.
                            self.log.info(u"Connection failed: {msg}", msg=txaio.failure_message(fail))
                            return one_reconnect_loop(None)

                        elif _is_ssl_error(fail.value):
                            # Quoting pyOpenSSL docs: "Whenever
                            # [SSL.Error] is raised directly, it has a
                            # list of error messages from the OpenSSL
                            # error queue, where each item is a tuple
                            # (lib, function, reason). Here lib, function
                            # and reason are all strings, describing where
                            # and what the problem is. See err(3) for more
                            # information."
                            self.log.error(u"TLS failure: {reason}", reason=fail.value.args[1])
                            self.log.error(u"Marking this transport as failed")
                            transport.failed()
                        else:
                            self.log.error(
                                u'Connection failed: {error}',
                                error=txaio.failure_message(fail),
                            )
                            # some types of errors should probably have
                            # stacktraces logged immediately at error
                            # level, e.g. SyntaxError?
                            self.log.debug(u'{tb}', tb=txaio.failure_format_traceback(fail))
                            return one_reconnect_loop(None)
Ejemplo n.º 6
0
def test_errback_without_except(framework):
    '''
    Create a failure without an except block
    '''
    f = txaio.create_future()
    exception = RuntimeError("it failed")
    errors = []

    def err(f):
        errors.append(f)

    txaio.add_callbacks(f, None, err)
    fail = txaio.create_failure(exception)
    txaio.reject(f, fail)

    run_once()

    assert len(errors) == 1
    assert isinstance(errors[0], txaio.IFailedFuture)
    tb = txaio.failure_format_traceback(errors[0])

    assert 'RuntimeError' in tb
    assert 'it failed' in tb
    assert txaio.failure_message(errors[0]) == 'RuntimeError: it failed'
    assert 'it failed' in str(errors[0])
Ejemplo n.º 7
0
 def send(self, msg):
     """
     Implements :func:`autobahn.wamp.interfaces.ITransport.send`
     """
     if self.isOpen():
         try:
             self.log.debug(
                 "WampLongPoll: TX {octets}",
                 octets=_LazyHexFormatter(msg),
             )
             payload, isBinary = self._serializer.serialize(msg)
         except Exception as e:
             # all exceptions raised from above should be serialization errors ..
             f = create_failure()
             self.log.error(
                 "Unable to serialize WAMP application payload: {msg}",
                 msg=failure_message(f),
             )
             self.log.debug("{tb}", tb=failure_format_traceback(f))
             raise SerializationError(
                 "unable to serialize WAMP application payload ({0})".
                 format(e))
         else:
             self._receive.queue(payload)
     else:
         raise TransportLost()
Ejemplo n.º 8
0
                        def error(err):
                            errmsg = txaio.failure_message(err)
                            try:
                                self.onUserError(err, errmsg)
                            except:
                                pass
                            formatted_tb = None
                            if self.traceback_app:
                                formatted_tb = txaio.failure_format_traceback(
                                    err)

                            del self._invocations[msg.request]

                            reply = self._message_from_exception(
                                message.Invocation.MESSAGE_TYPE,
                                msg.request,
                                err.value,
                                formatted_tb,
                            )

                            try:
                                self._transport.send(reply)
                            except SerializationError as e:
                                # the application-level payload returned from the invoked procedure can't be serialized
                                reply = message.Error(
                                    message.Invocation.MESSAGE_TYPE,
                                    msg.request,
                                    ApplicationError.INVALID_PAYLOAD,
                                    args=[
                                        u'error return value from invoked procedure "{0}" could not be serialized: {1}'
                                        .format(registration.procedure, e)
                                    ])
                                self._transport.send(reply)
                            # we have handled the error, so we eat it
                            return None
Ejemplo n.º 9
0
def test_errback(framework):
    f = txaio.create_future()
    exception = RuntimeError("it failed")
    errors = []

    def err(f):
        errors.append(f)
    txaio.add_callbacks(f, None, err)
    try:
        raise exception
    except:
        fail = txaio.create_failure()
    txaio.reject(f, fail)

    run_once()

    assert len(errors) == 1
    assert isinstance(errors[0], txaio.IFailedFuture)
    assert exception == errors[0].value
    assert txaio.failure_traceback(errors[0]) is not None

    tb = txaio.failure_format_traceback(errors[0])

    assert 'RuntimeError' in tb
    assert 'it failed' in tb
    assert txaio.failure_message(errors[0]) == 'RuntimeError: it failed'
    assert 'it failed' in str(errors[0])
Ejemplo n.º 10
0
 def component_failure(comp, f):
     log.error("Component '{c}' error: {msg}", c=comp, msg=txaio.failure_message(f))
     log.debug("Component error: {tb}", tb=txaio.failure_format_traceback(f))
     # double-check: is a component-failure still fatal to the
     # startup process (because we passed consume_exception=False
     # to gather() below?)
     return None
Ejemplo n.º 11
0
 def component_failure(comp, f):
     log.error("Component '{c}' error: {msg}", c=comp, msg=txaio.failure_message(f))
     log.debug("Component error: {tb}", tb=txaio.failure_format_traceback(f))
     # double-check: is a component-failure still fatal to the
     # startup process (because we passed consume_exception=False
     # to gather() below?)
     return None
Ejemplo n.º 12
0
                        def error(err):
                            errmsg = txaio.failure_message(err)
                            try:
                                self.onUserError(err, errmsg)
                            except:
                                pass
                            formatted_tb = None
                            if self.traceback_app:
                                formatted_tb = txaio.failure_format_traceback(err)

                            del self._invocations[msg.request]

                            reply = self._message_from_exception(
                                message.Invocation.MESSAGE_TYPE,
                                msg.request,
                                err.value,
                                formatted_tb,
                            )

                            try:
                                self._transport.send(reply)
                            except SerializationError as e:
                                # the application-level payload returned from the invoked procedure can't be serialized
                                reply = message.Error(message.Invocation.MESSAGE_TYPE, msg.request, ApplicationError.INVALID_PAYLOAD,
                                                      args=[u'error return value from invoked procedure "{0}" could not be serialized: {1}'.format(registration.procedure, e)])
                                self._transport.send(reply)
                            # we have handled the error, so we eat it
                            return None
Ejemplo n.º 13
0
def test_errback(framework):
    f = txaio.create_future()
    exception = RuntimeError("it failed")
    errors = []

    def err(f):
        errors.append(f)
    txaio.add_callbacks(f, None, err)
    try:
        raise exception
    except:
        fail = txaio.create_failure()
    txaio.reject(f, fail)

    run_once()

    assert len(errors) == 1
    assert isinstance(errors[0], txaio.IFailedFuture)
    assert exception == errors[0].value
    assert txaio.failure_traceback(errors[0]) is not None

    tb = txaio.failure_format_traceback(errors[0])

    assert 'RuntimeError' in tb
    assert 'it failed' in tb
    assert txaio.failure_message(errors[0]) == 'RuntimeError: it failed'
    assert 'it failed' in str(errors[0])
Ejemplo n.º 14
0
    def render_POST(self, request):
        """
        A client sends a message via WAMP-over-Longpoll by HTTP/POSTing
        to this Web resource. The body of the POST should contain a batch
        of WAMP messages which are serialized according to the selected
        serializer, and delimited by a single ``\0`` byte in between two WAMP
        messages in the batch.
        """
        payload = request.content.read()
        self.log.debug(
            "WampLongPoll: receiving data for transport '{tid}'\n{octets}",
            tid=self._parent._transport_id,
            octets=_LazyHexFormatter(payload),
        )

        try:
            # process (batch of) WAMP message(s)
            self._parent.onMessage(payload, None)

        except Exception:
            f = create_failure()
            self.log.error(
                "Could not unserialize WAMP message: {msg}",
                msg=failure_message(f),
            )
            self.log.debug("{tb}", tb=failure_format_traceback(f))
            return self._parent._parent._fail_request(
                request, b"could not unserialize WAMP message.")

        else:
            request.setResponseCode(http.NO_CONTENT)
            self._parent._parent._set_standard_headers(request)
            self._parent._isalive = True
            return b""
Ejemplo n.º 15
0
def test_errback_reject_no_args():
    """
    txaio.reject() with no args
    """

    f = txaio.create_future()
    exception = RuntimeError("it failed")
    errors = []

    def err(f):
        errors.append(f)
    txaio.add_callbacks(f, None, err)
    try:
        raise exception
    except:
        txaio.reject(f)

    run_once()

    assert len(errors) == 1
    assert isinstance(errors[0], txaio.IFailedFuture)
    assert exception == errors[0].value
    tb = txaio.failure_format_traceback(errors[0])

    assert 'RuntimeError' in tb
    assert 'it failed' in tb
    assert txaio.failure_message(errors[0]) == 'RuntimeError: it failed'
    assert 'it failed' in str(errors[0])
Ejemplo n.º 16
0
            def handle_connect_error(fail):
                # FIXME - make txaio friendly
                # Can connect_f ever be in a cancelled state?
                # if txaio.using_asyncio and isinstance(fail.value, asyncio.CancelledError):
                #     unrecoverable_error = True

                self.log.debug(u'component failed: {error}', error=txaio.failure_message(fail))
                self.log.debug(u'{tb}', tb=txaio.failure_format_traceback(fail))
                # If this is a "fatal error" that will never work,
                # we bail out now
                if isinstance(fail.value, ApplicationError):
                    self.log.error(u"{msg}", msg=fail.value.error_message())

                elif isinstance(fail.value, OSError):
                    # failed to connect entirely, like nobody
                    # listening etc.
                    self.log.info(u"Connection failed: {msg}", msg=txaio.failure_message(fail))

                elif self._is_ssl_error(fail.value):
                    # Quoting pyOpenSSL docs: "Whenever
                    # [SSL.Error] is raised directly, it has a
                    # list of error messages from the OpenSSL
                    # error queue, where each item is a tuple
                    # (lib, function, reason). Here lib, function
                    # and reason are all strings, describing where
                    # and what the problem is. See err(3) for more
                    # information."
                    # (and 'args' is a 1-tuple containing the above
                    # 3-tuple...)
                    ssl_lib, ssl_func, ssl_reason = fail.value.args[0][0]
                    self.log.error(u"TLS failure: {reason}", reason=ssl_reason)
                else:
                    self.log.error(
                        u'Connection failed: {error}',
                        error=txaio.failure_message(fail),
                    )

                if self._is_fatal is None:
                    is_fatal = False
                else:
                    is_fatal = self._is_fatal(fail.value)
                if is_fatal:
                    self.log.info("Error was fatal; failing transport")
                    transport_candidate[0].failed()

                txaio.call_later(0, transport_check, None)
                return
Ejemplo n.º 17
0
 def error(fail):
     self._delay_f = None
     if self._stopping:
         # might be better to add framework-specific checks in
         # subclasses to see if this is CancelledError (for
         # Twisted) and whatever asyncio does .. but tracking
         # if we're in the shutdown path is fine too
         txaio.resolve(self._done_f, None)
     else:
         self.log.info("Internal error {msg}", msg=txaio.failure_message(fail))
         self.log.debug("{tb}", tb=txaio.failure_format_traceback(fail))
         txaio.reject(self._done_f, fail)
Ejemplo n.º 18
0
 def error(fail):
     self._delay_f = None
     if self._stopping:
         # might be better to add framework-specific checks in
         # subclasses to see if this is CancelledError (for
         # Twisted) and whatever asyncio does .. but tracking
         # if we're in the shutdown path is fine too
         txaio.resolve(self._done_f, None)
     else:
         self.log.info("Internal error {msg}", msg=txaio.failure_message(fail))
         self.log.debug("{tb}", tb=txaio.failure_format_traceback(fail))
         txaio.reject(self._done_f, fail)
Ejemplo n.º 19
0
def test_errback_plain_exception(framework):
    '''
    reject a future with just an Exception
    '''
    f = txaio.create_future()
    exception = RuntimeError("it failed")
    errors = []

    def err(f):
        errors.append(f)
    txaio.add_callbacks(f, None, err)
    txaio.reject(f, exception)

    run_once()

    assert len(errors) == 1
    assert isinstance(errors[0], txaio.IFailedFuture)
    tb = txaio.failure_format_traceback(errors[0])

    assert 'RuntimeError' in tb
    assert 'it failed' in tb
    assert txaio.failure_message(errors[0]) == 'RuntimeError: it failed'
    assert 'it failed' in str(errors[0])
Ejemplo n.º 20
0
    def render_POST(self, request):
        """
        A client sends a message via WAMP-over-Longpoll by HTTP/POSTing
        to this Web resource. The body of the POST should contain a batch
        of WAMP messages which are serialized according to the selected
        serializer, and delimited by a single ``\0`` byte in between two WAMP
        messages in the batch.
        """
        payload = request.content.read()
        self.log.debug(
            "WampLongPoll: receiving data for transport '{tid}'\n{octets}",
            tid=self._parent._transport_id,
            octets=_LazyHexFormatter(payload),
        )

        try:
            # process (batch of) WAMP message(s)
            self._parent.onMessage(payload, None)

        except Exception:
            f = create_failure()
            self.log.error(
                "Could not unserialize WAMP message: {msg}",
                msg=failure_message(f),
            )
            self.log.debug("{tb}", tb=failure_format_traceback(f))
            return self._parent._parent._fail_request(
                request,
                b"could not unserialize WAMP message."
            )

        else:
            request.setResponseCode(http.NO_CONTENT)
            self._parent._parent._set_standard_headers(request)
            self._parent._isalive = True
            return b""
Ejemplo n.º 21
0
 def send(self, msg):
     """
     Implements :func:`autobahn.wamp.interfaces.ITransport.send`
     """
     if self.isOpen():
         try:
             self.log.debug(
                 "WampLongPoll: TX {octets}",
                 octets=_LazyHexFormatter(msg),
             )
             payload, isBinary = self._serializer.serialize(msg)
         except Exception as e:
             # all exceptions raised from above should be serialization errors ..
             f = create_failure()
             self.log.error(
                 "Unable to serialize WAMP application payload: {msg}",
                 msg=failure_message(f),
             )
             self.log.debug("{tb}", tb=failure_format_traceback(f))
             raise SerializationError("unable to serialize WAMP application payload ({0})".format(e))
         else:
             self._receive.queue(payload)
     else:
         raise TransportLost()
Ejemplo n.º 22
0
def test_errback_without_except():
    '''
    Create a failure without an except block
    '''
    f = txaio.create_future()
    exception = RuntimeError("it failed")
    errors = []

    def err(f):
        errors.append(f)
    txaio.add_callbacks(f, None, err)
    fail = txaio.create_failure(exception)
    txaio.reject(f, fail)

    run_once()

    assert len(errors) == 1
    assert isinstance(errors[0], txaio.IFailedFuture)
    tb = txaio.failure_format_traceback(errors[0])

    assert 'RuntimeError' in tb
    assert 'it failed' in tb
    assert txaio.failure_message(errors[0]) == 'RuntimeError: it failed'
    assert 'it failed' in str(errors[0])
Ejemplo n.º 23
0
    def render_POST(self, request):
        """
        Request to create a new WAMP session.
        """
        self.log.debug("WampLongPoll: creating new session ..")

        payload = request.content.read().decode('utf8')
        try:
            options = json.loads(payload)
        except Exception:
            f = create_failure()
            self.log.error(
                "Couldn't parse WAMP request body: {msg}",
                msg=failure_message(f),
            )
            self.log.debug("{msg}", msg=failure_format_traceback(f))
            return self._parent._fail_request(
                request, b"could not parse WAMP session open request body")

        if not isinstance(options, dict):
            return self._parent._fail_request(
                request, b"invalid type for WAMP session open request")

        if 'protocols' not in options:
            return self._parent._fail_request(
                request,
                "missing attribute 'protocols' in WAMP session open request")

        # determine the protocol to speak
        #
        protocol = None
        serializer = None
        for p in options['protocols']:
            version, serializerId = parseSubprotocolIdentifier(p)
            if version == 2 and serializerId in self._parent._serializers.keys(
            ):
                serializer = self._parent._serializers[serializerId]
                protocol = p
                break

        if protocol is None:
            return self._fail_request(
                request, b"no common protocol to speak (I speak: {0})".format([
                    "wamp.2.{0}".format(s)
                    for s in self._parent._serializers.keys()
                ]))

        # make up new transport ID
        #
        if self._parent._debug_transport_id:
            # use fixed transport ID for debugging purposes
            transport = self._parent._debug_transport_id
        else:
            transport = generate_token(1, 12)

        # this doesn't contain all the info (when a header key appears multiple times)
        # http_headers_received = request.getAllHeaders()
        http_headers_received = {}
        for key, values in request.requestHeaders.getAllRawHeaders():
            if key not in http_headers_received:
                http_headers_received[key] = []
            http_headers_received[key].extend(values)

        transport_details = {
            'transport': transport,
            'serializer': serializer,
            'protocol': protocol,
            'peer': request.getClientIP(),
            'http_headers_received': http_headers_received,
            'http_headers_sent': None
        }

        # create instance of WampLongPollResourceSession or subclass thereof ..
        #
        self._parent._transports[transport] = self._parent.protocol(
            self._parent, transport_details)

        # create response
        #
        self._parent._set_standard_headers(request)
        request.setHeader(b'content-type', b'application/json; charset=utf-8')

        result = {'transport': transport, 'protocol': protocol}

        self.log.debug("WampLongPoll: new session created on transport"
                       " '{transport}'".format(transport=transport, ))

        payload = json.dumps(result)
        return payload.encode()
Ejemplo n.º 24
0
    def start(self, reactor=None):
        """
        This starts the Component, which means it will start connecting
        (and re-connecting) to its configured transports. A Component
        runs until it is "done", which means one of:

        - There was a "main" function defined, and it completed successfully;
        - Something called ``.leave()`` on our session, and we left successfully;
        - ``.stop()`` was called, and completed successfully;
        - none of our transports were able to connect successfully (failure);

        :returns: a Deferred that fires (with ``None``) when we are
            "done" or with a Failure if something went wrong.
        """
        if reactor is None:
            self.log.warn("Using default reactor")
            from twisted.internet import reactor

        yield self.fire('start', reactor, self)

        # transports to try again and again ..
        transport_gen = itertools.cycle(self._transports)

        reconnect = True

        self.log.debug('Entering re-connect loop')

        while reconnect:
            # cycle through all transports forever ..
            transport = next(transport_gen)

            # only actually try to connect using the transport,
            # if the transport hasn't reached max. connect count
            if transport.can_reconnect():
                delay = transport.next_delay()
                self.log.debug(
                    'trying transport {transport_idx} using connect delay {transport_delay}',
                    transport_idx=transport.idx,
                    transport_delay=delay,
                )
                yield sleep(delay)
                try:
                    transport.connect_attempts += 1
                    yield self._connect_once(reactor, transport)
                    transport.connect_sucesses += 1
                except Exception as e:
                    transport.connect_failures += 1
                    f = txaio.create_failure()
                    self.log.error(u'component failed: {error}',
                                   error=txaio.failure_message(f))
                    self.log.debug(u'{tb}',
                                   tb=txaio.failure_format_traceback(f))
                    # If this is a "fatal error" that will never work,
                    # we bail out now
                    if isinstance(e, ApplicationError):
                        if e.error in [u'wamp.error.no_such_realm']:
                            reconnect = False
                            self.log.error(u"Fatal error, not reconnecting")
                            # The thinking here is that we really do
                            # want to 'raise' (and thereby fail the
                            # entire "start" / reconnect loop) because
                            # if the realm isn't valid, we're "never"
                            # going to succeed...
                            raise
                        self.log.error(u"{msg}", msg=e.error_message())
                    elif _is_ssl_error(e):
                        # Quoting pyOpenSSL docs: "Whenever
                        # [SSL.Error] is raised directly, it has a
                        # list of error messages from the OpenSSL
                        # error queue, where each item is a tuple
                        # (lib, function, reason). Here lib, function
                        # and reason are all strings, describing where
                        # and what the problem is. See err(3) for more
                        # information."
                        for (lib, fn, reason) in e.args[0]:
                            self.log.error(u"TLS failure: {reason}",
                                           reason=reason)
                        self.log.error(u"Marking this transport as failed")
                        transport.failed()
                    else:
                        f = txaio.create_failure()
                        self.log.error(
                            u'Connection failed: {error}',
                            error=txaio.failure_message(f),
                        )
                        # some types of errors should probably have
                        # stacktraces logged immediately at error
                        # level, e.g. SyntaxError?
                        self.log.debug(u'{tb}',
                                       tb=txaio.failure_format_traceback(f))
                else:
                    self.log.debug(u"Not reconnecting")
                    reconnect = False
            else:
                # check if there is any transport left we can use
                # to connect
                if not self._can_reconnect():
                    self.log.info("No remaining transports to try")
                    reconnect = False
Ejemplo n.º 25
0
 def error(fail):
     self.log.info("Internal error {msg}",
                   msg=txaio.failure_message(fail))
     self.log.debug("{tb}", tb=txaio.failure_format_traceback(fail))
     txaio.reject(done_f, fail)
Ejemplo n.º 26
0
 def component_failure(f):
     log.error("Component error: {msg}", msg=txaio.failure_message(f))
     log.debug("Component error: {tb}", tb=txaio.failure_format_traceback(f))
     return None
Ejemplo n.º 27
0
def test_bad_failures(handler, framework):
    # just ensuring this doesn't explode
    txaio.failure_format_traceback("not a failure")
    txaio.failure_message("not a failure")
Ejemplo n.º 28
0
    def render_POST(self, request):
        """
        Request to create a new WAMP session.
        """
        self.log.debug("WampLongPoll: creating new session ..")

        payload = request.content.read().decode('utf8')
        try:
            options = json.loads(payload)
        except Exception:
            f = create_failure()
            self.log.error(
                "Couldn't parse WAMP request body: {msg}",
                msg=failure_message(f),
            )
            self.log.debug("{msg}", msg=failure_format_traceback(f))
            return self._parent._fail_request(request, b"could not parse WAMP session open request body")

        if type(options) != dict:
            return self._parent._fail_request(request, b"invalid type for WAMP session open request")

        if u'protocols' not in options:
            return self._parent._fail_request(request, "missing attribute 'protocols' in WAMP session open request")

        # determine the protocol to speak
        #
        protocol = None
        serializer = None
        for p in options[u'protocols']:
            version, serializerId = parseSubprotocolIdentifier(p)
            if version == 2 and serializerId in self._parent._serializers.keys():
                serializer = self._parent._serializers[serializerId]
                protocol = p
                break

        if protocol is None:
            return self._fail_request(
                request,
                b"no common protocol to speak (I speak: {0})".format(
                    ["wamp.2.{0}".format(s) for s in self._parent._serializers.keys()])
            )

        # make up new transport ID
        #
        if self._parent._debug_transport_id:
            # use fixed transport ID for debugging purposes
            transport = self._parent._debug_transport_id
        else:
            transport = generate_token(1, 12)

        # this doesn't contain all the info (when a header key appears multiple times)
        # http_headers_received = request.getAllHeaders()
        http_headers_received = {}
        for key, values in request.requestHeaders.getAllRawHeaders():
            if key not in http_headers_received:
                http_headers_received[key] = []
            http_headers_received[key].extend(values)

        transport_details = {
            u'transport': transport,
            u'serializer': serializer,
            u'protocol': protocol,
            u'peer': request.getClientIP(),
            u'http_headers_received': http_headers_received,
            u'http_headers_sent': None
        }

        # create instance of WampLongPollResourceSession or subclass thereof ..
        #
        self._parent._transports[transport] = self._parent.protocol(self._parent, transport_details)

        # create response
        #
        self._parent._set_standard_headers(request)
        request.setHeader(b'content-type', b'application/json; charset=utf-8')

        result = {
            u'transport': transport,
            u'protocol': protocol
        }

        self.log.debug(
            "WampLongPoll: new session created on transport"
            " '{transport}'".format(
                transport=transport,
            )
        )

        payload = json.dumps(result)
        return payload.encode()
Ejemplo n.º 29
0
    def start(self, reactor=None):
        """
        This starts the Component, which means it will start connecting
        (and re-connecting) to its configured transports. A Component
        runs until it is "done", which means one of:

        - There was a "main" function defined, and it completed successfully;
        - Something called ``.leave()`` on our session, and we left successfully;
        - ``.stop()`` was called, and completed successfully;
        - none of our transports were able to connect successfully (failure);

        :returns: a Deferred that fires (with ``None``) when we are
            "done" or with a Failure if something went wrong.
        """
        if reactor is None:
            self.log.warn("Using default reactor")
            from twisted.internet import reactor

        yield self.fire('start', reactor, self)

        # transports to try again and again ..
        transport_gen = itertools.cycle(self._transports)

        reconnect = True
        last_failure = None

        self.log.debug('Entering re-connect loop')

        while reconnect:
            # cycle through all transports forever ..
            transport = next(transport_gen)

            # only actually try to connect using the transport,
            # if the transport hasn't reached max. connect count
            if transport.can_reconnect():
                delay = transport.next_delay()
                self.log.debug(
                    'trying transport {transport_idx} using connect delay {transport_delay}',
                    transport_idx=transport.idx,
                    transport_delay=delay,
                )
                yield sleep(delay)
                try:
                    yield self._connect_once(reactor, transport)
                except Exception as e:
                    f = txaio.create_failure()
                    last_failure = f
                    self.log.error(u'component failed: {error}', error=txaio.failure_message(f))
                    self.log.debug(u'{tb}', tb=txaio.failure_format_traceback(f))
                    # If this is a "fatal error" that will never work,
                    # we bail out now
                    if isinstance(e, ApplicationError):
                        if e.error in [u'wamp.error.no_such_realm', u'wamp.error.no_auth_method']:
                            reconnect = False
                            self.log.error(u"Fatal error, not reconnecting")
                            # The thinking here is that we really do
                            # want to 'raise' (and thereby fail the
                            # entire "start" / reconnect loop) because
                            # if the realm isn't valid, we're "never"
                            # going to succeed...
                            raise
                        self.log.error(u"{msg}", msg=e.error_message())
                    elif _is_ssl_error(e):
                        # Quoting pyOpenSSL docs: "Whenever
                        # [SSL.Error] is raised directly, it has a
                        # list of error messages from the OpenSSL
                        # error queue, where each item is a tuple
                        # (lib, function, reason). Here lib, function
                        # and reason are all strings, describing where
                        # and what the problem is. See err(3) for more
                        # information."
                        for (lib, fn, reason) in e.args[0]:
                            self.log.error(u"TLS failure: {reason}", reason=reason)
                        self.log.error(u"Marking this transport as failed")
                        transport.failed()
                    else:
                        f = txaio.create_failure()
                        self.log.error(
                            u'Connection failed: {error}',
                            error=txaio.failure_message(f),
                        )
                        # some types of errors should probably have
                        # stacktraces logged immediately at error
                        # level, e.g. SyntaxError?
                        self.log.debug(u'{tb}', tb=txaio.failure_format_traceback(f))
                else:
                    self.log.debug(u"Not reconnecting")
                    reconnect = False
            else:
                # check if there is any transport left we can use
                # to connect
                if not self._can_reconnect():
                    self.log.info("No remaining transports to try")
                    reconnect = False
        if last_failure is not None:
            last_failure.raiseException()
Ejemplo n.º 30
0
def test_bad_failures(handler, framework):
    # just ensuring this doesn't explode
    txaio.failure_format_traceback("not a failure")
    txaio.failure_message("not a failure")
 def error(fail):
     self.log.info("Internal error {msg}", msg=txaio.failure_message(fail))
     self.log.debug("{tb}", tb=txaio.failure_format_traceback(fail))
     txaio.reject(done_f, fail)