Skip to content

Commit 53f6be0

Browse files
Replace pickle with json (#1502)
1 parent a59c6f5 commit 53f6be0

11 files changed

+48
-64
lines changed

docs/server.rst

Lines changed: 11 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1096,17 +1096,17 @@ For a production deployment there are a few recommendations to keep your
10961096
application secure.
10971097

10981098
First of all, the message queue should never be listening on a public network
1099-
interface, to ensure that external clients never connect to it. The use of a
1100-
private network (VPC), where the communication between servers can happen
1101-
privately is highly recommended.
1102-
1103-
In addition, all message queues support authentication and encryption.
1104-
Authentication ensures that only the Socket.IO servers and related processes
1105-
have access, while encryption prevents data to be collected by a third-party
1106-
listening on the network.
1107-
1108-
Access credentials can be included in the connection URLs that are passed to the
1109-
client managers.
1099+
interface, to ensure that external clients never connect to it. For a single
1100+
node deployment, the queue should only listen on `localhost`. For a multi-node
1101+
system the use of a private network (VPC), where the communication between
1102+
servers can happen privately is highly recommended.
1103+
1104+
In addition, all message queues support authentication and encryption, which
1105+
can strenthen the security of the deployment. Authentication ensures that only
1106+
the Socket.IO servers and related processes have access, while encryption
1107+
prevents data from being collected by a third-party that is listening on the
1108+
network. Access credentials can be included in the connection URLs that are
1109+
passed to the client managers.
11101110

11111111
Horizontal Scaling
11121112
~~~~~~~~~~~~~~~~~~

src/socketio/async_aiopika_manager.py

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
import asyncio
2-
import pickle
32

3+
from engineio import json
44
from .async_pubsub_manager import AsyncPubSubManager
55

66
try:
@@ -82,7 +82,7 @@ async def _publish(self, data):
8282
try:
8383
await self.publisher_exchange.publish(
8484
aio_pika.Message(
85-
body=pickle.dumps(data),
85+
body=json.dumps(data),
8686
delivery_mode=aio_pika.DeliveryMode.PERSISTENT
8787
), routing_key='*',
8888
)
@@ -113,7 +113,7 @@ async def _listen(self):
113113
async with queue.iterator() as queue_iter:
114114
async for message in queue_iter:
115115
async with message.process():
116-
yield pickle.loads(message.body)
116+
yield message.body
117117
retry_sleep = 1
118118
except aio_pika.AMQPException:
119119
self._get_logger().error(

src/socketio/async_pubsub_manager.py

Lines changed: 4 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,6 @@
33
import uuid
44

55
from engineio import json
6-
import pickle
76

87
from .async_manager import AsyncManager
98

@@ -202,16 +201,10 @@ async def _thread(self):
202201
if isinstance(message, dict):
203202
data = message
204203
else:
205-
if isinstance(message, bytes): # pragma: no cover
206-
try:
207-
data = pickle.loads(message)
208-
except:
209-
pass
210-
if data is None:
211-
try:
212-
data = json.loads(message)
213-
except:
214-
pass
204+
try:
205+
data = json.loads(message)
206+
except:
207+
pass
215208
if data and 'method' in data:
216209
self._get_logger().debug('pubsub message: {}'.format(
217210
data['method']))

src/socketio/async_redis_manager.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,4 @@
11
import asyncio
2-
import pickle
32
from urllib.parse import urlparse
43

54
try: # pragma: no cover
@@ -20,6 +19,7 @@
2019
valkey = None
2120
ValkeyError = None
2221

22+
from engineio import json
2323
from .async_pubsub_manager import AsyncPubSubManager
2424
from .redis_manager import parse_redis_sentinel_url
2525

@@ -108,7 +108,7 @@ async def _publish(self, data):
108108
if not retry:
109109
self._redis_connect()
110110
return await self.redis.publish(
111-
self.channel, pickle.dumps(data))
111+
self.channel, json.dumps(data))
112112
except error as exc:
113113
if retry:
114114
self._get_logger().error(

src/socketio/kafka_manager.py

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,11 @@
11
import logging
2-
import pickle
32

43
try:
54
import kafka
65
except ImportError:
76
kafka = None
87

8+
from engineio import json
99
from .pubsub_manager import PubSubManager
1010

1111
logger = logging.getLogger('socketio')
@@ -53,7 +53,7 @@ def __init__(self, url='kafka://localhost:9092', channel='socketio',
5353
bootstrap_servers=self.kafka_urls)
5454

5555
def _publish(self, data):
56-
self.producer.send(self.channel, value=pickle.dumps(data))
56+
self.producer.send(self.channel, value=json.dumps(data))
5757
self.producer.flush()
5858

5959
def _kafka_listen(self):
@@ -62,4 +62,4 @@ def _kafka_listen(self):
6262
def _listen(self):
6363
for message in self._kafka_listen():
6464
if message.topic == self.channel:
65-
yield pickle.loads(message.value)
65+
yield message.value

src/socketio/kombu_manager.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,3 @@
1-
import pickle
21
import time
32
import uuid
43

@@ -7,6 +6,7 @@
76
except ImportError:
87
kombu = None
98

9+
from engineio import json
1010
from .pubsub_manager import PubSubManager
1111

1212

@@ -102,7 +102,7 @@ def _publish(self, data):
102102
try:
103103
producer_publish = self._producer_publish(
104104
self.publisher_connection)
105-
producer_publish(pickle.dumps(data))
105+
producer_publish(json.dumps(data))
106106
break
107107
except (OSError, kombu.exceptions.KombuError):
108108
if retry:

src/socketio/pubsub_manager.py

Lines changed: 4 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,6 @@
22
import uuid
33

44
from engineio import json
5-
import pickle
65

76
from .manager import Manager
87

@@ -196,16 +195,10 @@ def _thread(self):
196195
if isinstance(message, dict):
197196
data = message
198197
else:
199-
if isinstance(message, bytes): # pragma: no cover
200-
try:
201-
data = pickle.loads(message)
202-
except:
203-
pass
204-
if data is None:
205-
try:
206-
data = json.loads(message)
207-
except:
208-
pass
198+
try:
199+
data = json.loads(message)
200+
except:
201+
pass
209202
if data and 'method' in data:
210203
self._get_logger().debug('pubsub message: {}'.format(
211204
data['method']))

src/socketio/redis_manager.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,4 @@
11
import logging
2-
import pickle
32
import time
43
from urllib.parse import urlparse
54

@@ -17,6 +16,7 @@
1716
valkey = None
1817
ValkeyError = None
1918

19+
from engineio import json
2020
from .pubsub_manager import PubSubManager
2121

2222
logger = logging.getLogger('socketio')
@@ -145,7 +145,7 @@ def _publish(self, data):
145145
try:
146146
if not retry:
147147
self._redis_connect()
148-
return self.redis.publish(self.channel, pickle.dumps(data))
148+
return self.redis.publish(self.channel, json.dumps(data))
149149
except error as exc:
150150
if retry:
151151
logger.error(

src/socketio/zmq_manager.py

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
1-
import pickle
21
import re
32

3+
from engineio import json
44
from .pubsub_manager import PubSubManager
55

66

@@ -75,14 +75,14 @@ def __init__(self, url='zmq+tcp://localhost:5555+5556',
7575
self.channel = channel
7676

7777
def _publish(self, data):
78-
pickled_data = pickle.dumps(
78+
packed_data = json.dumps(
7979
{
8080
'type': 'message',
8181
'channel': self.channel,
8282
'data': data
8383
}
84-
)
85-
return self.sink.send(pickled_data)
84+
).encode()
85+
return self.sink.send(packed_data)
8686

8787
def zmq_listen(self):
8888
while True:
@@ -94,7 +94,7 @@ def _listen(self):
9494
for message in self.zmq_listen():
9595
if isinstance(message, bytes):
9696
try:
97-
message = pickle.loads(message)
97+
message = json.loads(message)
9898
except Exception:
9999
pass
100100
if isinstance(message, dict) and \

tests/async/test_pubsub_manager.py

Lines changed: 6 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
import asyncio
22
import functools
3+
import json
34
from unittest import mock
45

56
import pytest
@@ -482,31 +483,29 @@ async def test_background_thread(self):
482483
host_id = self.pm.host_id
483484

484485
async def messages():
485-
import pickle
486-
487486
yield {'method': 'emit', 'value': 'foo', 'host_id': 'x'}
488487
yield {'missing': 'method', 'host_id': 'x'}
489488
yield '{"method": "callback", "value": "bar", "host_id": "x"}'
490489
yield {'method': 'disconnect', 'sid': '123', 'namespace': '/foo',
491490
'host_id': 'x'}
492491
yield {'method': 'bogus', 'host_id': 'x'}
493-
yield pickle.dumps({'method': 'close_room', 'value': 'baz',
494-
'host_id': 'x'})
492+
yield json.dumps({'method': 'close_room', 'value': 'baz',
493+
'host_id': 'x'})
495494
yield {'method': 'enter_room', 'sid': '123', 'namespace': '/foo',
496495
'room': 'room', 'host_id': 'x'}
497496
yield {'method': 'leave_room', 'sid': '123', 'namespace': '/foo',
498497
'room': 'room', 'host_id': 'x'}
499498
yield 'bad json'
500-
yield b'bad pickled'
499+
yield b'bad data'
501500

502501
# these should not publish anything on the queue, as they come from
503502
# the same host
504503
yield {'method': 'emit', 'value': 'foo', 'host_id': host_id}
505504
yield {'method': 'callback', 'value': 'bar', 'host_id': host_id}
506505
yield {'method': 'disconnect', 'sid': '123', 'namespace': '/foo',
507506
'host_id': host_id}
508-
yield pickle.dumps({'method': 'close_room', 'value': 'baz',
509-
'host_id': host_id})
507+
yield json.dumps({'method': 'close_room', 'value': 'baz',
508+
'host_id': host_id})
510509

511510
self.pm._listen = messages
512511
await self.pm._thread()

0 commit comments

Comments
 (0)