From 34f34e53d650dde605f5f4a98d7a70936524a1b8 Mon Sep 17 00:00:00 2001 From: Miguel Grinberg Date: Sun, 31 Oct 2021 00:35:51 +0100 Subject: [PATCH] Do not invoke reserved events on a catch-all handler (Fixes #814) --- docs/client.rst | 11 +++++++---- docs/server.rst | 3 +++ src/socketio/asyncio_client.py | 3 ++- src/socketio/asyncio_server.py | 3 ++- src/socketio/client.py | 5 ++++- src/socketio/server.py | 5 ++++- tests/asyncio/test_asyncio_client.py | 1 + tests/common/test_client.py | 1 + 8 files changed, 24 insertions(+), 8 deletions(-) diff --git a/docs/client.rst b/docs/client.rst index 5bf85ad..a44a573 100644 --- a/docs/client.rst +++ b/docs/client.rst @@ -65,6 +65,9 @@ or can also be coroutines:: async def message(data): print('I received a message!') +If the server includes arguments with an event, those are passed to the +handler function as arguments. + Catch-All Event Handlers ------------------------ @@ -72,13 +75,13 @@ A "catch-all" event handler is invoked for any events that do not have an event handler. You can define a catch-all handler using ``'*'`` as event name:: @sio.on('*') - def catch_all(event, sid, data): + def catch_all(event, data): pass Asyncio clients can also use a coroutine:: @sio.on('*') - async def catch_all(event, sid, data): + async def catch_all(event, data): pass A catch-all event handler receives the event name as a first argument. The @@ -115,8 +118,8 @@ going to attempt to reconnect immediately after invoking the disconnect handler. As soon as the connection is re-established the connect handler will be invoked once again. -If the server includes arguments with an event, those are passed to the -handler function as arguments. +The ``connect``, ``connect_error`` and ``disconnect`` events have to be +defined explicitly and are not invoked on a catch-all event handler. Connecting to a Server ---------------------- diff --git a/docs/server.rst b/docs/server.rst index e553696..f02fa3c 100644 --- a/docs/server.rst +++ b/docs/server.rst @@ -197,6 +197,9 @@ Asyncio servers can also use a coroutine:: A catch-all event handler receives the event name as a first argument. The remaining arguments are the same as for a regular event handler. +The ``connect`` and ``disconnect`` events have to be defined explicitly and are +not invoked on a catch-all event handler. + Connect and Disconnect Event Handlers ------------------------------------- diff --git a/src/socketio/asyncio_client.py b/src/socketio/asyncio_client.py index e98f337..03b770d 100644 --- a/src/socketio/asyncio_client.py +++ b/src/socketio/asyncio_client.py @@ -431,7 +431,8 @@ class AsyncClient(client.Client): handler = None if event in self.handlers[namespace]: handler = self.handlers[namespace][event] - elif '*' in self.handlers[namespace]: + elif event not in self.reserved_events and \ + '*' in self.handlers[namespace]: handler = self.handlers[namespace]['*'] args = (event, *args) if handler: diff --git a/src/socketio/asyncio_server.py b/src/socketio/asyncio_server.py index a43430c..59fab4a 100644 --- a/src/socketio/asyncio_server.py +++ b/src/socketio/asyncio_server.py @@ -532,7 +532,8 @@ class AsyncServer(server.Server): handler = None if event in self.handlers[namespace]: handler = self.handlers[namespace][event] - elif '*' in self.handlers[namespace]: + elif event not in self.reserved_events and \ + '*' in self.handlers[namespace]: handler = self.handlers[namespace]['*'] args = (event, *args) if handler: diff --git a/src/socketio/client.py b/src/socketio/client.py index 2078e5d..5046ea8 100644 --- a/src/socketio/client.py +++ b/src/socketio/client.py @@ -92,6 +92,8 @@ class Client(object): fatal errors are logged even when ``engineio_logger`` is ``False``. """ + reserved_events = ['connect', 'connect_error', 'disconnect'] + def __init__(self, reconnection=True, reconnection_attempts=0, reconnection_delay=1, reconnection_delay_max=5, randomization_factor=0.5, logger=False, serializer='default', @@ -625,7 +627,8 @@ class Client(object): if namespace in self.handlers: if event in self.handlers[namespace]: return self.handlers[namespace][event](*args) - elif '*' in self.handlers[namespace]: + elif event not in self.reserved_events and \ + '*' in self.handlers[namespace]: return self.handlers[namespace]['*'](event, *args) # or else, forward the event to a namespace handler if one exists diff --git a/src/socketio/server.py b/src/socketio/server.py index b8ee435..cdf255b 100644 --- a/src/socketio/server.py +++ b/src/socketio/server.py @@ -106,6 +106,8 @@ class Server(object): fatal errors are logged even when ``engineio_logger`` is ``False``. """ + reserved_events = ['connect', 'disconnect'] + def __init__(self, client_manager=None, logger=False, serializer='default', json=None, async_handlers=True, always_connect=False, **kwargs): @@ -741,7 +743,8 @@ class Server(object): if namespace in self.handlers: if event in self.handlers[namespace]: return self.handlers[namespace][event](*args) - elif '*' in self.handlers[namespace]: + elif event not in self.reserved_events and \ + '*' in self.handlers[namespace]: return self.handlers[namespace]['*'](event, *args) # or else, forward the event to a namespace handler if one exists diff --git a/tests/asyncio/test_asyncio_client.py b/tests/asyncio/test_asyncio_client.py index 06a119d..b8d5c4c 100644 --- a/tests/asyncio/test_asyncio_client.py +++ b/tests/asyncio/test_asyncio_client.py @@ -838,6 +838,7 @@ class TestAsyncClient(unittest.TestCase): c.on('*', catchall_handler) _run(c._trigger_event('foo', '/', 1, '2')) _run(c._trigger_event('bar', '/', 1, '2', 3)) + _run(c._trigger_event('connect', '/')) # should not trigger handler.assert_called_once_with(1, '2') catchall_handler.assert_called_once_with('bar', 1, '2', 3) diff --git a/tests/common/test_client.py b/tests/common/test_client.py index 2c3a93d..a9415ef 100644 --- a/tests/common/test_client.py +++ b/tests/common/test_client.py @@ -943,6 +943,7 @@ class TestClient(unittest.TestCase): c.on('*', catchall_handler) c._trigger_event('foo', '/', 1, '2') c._trigger_event('bar', '/', 1, '2', 3) + c._trigger_event('connect', '/') # should not trigger handler.assert_called_once_with(1, '2') catchall_handler.assert_called_once_with('bar', 1, '2', 3)