Example #1
0
    def do_extra_handshake(self, request):
        """Do extra checking in WebSocket handshake.

        Select a handler based on request.uri and call its
        web_socket_do_extra_handshake function.

        Args:
            request: mod_python request.

        Raises:
            DispatchException: when handler was not found
            AbortedByUserException: when user handler abort connection
            HandshakeException: when opening handshake failed
        """

        handler_suite = self.get_handler_suite(request.ws_resource)
        if handler_suite is None:
            raise DispatchException('No handler for: %r' % request.ws_resource)
        do_extra_handshake_ = handler_suite.do_extra_handshake
        try:
            do_extra_handshake_(request)
        except handshake.AbortedByUserException as e:
            # Re-raise to tell the caller of this function to finish this
            # connection without sending any error.
            self._logger.debug('%s', util.get_stack_trace())
            raise
        except Exception as e:
            util.prepend_message_to_exception(
                    '%s raised exception for %s: ' % (
                            _DO_EXTRA_HANDSHAKE_HANDLER_NAME,
                            request.ws_resource),
                    e)
            raise handshake.HandshakeException(e, common.HTTP_STATUS_FORBIDDEN)
Example #2
0
    def transfer_data(self, request):
        """Let a handler transfer_data with a Web Socket client.

        Select a handler based on request.ws_resource and call its
        web_socket_transfer_data function.

        Args:
            request: mod_python request.
        """

        unused_do_extra_handshake, transfer_data_ = self._handler(request)
        try:
            try:
                request.client_terminated = False
                request.server_terminated = False
                transfer_data_(request)
            except msgutil.ConnectionTerminatedException, e:
                util.prepend_message_to_exception(
                    'client initiated closing handshake for %s: ' %
                    (request.ws_resource), e)
                raise
            except Exception, e:
                print 'exception: %s' % type(e)
                util.prepend_message_to_exception(
                    '%s raised exception for %s: ' %
                    (_TRANSFER_DATA_HANDLER_NAME, request.ws_resource), e)
                raise
Example #3
0
    def transfer_data(self, request):
        """Let a handler transfer_data with a Web Socket client.

        Select a handler based on request.ws_resource and call its
        web_socket_transfer_data function.

        Args:
            request: mod_python request.
        """

        unused_do_extra_handshake, transfer_data_ = self._handler(request)
        try:
            try:
                request.client_terminated = False
                request.server_terminated = False
                transfer_data_(request)
            except msgutil.ConnectionTerminatedException, e:
                util.prepend_message_to_exception(
                    'client initiated closing handshake for %s: ' % (
                    request.ws_resource),
                    e)
                raise
            except Exception, e:
                print 'exception: %s' % type(e)
                util.prepend_message_to_exception(
                    '%s raised exception for %s: ' % (
                    _TRANSFER_DATA_HANDLER_NAME, request.ws_resource),
                    e)
                raise
Example #4
0
def _write(request, bytes):
    try:
        request.connection.write(bytes)
    except Exception, e:
        util.prepend_message_to_exception(
            'Failed to send message to %r: ' %
            (request.connection.remote_addr, ), e)
        raise
Example #5
0
    def transfer_data(self, request):
        """Let a handler transfer_data with a WebSocket client.

        Select a handler based on request.ws_resource and call its
        web_socket_transfer_data function.

        Args:
            request: mod_python request.

        Raises:
            DispatchException: when handler was not found
            AbortedByUserException: when user handler abort connection
        """

        # TODO(tyoshino): Terminate underlying TCP connection if possible.
        try:
            if mux.use_mux(request):
                mux.start(request, self)
            else:
                handler_suite = self.get_handler_suite(request.ws_resource)
                if handler_suite is None:
                    raise DispatchException('No handler for: %r' %
                                            request.ws_resource)
                transfer_data_ = handler_suite.transfer_data
                transfer_data_(request)

            if not request.server_terminated:
                request.ws_stream.close_connection()
        # Catch non-critical exceptions the handler didn't handle.
        except handshake.AbortedByUserException as e:
            self._logger.debug('%s', util.get_stack_trace())
            raise
        except msgutil.BadOperationException as e:
            self._logger.debug('%s', e)
            request.ws_stream.close_connection(
                common.STATUS_INTERNAL_ENDPOINT_ERROR)
        except msgutil.InvalidFrameException as e:
            # InvalidFrameException must be caught before
            # ConnectionTerminatedException that catches InvalidFrameException.
            self._logger.debug('%s', e)
            request.ws_stream.close_connection(common.STATUS_PROTOCOL_ERROR)
        except msgutil.UnsupportedFrameException as e:
            self._logger.debug('%s', e)
            request.ws_stream.close_connection(common.STATUS_UNSUPPORTED_DATA)
        except stream.InvalidUTF8Exception as e:
            self._logger.debug('%s', e)
            request.ws_stream.close_connection(
                common.STATUS_INVALID_FRAME_PAYLOAD_DATA)
        except msgutil.ConnectionTerminatedException as e:
            self._logger.debug('%s', e)
        except Exception as e:
            # Any other exceptions are forwarded to the caller of this
            # function.
            util.prepend_message_to_exception(
                '%s raised exception for %s: ' % (
                    _TRANSFER_DATA_HANDLER_NAME, request.ws_resource),
                e)
            raise
