diff --git a/src/socketio/asyncio_server.py b/src/socketio/asyncio_server.py index 59fab4a..8dbba22 100644 --- a/src/socketio/asyncio_server.py +++ b/src/socketio/asyncio_server.py @@ -377,7 +377,7 @@ class AsyncServer(server.Server): eio_sid = self.manager.pre_disconnect(sid, namespace=namespace) await self._send_packet(eio_sid, self.packet_class( packet.DISCONNECT, namespace=namespace)) - await self._trigger_event('disconnect', namespace, sid) + await self._trigger_event('disconnect', namespace, sid, safe=True) self.manager.disconnect(sid, namespace=namespace) async def handle_request(self, *args, **kwargs): @@ -450,18 +450,20 @@ class AsyncServer(server.Server): try: if data: success = await self._trigger_event( - 'connect', namespace, sid, self.environ[eio_sid], data) + 'connect', namespace, sid, self.environ[eio_sid], data, safe=False) else: try: success = await self._trigger_event( - 'connect', namespace, sid, self.environ[eio_sid]) + 'connect', namespace, sid, self.environ[eio_sid], safe=False) except TypeError: success = await self._trigger_event( - 'connect', namespace, sid, self.environ[eio_sid], None) + 'connect', namespace, sid, self.environ[eio_sid], None, safe=False) except exceptions.ConnectionRefusedError as exc: fail_reason = exc.error_args success = False - + except exceptions.NamespaceNotFoundError: + fail_reason = "Namespace not found" + success = False if success is False: if self.always_connect: self.manager.pre_disconnect(sid, namespace) @@ -483,7 +485,7 @@ class AsyncServer(server.Server): if not self.manager.is_connected(sid, namespace): # pragma: no cover return self.manager.pre_disconnect(sid, namespace=namespace) - await self._trigger_event('disconnect', namespace, sid) + await self._trigger_event('disconnect', namespace, sid, safe=True) self.manager.disconnect(sid, namespace) async def _handle_event(self, eio_sid, namespace, id, data): @@ -505,7 +507,7 @@ class AsyncServer(server.Server): async def _handle_event_internal(self, server, sid, eio_sid, data, namespace, id): - r = await server._trigger_event(data[0], namespace, sid, *data[1:]) + r = await server._trigger_event(data[0], namespace, sid, *data[1:], safe=True) if id is not None: # send ACK packet with the response returned by the handler # tuples are expanded as multiple arguments @@ -525,7 +527,7 @@ class AsyncServer(server.Server): self.logger.info('received ack from %s [%s]', sid, namespace) await self.manager.trigger_callback(sid, id, data) - async def _trigger_event(self, event, namespace, *args): + async def _trigger_event(self, event, namespace, *args, safe): """Invoke an application event handler.""" # first see if we have an explicit handler for the event if namespace in self.handlers: @@ -550,6 +552,8 @@ class AsyncServer(server.Server): elif namespace in self.namespace_handlers: return await self.namespace_handlers[namespace].trigger_event( event, *args) + elif not safe: + raise exceptions.NamespaceNotFoundError(namespace, event) async def _handle_eio_connect(self, eio_sid, environ): """Handle the Engine.IO connection event.""" diff --git a/src/socketio/exceptions.py b/src/socketio/exceptions.py index d9dae4a..dcb92e4 100644 --- a/src/socketio/exceptions.py +++ b/src/socketio/exceptions.py @@ -32,3 +32,6 @@ class TimeoutError(SocketIOError): class BadNamespaceError(SocketIOError): pass + +class NamespaceNotFoundError(SocketIOError): + pass diff --git a/src/socketio/server.py b/src/socketio/server.py index cdf255b..9ffc2bc 100644 --- a/src/socketio/server.py +++ b/src/socketio/server.py @@ -557,7 +557,7 @@ class Server(object): eio_sid = self.manager.pre_disconnect(sid, namespace=namespace) self._send_packet(eio_sid, self.packet_class( packet.DISCONNECT, namespace=namespace)) - self._trigger_event('disconnect', namespace, sid) + self._trigger_event('disconnect', namespace, sid, safe=True) self.manager.disconnect(sid, namespace=namespace) def transport(self, sid): @@ -662,17 +662,20 @@ class Server(object): try: if data: success = self._trigger_event( - 'connect', namespace, sid, self.environ[eio_sid], data) + 'connect', namespace, sid, self.environ[eio_sid], data, safe=False) else: try: success = self._trigger_event( - 'connect', namespace, sid, self.environ[eio_sid]) + 'connect', namespace, sid, self.environ[eio_sid], safe=False) except TypeError: success = self._trigger_event( - 'connect', namespace, sid, self.environ[eio_sid], None) + 'connect', namespace, sid, self.environ[eio_sid], None, safe=False) except exceptions.ConnectionRefusedError as exc: fail_reason = exc.error_args success = False + except exceptions.NamespaceNotFoundError: + fail_reason = "Namespace not found" + success = False if success is False: if self.always_connect: @@ -695,7 +698,7 @@ class Server(object): if not self.manager.is_connected(sid, namespace): # pragma: no cover return self.manager.pre_disconnect(sid, namespace=namespace) - self._trigger_event('disconnect', namespace, sid) + self._trigger_event('disconnect', namespace, sid, safe=True) self.manager.disconnect(sid, namespace) def _handle_event(self, eio_sid, namespace, id, data): @@ -717,7 +720,7 @@ class Server(object): def _handle_event_internal(self, server, sid, eio_sid, data, namespace, id): - r = server._trigger_event(data[0], namespace, sid, *data[1:]) + r = server._trigger_event(data[0], namespace, sid, *data[1:], safe=True) if id is not None: # send ACK packet with the response returned by the handler # tuples are expanded as multiple arguments @@ -737,7 +740,7 @@ class Server(object): self.logger.info('received ack from %s [%s]', sid, namespace) self.manager.trigger_callback(sid, id, data) - def _trigger_event(self, event, namespace, *args): + def _trigger_event(self, event, namespace, *args, safe): """Invoke an application event handler.""" # first see if we have an explicit handler for the event if namespace in self.handlers: @@ -751,6 +754,8 @@ class Server(object): elif namespace in self.namespace_handlers: return self.namespace_handlers[namespace].trigger_event( event, *args) + elif not safe: + raise exceptions.NamespaceNotFoundError(namespace, event) def _handle_eio_connect(self, eio_sid, environ): """Handle the Engine.IO connection event."""