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)
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
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
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
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
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
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
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
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
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
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)
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. """
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')
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))
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. """
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