Example #6
0
def _write(request, bytes):
    try:
        request.connection.write(bytes)
    except Exception, e:
        util.prepend_message_to_exception(
                'Failed to send message to %r: ' %
                        (request.connection.remote_addr,),
                e)
        raise
Example #7
0
    def _write(self, bytes_to_write):
        """Writes given bytes to connection. In case we catch any exception,
        prepends remote address to the exception message and raise again.
        """

        try:
            self._request.connection.write(bytes_to_write)
        except Exception as e:
            util.prepend_message_to_exception(
                'Failed to send message to %r: ' %
                (self._request.connection.remote_addr, ), e)
            raise
Example #8
0
    def _write(self, bytes):
        """Writes given bytes to connection. In case we catch any exception,
        prepends remote address to the exception message and raise again.
        """

        try:
            self._request.connection.write(bytes)
        except Exception, e:
            util.prepend_message_to_exception(
                    'Failed to send message to %r: ' %
                            (self._request.connection.remote_addr,),
                    e)
            raise
Example #9
0
    def do_extra_handshake(self, request):
        """Do extra checking in Web Socket handshake.

        Select a handler based on request.uri and call its
        web_socket_do_extra_handshake function.

        Args:
            request: mod_python request.
        """

        do_extra_handshake_, unused_transfer_data = self._handler(request)
        try:
            do_extra_handshake_(request)
        except Exception, e:
            util.prepend_message_to_exception(
                '%s raised exception for %s: ' %
                (_DO_EXTRA_HANDSHAKE_HANDLER_NAME, request.ws_resource), e)
            raise
Example #10
0
    def do_extra_handshake(self, request):
        """Do extra checking in Web Socket handshake.

        Select a handler based on request.uri and call its
        web_socket_do_extra_handshake function.

        Args:
            request: mod_python request.
        """

        do_extra_handshake_, unused_transfer_data = self._handler(request)
        try:
            do_extra_handshake_(request)
        except Exception, e:
            util.prepend_message_to_exception(
                    '%s raised exception for %s: ' % (
                            _DO_EXTRA_HANDSHAKE_HANDLER_NAME,
                            request.ws_resource),
                    e)
            raise
Example #11
0
class Dispatcher(object):
    """Dispatches WebSocket requests.

    This class maintains a map from resource name to handlers.
    """
    def __init__(self,
                 root_dir,
                 scan_dir=None,
                 allow_handlers_outside_root_dir=True):
        """Construct an instance.

        Args:
            root_dir: The directory where handler definition files are
                      placed.
            scan_dir: The directory where handler definition files are
                      searched. scan_dir must be a directory under root_dir,
                      including root_dir itself.  If scan_dir is None,
                      root_dir is used as scan_dir. scan_dir can be useful
                      in saving scan time when root_dir contains many
                      subdirectories.
            allow_handlers_outside_root_dir: Scans handler files even if their
                      canonical path is not under root_dir.
        """

        self._logger = util.get_class_logger(self)

        self._handler_suite_map = {}
        self._source_warnings = []
        if scan_dir is None:
            scan_dir = root_dir
        if not os.path.realpath(scan_dir).startswith(
                os.path.realpath(root_dir)):
            raise DispatchException('scan_dir:%s must be a directory under '
                                    'root_dir:%s.' % (scan_dir, root_dir))
        self._source_handler_files_in_dir(root_dir, scan_dir,
                                          allow_handlers_outside_root_dir)

    def add_resource_path_alias(self, alias_resource_path,
                                existing_resource_path):
        """Add resource path alias.

        Once added, request to alias_resource_path would be handled by
        handler registered for existing_resource_path.

        Args:
            alias_resource_path: alias resource path
            existing_resource_path: existing resource path
        """
        try:
            handler_suite = self._handler_suite_map[existing_resource_path]
            self._handler_suite_map[alias_resource_path] = handler_suite
        except KeyError:
            raise DispatchException('No handler for: %r' %
                                    existing_resource_path)

    def source_warnings(self):
        """Return warnings in sourcing handlers."""

        return self._source_warnings

    def do_extra_handshake(self, request):
        """Do extra checking in WebSocket handshake.

        Select a handler based on request.uri and call its
        web_socket_do_extra_handshake function.

        Args:
            request: mod_python request.

        Raises:
            DispatchException: when handler was not found
            AbortedByUserException: when user handler abort connection
            HandshakeException: when opening handshake failed
        """

        handler_suite = self.get_handler_suite(request.ws_resource)
        if handler_suite is None:
            raise DispatchException('No handler for: %r' % request.ws_resource)
        do_extra_handshake_ = handler_suite.do_extra_handshake
        try:
            do_extra_handshake_(request)
        except handshake.AbortedByUserException, e:
            raise
        except Exception, e:
            util.prepend_message_to_exception(
                '%s raised exception for %s: ' %
                (_DO_EXTRA_HANDSHAKE_HANDLER_NAME, request.ws_resource), e)
            raise handshake.HandshakeException(e, common.HTTP_STATUS_FORBIDDEN)
