From ca140fe44d0ceb3004073645222abec182d8784b Mon Sep 17 00:00:00 2001
From: Miguel Grinberg <miguel.grinberg@gmail.com>
Date: Thu, 21 May 2026 22:39:03 +0100
Subject: [PATCH] prevent unnecessary resource allocation (#1574)

---
 src/socketio/async_server.py |  5 +++++
 src/socketio/server.py       |  5 +++++
 tests/async/test_server.py   | 32 ++++++++++++++++++++++++++++++++
 tests/common/test_server.py  | 29 +++++++++++++++++++++++++++++
 4 files changed, 71 insertions(+)

Index: python-socketio-5.7.2/src/socketio/asyncio_server.py
===================================================================
--- python-socketio-5.7.2.orig/src/socketio/asyncio_server.py
+++ python-socketio-5.7.2/src/socketio/asyncio_server.py
@@ -381,6 +381,8 @@ class AsyncServer(server.Server):
         if delete_it:
             self.logger.info('Disconnecting %s [%s]', sid, namespace)
             eio_sid = self.manager.pre_disconnect(sid, namespace=namespace)
+            if eio_sid in self._binary_packet:
+                del self._binary_packet[eio_sid]
             await self._send_packet(eio_sid, self.packet_class(
                 packet.DISCONNECT, namespace=namespace))
             await self._trigger_event('disconnect', namespace, sid)
@@ -602,6 +604,9 @@ class AsyncServer(server.Server):
                                        pkt.data)
             elif pkt.packet_type == packet.BINARY_EVENT or \
                     pkt.packet_type == packet.BINARY_ACK:
+                if not self.manager.sid_from_eio_sid(eio_sid,
+                                                     pkt.namespace or '/'):
+                    raise ValueError('Unexpected binary packet')
                 self._binary_packet[eio_sid] = pkt
             elif pkt.packet_type == packet.CONNECT_ERROR:
                 raise ValueError('Unexpected CONNECT_ERROR packet.')
Index: python-socketio-5.7.2/src/socketio/server.py
===================================================================
--- python-socketio-5.7.2.orig/src/socketio/server.py
+++ python-socketio-5.7.2/src/socketio/server.py
@@ -562,6 +562,8 @@ class Server(object):
         if delete_it:
             self.logger.info('Disconnecting %s [%s]', sid, namespace)
             eio_sid = self.manager.pre_disconnect(sid, namespace=namespace)
+            if eio_sid in self._binary_packet:
+                del self._binary_packet[eio_sid]
             self._send_packet(eio_sid, self.packet_class(
                 packet.DISCONNECT, namespace=namespace))
             self._trigger_event('disconnect', namespace, sid)
@@ -795,6 +797,9 @@ class Server(object):
                 self._handle_ack(eio_sid, pkt.namespace, pkt.id, pkt.data)
             elif pkt.packet_type == packet.BINARY_EVENT or \
                     pkt.packet_type == packet.BINARY_ACK:
+                if not self.manager.sid_from_eio_sid(eio_sid,
+                                                     pkt.namespace or '/'):
+                    raise ValueError('Unexpected binary packet')
                 self._binary_packet[eio_sid] = pkt
             elif pkt.packet_type == packet.CONNECT_ERROR:
                 raise ValueError('Unexpected CONNECT_ERROR packet.')
Index: python-socketio-5.7.2/tests/asyncio/test_asyncio_server.py
===================================================================
--- python-socketio-5.7.2.orig/tests/asyncio/test_asyncio_server.py
+++ python-socketio-5.7.2/tests/asyncio/test_asyncio_server.py
@@ -712,6 +712,20 @@ class TestAsyncServer(unittest.TestCase)
             sid, 321, ['my message', 'a', b'foo']
         )
 
+    async def test_handle_event_binary_from_unknown(self, eio):
+        eio.return_value.send = AsyncMock()
+        s = asyncio_server.AsyncServer(async_handlers=False)
+        await s.manager.connect('123', '/')
+        handler = mock.MagicMock()
+        s.on('my message', handler)
+        with pytest.raises(ValueError):
+            await s._handle_eio_message(
+                '999',
+                '52-["my message","a",'
+                '{"_placeholder":true,"num":1},'
+                '{"_placeholder":true,"num":0}]',
+            )
+
     def test_handle_event_with_ack(self, eio):
         eio.return_value.send = AsyncMock()
         s = asyncio_server.AsyncServer(async_handlers=False)
@@ -904,6 +918,24 @@ class TestAsyncServer(unittest.TestCase)
         _run(s.disconnect('1'))
         assert calls == s.eio.send.mock.call_count
 
+    async def test_disconnect_with_partial_binary_packet(self, eio):
+        eio.return_value.send = AsyncMock()
+        eio.return_value.disconnect = AsyncMock()
+        s = asyncio_server.AsyncServer()
+        await s._handle_eio_connect('123', 'environ')
+        await s._handle_eio_message('123', '0')
+        await s._handle_eio_message(
+            '123',
+            '52-["my message","a",'
+            '{"_placeholder":true,"num":1},'
+            '{"_placeholder":true,"num":0}]',
+        )
+        await s._handle_eio_message('123', b'foo')
+        assert s._binary_packet['123'] is not None
+        await s.disconnect('1')
+        s.eio.send.assert_any_await('123', '1')
+        assert '123' not in s._binary_packet
+
     def test_disconnect_twice_namespace(self, eio):
         eio.return_value.send = AsyncMock()
         s = asyncio_server.AsyncServer()
Index: python-socketio-5.7.2/tests/common/test_server.py
===================================================================
--- python-socketio-5.7.2.orig/tests/common/test_server.py
+++ python-socketio-5.7.2/tests/common/test_server.py
@@ -628,6 +628,19 @@ class TestServer(unittest.TestCase):
             sid, 321, ['my message', 'a', b'foo']
         )
 
+    def test_handle_event_binary_from_unknown(self, eio):
+        s = server.Server(async_handlers=False)
+        s.manager.connect('123', '/')
+        handler = mock.MagicMock()
+        s.on('my message', handler)
+        with pytest.raises(ValueError):
+            s._handle_eio_message(
+                '999',
+                '52-["my message","a",'
+                '{"_placeholder":true,"num":1},'
+                '{"_placeholder":true,"num":0}]',
+            )
+
     def test_handle_event_with_ack(self, eio):
         s = server.Server(async_handlers=False)
         sid = s.manager.connect('123', '/')
@@ -798,6 +811,22 @@ class TestServer(unittest.TestCase):
         s.disconnect('123', namespace='/foo')
         assert calls == s.eio.send.call_count
 
+    def test_disconnect_with_partial_binary_packet(self, eio):
+        s = server.Server()
+        s._handle_eio_connect('123', 'environ')
+        s._handle_eio_message('123', '0')
+        s._handle_eio_message(
+            '123',
+            '52-["my message","a",'
+            '{"_placeholder":true,"num":1},'
+            '{"_placeholder":true,"num":0}]',
+        )
+        s._handle_eio_message('123', b'foo')
+        assert s._binary_packet['123'] is not None
+        s.disconnect('1')
+        s.eio.send.assert_any_call('123', '1')
+        assert '123' not in s._binary_packet
+
     def test_namespace_handler(self, eio):
         result = {}
 