Example #12
0
    got_exception = False
    if not abort:
        _write(request, '\xff\x00')
        # timeout of 20 seconds to get the client's close frame ack
        initial_time = time()
        end_time = initial_time + 20
        while time() < end_time:
            try:
                receive_message(request)
            except ConnectionTerminatedException, e:
                got_exception = True
                sleep(1)
    request.server_terminated = True
    if got_exception:
        util.prepend_message_to_exception(
            'client initiated closing handshake for %s: ' %
            (request.ws_resource), e)
        raise ConnectionTerminatedException
    # TODO: 3. close the WebSocket connection.
    # note: mod_python Connection (mp_conn) doesn't have close method.


def send_message(request, message):
    """Send message.

    Args:
        request: mod_python request.
        message: unicode string to send.
    Raises:
        ConnectionTerminatedException: when server already terminated.
    """
Example #13
0
                self._logger.debug('%s', e)
                request.ws_stream.close_connection(
                    common.STATUS_PROTOCOL_ERROR)
            except msgutil.UnsupportedFrameException, e:
                self._logger.debug('%s', e)
                request.ws_stream.close_connection(
                    common.STATUS_UNSUPPORTED_DATA)
            except stream.InvalidUTF8Exception, e:
                self._logger.debug('%s', e)
                request.ws_stream.close_connection(
                    common.STATUS_INVALID_FRAME_PAYLOAD_DATA)
            except msgutil.ConnectionTerminatedException, e:
                self._logger.debug('%s', e)
            except Exception, e:
                util.prepend_message_to_exception(
                    '%s raised exception for %s: ' %
                    (_TRANSFER_DATA_HANDLER_NAME, request.ws_resource), e)
                raise

        except handshake.AbortedByUserException, e:
            self._logger.info('%s', e)
        return False


def _get_logger_from_class(c):
    return logging.getLogger('%s.%s' % (c.__module__, c.__name__))


def _configure_logging(options):
    logging.addLevelName(common.LOGLEVEL_FINE, 'FINE')
Example #14
0
 def test_prepend_message_to_exception(self):
     exc = Exception('World')
     self.assertEqual('World', str(exc))
     util.prepend_message_to_exception('Hello ', exc)
     self.assertEqual('Hello World', str(exc))
Example #15
0
 def test_prepend_message_to_exception(self):
     exc = Exception('World')
     self.assertEqual('World', str(exc))
     util.prepend_message_to_exception('Hello ', exc)
     self.assertEqual('Hello World', str(exc))
Example #16
0
    got_exception = False
    if not abort:
        _write(request, '\xff\x00')
        # timeout of 20 seconds to get the client's close frame ack
        initial_time = time()
        end_time = initial_time + 20
        while time() < end_time:
            try:
                receive_message(request)
            except ConnectionTerminatedException, e:
                got_exception = True
                sleep(1)
    request.server_terminated = True
    if got_exception:
        util.prepend_message_to_exception(
            'client initiated closing handshake for %s: ' % (
            request.ws_resource),
            e)
        raise ConnectionTerminatedException
    # TODO: 3. close the WebSocket connection.
    # note: mod_python Connection (mp_conn) doesn't have close method.


def send_message(request, message):
    """Send message.

    Args:
        request: mod_python request.
        message: unicode string to send.
    Raises:
        ConnectionTerminatedException: when server already terminated.
    """
Example #17
0
            self._logger.debug('%s', e)
            request.ws_stream.close_connection(common.STATUS_PROTOCOL_ERROR)
        except msgutil.UnsupportedFrameException, e:
            self._logger.debug('%s', e)
            request.ws_stream.close_connection(common.STATUS_UNSUPPORTED_DATA)
        except stream.InvalidUTF8Exception, e:
            self._logger.debug('%s', e)
            request.ws_stream.close_connection(
                common.STATUS_INVALID_FRAME_PAYLOAD_DATA)
        except msgutil.ConnectionTerminatedException, e:
            self._logger.debug('%s', e)
        except Exception, e:
            # Any other exceptions are forwarded to the caller of this
            # function.
            util.prepend_message_to_exception(
                '%s raised exception for %s: ' % (
                    _TRANSFER_DATA_HANDLER_NAME, request.ws_resource),
                e)
            raise

    def passive_closing_handshake(self, request):
        """Prepare code and reason for responding client initiated closing
        handshake.
        """

        handler_suite = self.get_handler_suite(request.ws_resource)
        if handler_suite is None:
            return _default_passive_closing_handshake_handler(request)
        return handler_suite.passive_closing_handshake(request)

    def get_handler_suite(self, resource):
        """Retrieves two handlers (one for extra handshake processing, and one