python-engineio 4.14.0__tar.gz → 4.15.0__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {python_engineio-4.14.0/src/python_engineio.egg-info → python_engineio-4.15.0}/PKG-INFO +8 -7
- {python_engineio-4.14.0 → python_engineio-4.15.0}/pyproject.toml +8 -7
- {python_engineio-4.14.0 → python_engineio-4.15.0}/src/engineio/async_client.py +18 -6
- {python_engineio-4.14.0 → python_engineio-4.15.0}/src/engineio/async_server.py +26 -13
- {python_engineio-4.14.0 → python_engineio-4.15.0}/src/engineio/base_client.py +8 -2
- {python_engineio-4.14.0 → python_engineio-4.15.0}/src/engineio/client.py +8 -1
- {python_engineio-4.14.0 → python_engineio-4.15.0}/src/engineio/server.py +26 -13
- {python_engineio-4.14.0 → python_engineio-4.15.0}/src/engineio/static_files.py +2 -0
- {python_engineio-4.14.0 → python_engineio-4.15.0/src/python_engineio.egg-info}/PKG-INFO +8 -7
- {python_engineio-4.14.0 → python_engineio-4.15.0}/src/python_engineio.egg-info/SOURCES.txt +1 -0
- python_engineio-4.15.0/tests/async/.test_client.py.swp +0 -0
- {python_engineio-4.14.0 → python_engineio-4.15.0}/tests/async/test_asgi.py +2 -0
- {python_engineio-4.14.0 → python_engineio-4.15.0}/tests/async/test_client.py +155 -71
- {python_engineio-4.14.0 → python_engineio-4.15.0}/tests/async/test_server.py +12 -0
- {python_engineio-4.14.0 → python_engineio-4.15.0}/tests/common/test_client.py +37 -10
- {python_engineio-4.14.0 → python_engineio-4.15.0}/tests/common/test_middleware.py +2 -0
- {python_engineio-4.14.0 → python_engineio-4.15.0}/tests/common/test_server.py +11 -0
- {python_engineio-4.14.0 → python_engineio-4.15.0}/tox.ini +19 -0
- {python_engineio-4.14.0 → python_engineio-4.15.0}/LICENSE +0 -0
- {python_engineio-4.14.0 → python_engineio-4.15.0}/MANIFEST.in +0 -0
- {python_engineio-4.14.0 → python_engineio-4.15.0}/README.md +0 -0
- {python_engineio-4.14.0 → python_engineio-4.15.0}/docs/_static/README.md +0 -0
- {python_engineio-4.14.0 → python_engineio-4.15.0}/setup.cfg +0 -0
- {python_engineio-4.14.0 → python_engineio-4.15.0}/src/engineio/__init__.py +0 -0
- {python_engineio-4.14.0 → python_engineio-4.15.0}/src/engineio/async_drivers/__init__.py +0 -0
- {python_engineio-4.14.0 → python_engineio-4.15.0}/src/engineio/async_drivers/_websocket_wsgi.py +0 -0
- {python_engineio-4.14.0 → python_engineio-4.15.0}/src/engineio/async_drivers/aiohttp.py +0 -0
- {python_engineio-4.14.0 → python_engineio-4.15.0}/src/engineio/async_drivers/asgi.py +0 -0
- {python_engineio-4.14.0 → python_engineio-4.15.0}/src/engineio/async_drivers/eventlet.py +0 -0
- {python_engineio-4.14.0 → python_engineio-4.15.0}/src/engineio/async_drivers/gevent.py +0 -0
- {python_engineio-4.14.0 → python_engineio-4.15.0}/src/engineio/async_drivers/gevent_uwsgi.py +0 -0
- {python_engineio-4.14.0 → python_engineio-4.15.0}/src/engineio/async_drivers/sanic.py +0 -0
- {python_engineio-4.14.0 → python_engineio-4.15.0}/src/engineio/async_drivers/threading.py +0 -0
- {python_engineio-4.14.0 → python_engineio-4.15.0}/src/engineio/async_drivers/tornado.py +0 -0
- {python_engineio-4.14.0 → python_engineio-4.15.0}/src/engineio/async_socket.py +0 -0
- {python_engineio-4.14.0 → python_engineio-4.15.0}/src/engineio/base_server.py +0 -0
- {python_engineio-4.14.0 → python_engineio-4.15.0}/src/engineio/base_socket.py +0 -0
- {python_engineio-4.14.0 → python_engineio-4.15.0}/src/engineio/exceptions.py +0 -0
- {python_engineio-4.14.0 → python_engineio-4.15.0}/src/engineio/json.py +0 -0
- {python_engineio-4.14.0 → python_engineio-4.15.0}/src/engineio/middleware.py +0 -0
- {python_engineio-4.14.0 → python_engineio-4.15.0}/src/engineio/packet.py +0 -0
- {python_engineio-4.14.0 → python_engineio-4.15.0}/src/engineio/payload.py +0 -0
- {python_engineio-4.14.0 → python_engineio-4.15.0}/src/engineio/socket.py +0 -0
- {python_engineio-4.14.0 → python_engineio-4.15.0}/src/python_engineio.egg-info/dependency_links.txt +0 -0
- {python_engineio-4.14.0 → python_engineio-4.15.0}/src/python_engineio.egg-info/not-zip-safe +0 -0
- {python_engineio-4.14.0 → python_engineio-4.15.0}/src/python_engineio.egg-info/requires.txt +0 -0
- {python_engineio-4.14.0 → python_engineio-4.15.0}/src/python_engineio.egg-info/top_level.txt +0 -0
- {python_engineio-4.14.0 → python_engineio-4.15.0}/tests/async/__init__.py +0 -0
- {python_engineio-4.14.0 → python_engineio-4.15.0}/tests/async/index.html +0 -0
- {python_engineio-4.14.0 → python_engineio-4.15.0}/tests/async/test_aiohttp.py +0 -0
- {python_engineio-4.14.0 → python_engineio-4.15.0}/tests/async/test_sanic.py +0 -0
- {python_engineio-4.14.0 → python_engineio-4.15.0}/tests/async/test_socket.py +0 -0
- {python_engineio-4.14.0 → python_engineio-4.15.0}/tests/async/test_tornado.py +0 -0
- {python_engineio-4.14.0 → python_engineio-4.15.0}/tests/common/__init__.py +0 -0
- {python_engineio-4.14.0 → python_engineio-4.15.0}/tests/common/index.html +0 -0
- {python_engineio-4.14.0 → python_engineio-4.15.0}/tests/common/test_packet.py +0 -0
- {python_engineio-4.14.0 → python_engineio-4.15.0}/tests/common/test_payload.py +0 -0
- {python_engineio-4.14.0 → python_engineio-4.15.0}/tests/common/test_socket.py +0 -0
- {python_engineio-4.14.0 → python_engineio-4.15.0}/tests/performance/README.md +0 -0
- {python_engineio-4.14.0 → python_engineio-4.15.0}/tests/performance/binary_b64_packet.py +0 -0
- {python_engineio-4.14.0 → python_engineio-4.15.0}/tests/performance/binary_packet.py +0 -0
- {python_engineio-4.14.0 → python_engineio-4.15.0}/tests/performance/json_packet.py +0 -0
- {python_engineio-4.14.0 → python_engineio-4.15.0}/tests/performance/payload.py +0 -0
- {python_engineio-4.14.0 → python_engineio-4.15.0}/tests/performance/run.sh +0 -0
- {python_engineio-4.14.0 → python_engineio-4.15.0}/tests/performance/server_receive.py +0 -0
- {python_engineio-4.14.0 → python_engineio-4.15.0}/tests/performance/text_packet.py +0 -0
|
@@ -1,14 +1,15 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: python-engineio
|
|
3
|
-
Version: 4.
|
|
3
|
+
Version: 4.15.0
|
|
4
4
|
Summary: Engine.IO server and client for Python
|
|
5
5
|
Author-email: Miguel Grinberg <miguel.grinberg@gmail.com>
|
|
6
|
-
License: MIT
|
|
7
|
-
Project-URL:
|
|
8
|
-
Project-URL:
|
|
9
|
-
Project-URL:
|
|
10
|
-
Project-URL:
|
|
11
|
-
Project-URL:
|
|
6
|
+
License-Expression: MIT
|
|
7
|
+
Project-URL: Homepage, https://code.miguelgrinberg.com/miguelgrinberg/python-engineio
|
|
8
|
+
Project-URL: Documentation, https://python-engineio.readthedocs.io/
|
|
9
|
+
Project-URL: Source Code, https://code.miguelgrinberg.com/miguelgrinberg/python-engineio
|
|
10
|
+
Project-URL: Issue Tracker, https://code.miguelgrinberg.com/miguelgrinberg/python-engineio/issues
|
|
11
|
+
Project-URL: Changelog, https://code.miguelgrinberg.com/miguelgrinberg/python-engineio/src/branch/main/CHANGES.md
|
|
12
|
+
Project-URL: Funding, https://code.miguelgrinberg.com/miguelgrinberg/python-engineio#sponsor-this-project
|
|
12
13
|
Classifier: Environment :: Web Environment
|
|
13
14
|
Classifier: Intended Audience :: Developers
|
|
14
15
|
Classifier: Programming Language :: Python :: 3
|
|
@@ -1,7 +1,6 @@
|
|
|
1
1
|
[project]
|
|
2
2
|
name = "python-engineio"
|
|
3
|
-
version = "4.
|
|
4
|
-
license = {text = "MIT"}
|
|
3
|
+
version = "4.15.0"
|
|
5
4
|
authors = [{name = "Miguel Grinberg", email = "miguel.grinberg@gmail.com"}]
|
|
6
5
|
description = "Engine.IO server and client for Python"
|
|
7
6
|
classifiers = [
|
|
@@ -10,6 +9,7 @@ classifiers = [
|
|
|
10
9
|
"Programming Language :: Python :: 3",
|
|
11
10
|
"Operating System :: OS Independent",
|
|
12
11
|
]
|
|
12
|
+
license = "MIT"
|
|
13
13
|
requires-python = ">=3.8"
|
|
14
14
|
dependencies = ["simple-websocket >= 0.10.0"]
|
|
15
15
|
|
|
@@ -18,11 +18,12 @@ file = "README.md"
|
|
|
18
18
|
content-type = "text/markdown"
|
|
19
19
|
|
|
20
20
|
[project.urls]
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
21
|
+
Homepage = "https://code.miguelgrinberg.com/miguelgrinberg/python-engineio"
|
|
22
|
+
Documentation = "https://python-engineio.readthedocs.io/"
|
|
23
|
+
"Source Code" = "https://code.miguelgrinberg.com/miguelgrinberg/python-engineio"
|
|
24
|
+
"Issue Tracker" = "https://code.miguelgrinberg.com/miguelgrinberg/python-engineio/issues"
|
|
25
|
+
Changelog = "https://code.miguelgrinberg.com/miguelgrinberg/python-engineio/src/branch/main/CHANGES.md"
|
|
26
|
+
Funding = "https://code.miguelgrinberg.com/miguelgrinberg/python-engineio#sponsor-this-project"
|
|
26
27
|
|
|
27
28
|
[project.optional-dependencies]
|
|
28
29
|
client = [
|
|
@@ -226,6 +226,7 @@ class AsyncClient(base_client.BaseClient):
|
|
|
226
226
|
if not self.external_http: # pragma: no cover
|
|
227
227
|
if self.http and not self.http.closed:
|
|
228
228
|
await self.http.close()
|
|
229
|
+
self.http = None
|
|
229
230
|
|
|
230
231
|
def __del__(self): # pragma: no cover
|
|
231
232
|
# try to close the aiohttp session if it is still open
|
|
@@ -323,8 +324,13 @@ class AsyncClient(base_client.BaseClient):
|
|
|
323
324
|
self.logger.info(
|
|
324
325
|
'Attempting WebSocket connection to ' + websocket_url)
|
|
325
326
|
|
|
326
|
-
if self.http is None or self.http.closed:
|
|
327
|
-
self.
|
|
327
|
+
if self.http is None or self.http.closed:
|
|
328
|
+
if self.http_factory:
|
|
329
|
+
self.http = self.http_factory()
|
|
330
|
+
if inspect.iscoroutine(self.http):
|
|
331
|
+
self.http = await self.http
|
|
332
|
+
else:
|
|
333
|
+
self.http = aiohttp.ClientSession()
|
|
328
334
|
|
|
329
335
|
# extract any new cookies passed in a header so that they can also be
|
|
330
336
|
# sent the the WebSocket route
|
|
@@ -458,12 +464,17 @@ class AsyncClient(base_client.BaseClient):
|
|
|
458
464
|
|
|
459
465
|
async def _send_request(
|
|
460
466
|
self, method, url, headers=None, body=None,
|
|
461
|
-
timeout=None):
|
|
467
|
+
timeout=None):
|
|
462
468
|
if self.http is None or self.http.closed:
|
|
463
|
-
self.
|
|
469
|
+
if self.http_factory:
|
|
470
|
+
self.http = self.http_factory()
|
|
471
|
+
if inspect.iscoroutine(self.http):
|
|
472
|
+
self.http = await self.http
|
|
473
|
+
else:
|
|
474
|
+
self.http = aiohttp.ClientSession()
|
|
464
475
|
http_method = getattr(self.http, method.lower())
|
|
465
476
|
|
|
466
|
-
try:
|
|
477
|
+
try: # pragma: no cover
|
|
467
478
|
if not self.ssl_verify:
|
|
468
479
|
return await http_method(
|
|
469
480
|
url, headers=headers, data=body,
|
|
@@ -473,7 +484,8 @@ class AsyncClient(base_client.BaseClient):
|
|
|
473
484
|
url, headers=headers, data=body,
|
|
474
485
|
timeout=aiohttp.ClientTimeout(total=timeout))
|
|
475
486
|
|
|
476
|
-
except (aiohttp.ClientError, asyncio.TimeoutError)
|
|
487
|
+
except (aiohttp.ClientError, asyncio.TimeoutError) \
|
|
488
|
+
as exc: # pragma: no cover
|
|
477
489
|
self.logger.info('HTTP %s request to %s failed with error %s.',
|
|
478
490
|
method, url, exc)
|
|
479
491
|
return str(exc)
|
|
@@ -298,7 +298,13 @@ class AsyncServer(base_server.BaseServer):
|
|
|
298
298
|
self._log_error_once(f'{e} {sid}', 'bad-sid')
|
|
299
299
|
r = self._bad_request(f'{e} {sid}')
|
|
300
300
|
else:
|
|
301
|
-
if
|
|
301
|
+
if socket.upgraded:
|
|
302
|
+
# cannot accept HTTP requests once upgraded
|
|
303
|
+
self._log_error_once(
|
|
304
|
+
f'Unexpected HTTP request for session {sid}',
|
|
305
|
+
'unexpected-http')
|
|
306
|
+
r = self._bad_request('Unexpected HTTP request')
|
|
307
|
+
elif transport != 'polling' and \
|
|
302
308
|
transport != upgrade_header:
|
|
303
309
|
self._log_error_once(
|
|
304
310
|
f'Invalid transport for session {sid}',
|
|
@@ -326,18 +332,25 @@ class AsyncServer(base_server.BaseServer):
|
|
|
326
332
|
r = self._bad_request(f'Invalid session {sid}')
|
|
327
333
|
else:
|
|
328
334
|
socket = self._get_socket(sid)
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
#
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
|
|
335
|
+
if not socket.upgraded:
|
|
336
|
+
try:
|
|
337
|
+
await socket.handle_post_request(environ)
|
|
338
|
+
r = self._ok(jsonp_index=jsonp_index)
|
|
339
|
+
except exceptions.EngineIOError:
|
|
340
|
+
if sid in self.sockets: # pragma: no cover
|
|
341
|
+
await self.disconnect(sid)
|
|
342
|
+
r = self._bad_request()
|
|
343
|
+
except: # pragma: no cover
|
|
344
|
+
# for any other unexpected errors, we log the error
|
|
345
|
+
# and keep going
|
|
346
|
+
self.logger.exception('post request handler error')
|
|
347
|
+
r = self._ok(jsonp_index=jsonp_index)
|
|
348
|
+
else:
|
|
349
|
+
# cannot accept HTTP requests once upgraded
|
|
350
|
+
self._log_error_once(
|
|
351
|
+
f'Unexpected HTTP request for session {sid}',
|
|
352
|
+
'unexpected-http')
|
|
353
|
+
r = self._bad_request('Unexpected HTTP request')
|
|
341
354
|
elif method == 'OPTIONS':
|
|
342
355
|
r = self._ok()
|
|
343
356
|
else:
|
|
@@ -55,8 +55,14 @@ class BaseClient:
|
|
|
55
55
|
self.upgrades = None
|
|
56
56
|
self.ping_interval = None
|
|
57
57
|
self.ping_timeout = None
|
|
58
|
-
self.http =
|
|
59
|
-
self.
|
|
58
|
+
self.http = None
|
|
59
|
+
self.http_factory = None
|
|
60
|
+
if http_session is not None:
|
|
61
|
+
if callable(http_session):
|
|
62
|
+
self.http_factory = http_session
|
|
63
|
+
else:
|
|
64
|
+
self.http = http_session
|
|
65
|
+
self.external_http = self.http is not None
|
|
60
66
|
self.handle_sigint = handle_sigint
|
|
61
67
|
self.ws = None
|
|
62
68
|
self.read_loop_task = None
|
|
@@ -183,6 +183,8 @@ class Client(base_client.BaseClient):
|
|
|
183
183
|
self.queue.task_done()
|
|
184
184
|
except self.queue_empty:
|
|
185
185
|
break
|
|
186
|
+
if not self.external_http: # pragma: no cover
|
|
187
|
+
self.http = None
|
|
186
188
|
|
|
187
189
|
def _connect_polling(self, url, headers, engineio_path):
|
|
188
190
|
"""Establish a long-polling connection to the Engine.IO server."""
|
|
@@ -274,6 +276,8 @@ class Client(base_client.BaseClient):
|
|
|
274
276
|
# so that they are preserved when connecting to the WebSocket route
|
|
275
277
|
cookies = None
|
|
276
278
|
extra_options = {}
|
|
279
|
+
if self.http is None and self.http_factory:
|
|
280
|
+
self.http = self.http_factory()
|
|
277
281
|
if self.http:
|
|
278
282
|
# cookies
|
|
279
283
|
ck = SimpleCookie()
|
|
@@ -458,7 +462,10 @@ class Client(base_client.BaseClient):
|
|
|
458
462
|
self, method, url, headers=None, body=None,
|
|
459
463
|
timeout=None): # pragma: no cover
|
|
460
464
|
if self.http is None:
|
|
461
|
-
self.
|
|
465
|
+
if self.http_factory:
|
|
466
|
+
self.http = self.http_factory()
|
|
467
|
+
else:
|
|
468
|
+
self.http = requests.Session()
|
|
462
469
|
if not self.ssl_verify:
|
|
463
470
|
self.http.verify = False
|
|
464
471
|
try:
|
|
@@ -276,7 +276,13 @@ class Server(base_server.BaseServer):
|
|
|
276
276
|
self._log_error_once(f'{e} {sid}', 'bad-sid')
|
|
277
277
|
r = self._bad_request(f'{e} {sid}')
|
|
278
278
|
else:
|
|
279
|
-
if
|
|
279
|
+
if socket.upgraded:
|
|
280
|
+
# cannot accept HTTP requests once upgraded
|
|
281
|
+
self._log_error_once(
|
|
282
|
+
f'Unexpected HTTP request for session {sid}',
|
|
283
|
+
'unexpected-http')
|
|
284
|
+
r = self._bad_request('Unexpected HTTP request')
|
|
285
|
+
elif transport != 'polling' and \
|
|
280
286
|
transport != upgrade_header:
|
|
281
287
|
self._log_error_once(
|
|
282
288
|
f'Invalid transport for session {sid}',
|
|
@@ -304,18 +310,25 @@ class Server(base_server.BaseServer):
|
|
|
304
310
|
r = self._bad_request(f'Invalid session {sid}')
|
|
305
311
|
else:
|
|
306
312
|
socket = self._get_socket(sid)
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
self.
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
#
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
313
|
+
if not socket.upgraded:
|
|
314
|
+
try:
|
|
315
|
+
socket.handle_post_request(environ)
|
|
316
|
+
r = self._ok(jsonp_index=jsonp_index)
|
|
317
|
+
except exceptions.EngineIOError:
|
|
318
|
+
if sid in self.sockets: # pragma: no cover
|
|
319
|
+
self.disconnect(sid)
|
|
320
|
+
r = self._bad_request()
|
|
321
|
+
except: # pragma: no cover
|
|
322
|
+
# for any other unexpected errors, we log the error
|
|
323
|
+
# and keep going
|
|
324
|
+
self.logger.exception('post request handler error')
|
|
325
|
+
r = self._ok(jsonp_index=jsonp_index)
|
|
326
|
+
else:
|
|
327
|
+
# cannot accept HTTP requests once upgraded
|
|
328
|
+
self._log_error_once(
|
|
329
|
+
f'Unexpected HTTP request for session {sid}',
|
|
330
|
+
'unexpected-http')
|
|
331
|
+
r = self._bad_request('Unexpected HTTP request')
|
|
319
332
|
elif method == 'OPTIONS':
|
|
320
333
|
r = self._ok()
|
|
321
334
|
else:
|
|
@@ -1,14 +1,15 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: python-engineio
|
|
3
|
-
Version: 4.
|
|
3
|
+
Version: 4.15.0
|
|
4
4
|
Summary: Engine.IO server and client for Python
|
|
5
5
|
Author-email: Miguel Grinberg <miguel.grinberg@gmail.com>
|
|
6
|
-
License: MIT
|
|
7
|
-
Project-URL:
|
|
8
|
-
Project-URL:
|
|
9
|
-
Project-URL:
|
|
10
|
-
Project-URL:
|
|
11
|
-
Project-URL:
|
|
6
|
+
License-Expression: MIT
|
|
7
|
+
Project-URL: Homepage, https://code.miguelgrinberg.com/miguelgrinberg/python-engineio
|
|
8
|
+
Project-URL: Documentation, https://python-engineio.readthedocs.io/
|
|
9
|
+
Project-URL: Source Code, https://code.miguelgrinberg.com/miguelgrinberg/python-engineio
|
|
10
|
+
Project-URL: Issue Tracker, https://code.miguelgrinberg.com/miguelgrinberg/python-engineio/issues
|
|
11
|
+
Project-URL: Changelog, https://code.miguelgrinberg.com/miguelgrinberg/python-engineio/src/branch/main/CHANGES.md
|
|
12
|
+
Project-URL: Funding, https://code.miguelgrinberg.com/miguelgrinberg/python-engineio#sponsor-this-project
|
|
12
13
|
Classifier: Environment :: Web Environment
|
|
13
14
|
Classifier: Intended Audience :: Developers
|
|
14
15
|
Classifier: Programming Language :: Python :: 3
|
|
@@ -36,6 +36,7 @@ src/python_engineio.egg-info/dependency_links.txt
|
|
|
36
36
|
src/python_engineio.egg-info/not-zip-safe
|
|
37
37
|
src/python_engineio.egg-info/requires.txt
|
|
38
38
|
src/python_engineio.egg-info/top_level.txt
|
|
39
|
+
tests/async/.test_client.py.swp
|
|
39
40
|
tests/async/__init__.py
|
|
40
41
|
tests/async/index.html
|
|
41
42
|
tests/async/test_aiohttp.py
|
|
Binary file
|
|
@@ -147,6 +147,8 @@ class TestAsgi:
|
|
|
147
147
|
'Not Found')
|
|
148
148
|
await check_path('/bar/foo', 404, 'text/plain', 'Not Found')
|
|
149
149
|
await check_path('', 404, 'text/plain', 'Not Found')
|
|
150
|
+
await check_path('/static/../../LICENSE', 404, 'text/plain',
|
|
151
|
+
'Not Found')
|
|
150
152
|
|
|
151
153
|
app.static_files[''] = 'index.html'
|
|
152
154
|
await check_path('/static/test/', 200, 'text/html', '<html></html>\n')
|
|
@@ -133,16 +133,60 @@ class TestAsyncClient:
|
|
|
133
133
|
match='Connect handler failed: Failed on purpose'):
|
|
134
134
|
await c.connect('http://foo')
|
|
135
135
|
|
|
136
|
-
@mock.patch('engineio.
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
136
|
+
@mock.patch('engineio.async_client.aiohttp.ClientSession')
|
|
137
|
+
async def test_connect_websocket_default_session(self, _session):
|
|
138
|
+
_session().ws_connect = mock.AsyncMock()
|
|
139
|
+
ws = _session().ws_connect.return_value
|
|
140
|
+
ws.receive = mock.AsyncMock()
|
|
141
|
+
ws.receive.return_value.data = packet.Packet(
|
|
142
|
+
packet.MESSAGE, # invaid on purpose
|
|
143
|
+
{},
|
|
144
|
+
).encode()
|
|
140
145
|
c = async_client.AsyncClient()
|
|
141
|
-
|
|
146
|
+
with pytest.raises(exceptions.ConnectionError,
|
|
147
|
+
match='no OPEN packet'):
|
|
148
|
+
await c.connect('http://foo', transports='websocket')
|
|
149
|
+
|
|
150
|
+
async def test_connect_websocket_external_session(self):
|
|
151
|
+
c = async_client.AsyncClient()
|
|
152
|
+
c.http = mock.Mock(closed=False)
|
|
153
|
+
c.external_http = True
|
|
142
154
|
c.http.ws_connect = mock.AsyncMock()
|
|
143
|
-
c.http.close = mock.AsyncMock()
|
|
144
155
|
ws = c.http.ws_connect.return_value
|
|
145
156
|
ws.receive = mock.AsyncMock()
|
|
157
|
+
ws.receive.return_value.data = packet.Packet(
|
|
158
|
+
packet.MESSAGE, # invaid on purpose
|
|
159
|
+
{},
|
|
160
|
+
).encode()
|
|
161
|
+
with pytest.raises(exceptions.ConnectionError,
|
|
162
|
+
match='no OPEN packet'):
|
|
163
|
+
await c.connect('http://foo', transports='websocket')
|
|
164
|
+
|
|
165
|
+
async def test_connect_websocket_async_session_factory(self):
|
|
166
|
+
async def get_session():
|
|
167
|
+
http = mock.MagicMock(closed=False)
|
|
168
|
+
http.ws_connect = mock.AsyncMock()
|
|
169
|
+
http.close = mock.AsyncMock()
|
|
170
|
+
ws = http.ws_connect.return_value
|
|
171
|
+
ws.receive = mock.AsyncMock()
|
|
172
|
+
ws.receive.return_value.data = packet.Packet(
|
|
173
|
+
packet.MESSAGE, # invaid on purpose
|
|
174
|
+
{},
|
|
175
|
+
).encode()
|
|
176
|
+
return http
|
|
177
|
+
|
|
178
|
+
c = async_client.AsyncClient(http_session=get_session)
|
|
179
|
+
with pytest.raises(exceptions.ConnectionError,
|
|
180
|
+
match='no OPEN packet'):
|
|
181
|
+
await c.connect('http://foo', transports='websocket')
|
|
182
|
+
|
|
183
|
+
@mock.patch('engineio.client.time.time', return_value=123.456)
|
|
184
|
+
async def test_connect_websocket_handler_failure(self, _time):
|
|
185
|
+
http = mock.MagicMock(closed=False)
|
|
186
|
+
http.ws_connect = mock.AsyncMock()
|
|
187
|
+
http.close = mock.AsyncMock()
|
|
188
|
+
ws = http.ws_connect.return_value
|
|
189
|
+
ws.receive = mock.AsyncMock()
|
|
146
190
|
ws.receive.return_value.data = packet.Packet(
|
|
147
191
|
packet.OPEN,
|
|
148
192
|
{
|
|
@@ -152,6 +196,7 @@ class TestAsyncClient:
|
|
|
152
196
|
'pingTimeout': 2000,
|
|
153
197
|
},
|
|
154
198
|
).encode()
|
|
199
|
+
c = async_client.AsyncClient(http_session=lambda: http)
|
|
155
200
|
|
|
156
201
|
@c.on('connect')
|
|
157
202
|
def connect():
|
|
@@ -161,6 +206,41 @@ class TestAsyncClient:
|
|
|
161
206
|
match='Connect handler failed: Failed on purpose'):
|
|
162
207
|
await c.connect('http://foo', transports='websocket')
|
|
163
208
|
|
|
209
|
+
@mock.patch('engineio.async_client.aiohttp.ClientSession')
|
|
210
|
+
async def test_send_request_with_default_session(self, _session):
|
|
211
|
+
_session().get = mock.AsyncMock()
|
|
212
|
+
c = async_client.AsyncClient()
|
|
213
|
+
await c._send_request('GET', '/socket.io')
|
|
214
|
+
_session().get.assert_awaited_once()
|
|
215
|
+
|
|
216
|
+
async def test_send_request_with_session_factory(self):
|
|
217
|
+
http = mock.Mock()
|
|
218
|
+
http.closed = False
|
|
219
|
+
http.get = mock.AsyncMock()
|
|
220
|
+
c = async_client.AsyncClient(http_session=lambda: http)
|
|
221
|
+
await c._send_request('GET', '/socket.io')
|
|
222
|
+
http.get.assert_awaited_once()
|
|
223
|
+
|
|
224
|
+
async def test_send_request_with_async_session_factory(self):
|
|
225
|
+
async def get_session():
|
|
226
|
+
http = mock.Mock()
|
|
227
|
+
http.closed = False
|
|
228
|
+
http.get = mock.AsyncMock()
|
|
229
|
+
return http
|
|
230
|
+
|
|
231
|
+
c = async_client.AsyncClient(http_session=get_session)
|
|
232
|
+
await c._send_request('GET', '/socket.io')
|
|
233
|
+
c.http.get.assert_awaited_once()
|
|
234
|
+
|
|
235
|
+
async def test_send_request_with_external_session(self):
|
|
236
|
+
c = async_client.AsyncClient()
|
|
237
|
+
c.http = mock.Mock()
|
|
238
|
+
c.http.closed = False
|
|
239
|
+
c.http.get = mock.AsyncMock()
|
|
240
|
+
c.external_http = True
|
|
241
|
+
await c._send_request('GET', '/socket.io')
|
|
242
|
+
c.http.get.assert_awaited_once()
|
|
243
|
+
|
|
164
244
|
async def test_wait(self):
|
|
165
245
|
c = async_client.AsyncClient()
|
|
166
246
|
done = []
|
|
@@ -563,18 +643,18 @@ class TestAsyncClient:
|
|
|
563
643
|
@mock.patch('engineio.async_client.aiohttp.ClientWSTimeout',
|
|
564
644
|
new=mock_ws_timeout)
|
|
565
645
|
async def test_websocket_connection_failed(self, _time):
|
|
566
|
-
|
|
567
|
-
|
|
568
|
-
c.http.ws_connect = mock.AsyncMock(
|
|
646
|
+
http = mock.MagicMock(closed=False)
|
|
647
|
+
http.ws_connect = mock.AsyncMock(
|
|
569
648
|
side_effect=[aiohttp.client_exceptions.ServerConnectionError()]
|
|
570
649
|
)
|
|
650
|
+
c = async_client.AsyncClient(http_session=lambda: http)
|
|
571
651
|
with pytest.raises(exceptions.ConnectionError):
|
|
572
652
|
await c.connect(
|
|
573
653
|
'http://foo',
|
|
574
654
|
transports=['websocket'],
|
|
575
655
|
headers={'Foo': 'Bar'},
|
|
576
656
|
)
|
|
577
|
-
|
|
657
|
+
http.ws_connect.assert_awaited_once_with(
|
|
578
658
|
'ws://foo/engine.io/?transport=websocket&EIO=4&t=123.456',
|
|
579
659
|
headers={'Foo': 'Bar'},
|
|
580
660
|
timeout=5
|
|
@@ -582,21 +662,24 @@ class TestAsyncClient:
|
|
|
582
662
|
|
|
583
663
|
@mock.patch('engineio.client.time.time', return_value=123.456)
|
|
584
664
|
async def test_websocket_connection_extra(self, _time):
|
|
585
|
-
|
|
586
|
-
|
|
587
|
-
'timeout': 10
|
|
588
|
-
})
|
|
589
|
-
c.http = mock.MagicMock(closed=False)
|
|
590
|
-
c.http.ws_connect = mock.AsyncMock(
|
|
665
|
+
http = mock.MagicMock(closed=False)
|
|
666
|
+
http.ws_connect = mock.AsyncMock(
|
|
591
667
|
side_effect=[aiohttp.client_exceptions.ServerConnectionError()]
|
|
592
668
|
)
|
|
669
|
+
c = async_client.AsyncClient(
|
|
670
|
+
http_session=lambda: http,
|
|
671
|
+
websocket_extra_options={
|
|
672
|
+
'headers': {'Baz': 'Qux'},
|
|
673
|
+
'timeout': 10
|
|
674
|
+
}
|
|
675
|
+
)
|
|
593
676
|
with pytest.raises(exceptions.ConnectionError):
|
|
594
677
|
await c.connect(
|
|
595
678
|
'http://foo',
|
|
596
679
|
transports=['websocket'],
|
|
597
680
|
headers={'Foo': 'Bar'},
|
|
598
681
|
)
|
|
599
|
-
|
|
682
|
+
http.ws_connect.assert_awaited_once_with(
|
|
600
683
|
'ws://foo/engine.io/?transport=websocket&EIO=4&t=123.456',
|
|
601
684
|
headers={'Foo': 'Bar', 'Baz': 'Qux'},
|
|
602
685
|
timeout=10,
|
|
@@ -606,28 +689,28 @@ class TestAsyncClient:
|
|
|
606
689
|
@mock.patch('engineio.async_client.aiohttp.ClientWSTimeout',
|
|
607
690
|
new=mock_ws_timeout)
|
|
608
691
|
async def test_websocket_upgrade_failed(self, _time):
|
|
609
|
-
|
|
610
|
-
|
|
611
|
-
c.http.ws_connect = mock.AsyncMock(
|
|
692
|
+
http = mock.MagicMock(closed=False)
|
|
693
|
+
http.ws_connect = mock.AsyncMock(
|
|
612
694
|
side_effect=[aiohttp.client_exceptions.ServerConnectionError()]
|
|
613
695
|
)
|
|
696
|
+
c = async_client.AsyncClient(http_session=lambda: http)
|
|
614
697
|
c.sid = '123'
|
|
615
698
|
assert not await c.connect('http://foo', transports=['websocket'])
|
|
616
|
-
|
|
699
|
+
http.ws_connect.assert_awaited_once_with(
|
|
617
700
|
'ws://foo/engine.io/?transport=websocket&EIO=4&sid=123&t=123.456',
|
|
618
701
|
headers={},
|
|
619
702
|
timeout=5,
|
|
620
703
|
)
|
|
621
704
|
|
|
622
705
|
async def test_websocket_connection_no_open_packet(self):
|
|
623
|
-
|
|
624
|
-
|
|
625
|
-
|
|
626
|
-
ws = c.http.ws_connect.return_value
|
|
706
|
+
http = mock.MagicMock(closed=False)
|
|
707
|
+
http.ws_connect = mock.AsyncMock()
|
|
708
|
+
ws = http.ws_connect.return_value
|
|
627
709
|
ws.receive = mock.AsyncMock()
|
|
628
710
|
ws.receive.return_value.data = packet.Packet(
|
|
629
711
|
packet.CLOSE
|
|
630
712
|
).encode()
|
|
713
|
+
c = async_client.AsyncClient(http_session=lambda: http)
|
|
631
714
|
with pytest.raises(exceptions.ConnectionError):
|
|
632
715
|
await c.connect('http://foo', transports=['websocket'])
|
|
633
716
|
|
|
@@ -635,10 +718,9 @@ class TestAsyncClient:
|
|
|
635
718
|
@mock.patch('engineio.async_client.aiohttp.ClientWSTimeout',
|
|
636
719
|
new=mock_ws_timeout)
|
|
637
720
|
async def test_websocket_connection_successful(self, _time):
|
|
638
|
-
|
|
639
|
-
|
|
640
|
-
|
|
641
|
-
ws = c.http.ws_connect.return_value
|
|
721
|
+
http = mock.MagicMock(closed=False)
|
|
722
|
+
http.ws_connect = mock.AsyncMock()
|
|
723
|
+
ws = http.ws_connect.return_value
|
|
642
724
|
ws.receive = mock.AsyncMock()
|
|
643
725
|
ws.receive.return_value.data = packet.Packet(
|
|
644
726
|
packet.OPEN,
|
|
@@ -649,6 +731,7 @@ class TestAsyncClient:
|
|
|
649
731
|
'pingTimeout': 2000,
|
|
650
732
|
},
|
|
651
733
|
).encode()
|
|
734
|
+
c = async_client.AsyncClient(http_session=lambda: http)
|
|
652
735
|
c._read_loop_polling = mock.AsyncMock()
|
|
653
736
|
c._read_loop_websocket = mock.AsyncMock()
|
|
654
737
|
c._write_loop = mock.AsyncMock()
|
|
@@ -668,7 +751,7 @@ class TestAsyncClient:
|
|
|
668
751
|
assert c.upgrades == []
|
|
669
752
|
assert c.transport() == 'websocket'
|
|
670
753
|
assert c.ws == ws
|
|
671
|
-
|
|
754
|
+
http.ws_connect.assert_awaited_once_with(
|
|
672
755
|
'ws://foo/engine.io/?transport=websocket&EIO=4&t=123.456',
|
|
673
756
|
headers={},
|
|
674
757
|
timeout=5,
|
|
@@ -676,10 +759,9 @@ class TestAsyncClient:
|
|
|
676
759
|
|
|
677
760
|
@mock.patch('engineio.client.time.time', return_value=123.456)
|
|
678
761
|
async def test_websocket_https_noverify_connection_successful(self, _time):
|
|
679
|
-
|
|
680
|
-
|
|
681
|
-
|
|
682
|
-
ws = c.http.ws_connect.return_value
|
|
762
|
+
http = mock.MagicMock(closed=False)
|
|
763
|
+
http.ws_connect = mock.AsyncMock()
|
|
764
|
+
ws = http.ws_connect.return_value
|
|
683
765
|
ws.receive = mock.AsyncMock()
|
|
684
766
|
ws.receive.return_value.data = packet.Packet(
|
|
685
767
|
packet.OPEN,
|
|
@@ -690,6 +772,8 @@ class TestAsyncClient:
|
|
|
690
772
|
'pingTimeout': 2000,
|
|
691
773
|
},
|
|
692
774
|
).encode()
|
|
775
|
+
c = async_client.AsyncClient(
|
|
776
|
+
http_session=lambda: http, ssl_verify=False)
|
|
693
777
|
c._read_loop_polling = mock.AsyncMock()
|
|
694
778
|
c._read_loop_websocket = mock.AsyncMock()
|
|
695
779
|
c._write_loop = mock.AsyncMock()
|
|
@@ -709,7 +793,7 @@ class TestAsyncClient:
|
|
|
709
793
|
assert c.upgrades == []
|
|
710
794
|
assert c.transport() == 'websocket'
|
|
711
795
|
assert c.ws == ws
|
|
712
|
-
_, kwargs =
|
|
796
|
+
_, kwargs = http.ws_connect.await_args
|
|
713
797
|
assert 'ssl' in kwargs
|
|
714
798
|
assert isinstance(kwargs['ssl'], ssl.SSLContext)
|
|
715
799
|
assert kwargs['ssl'].verify_mode == ssl.CERT_NONE
|
|
@@ -718,10 +802,9 @@ class TestAsyncClient:
|
|
|
718
802
|
@mock.patch('engineio.async_client.aiohttp.ClientWSTimeout',
|
|
719
803
|
new=mock_ws_timeout)
|
|
720
804
|
async def test_websocket_connection_with_cookies(self, _time):
|
|
721
|
-
|
|
722
|
-
|
|
723
|
-
|
|
724
|
-
ws = c.http.ws_connect.return_value
|
|
805
|
+
http = mock.MagicMock(closed=False)
|
|
806
|
+
http.ws_connect = mock.AsyncMock()
|
|
807
|
+
ws = http.ws_connect.return_value
|
|
725
808
|
ws.receive = mock.AsyncMock()
|
|
726
809
|
ws.receive.return_value.data = packet.Packet(
|
|
727
810
|
packet.OPEN,
|
|
@@ -732,18 +815,19 @@ class TestAsyncClient:
|
|
|
732
815
|
'pingTimeout': 2000,
|
|
733
816
|
},
|
|
734
817
|
).encode()
|
|
735
|
-
|
|
736
|
-
|
|
737
|
-
|
|
738
|
-
|
|
739
|
-
|
|
818
|
+
http._cookie_jar = [mock.MagicMock(), mock.MagicMock()]
|
|
819
|
+
http._cookie_jar[0].key = 'key'
|
|
820
|
+
http._cookie_jar[0].value = 'value'
|
|
821
|
+
http._cookie_jar[1].key = 'key2'
|
|
822
|
+
http._cookie_jar[1].value = 'value2'
|
|
823
|
+
c = async_client.AsyncClient(http_session=lambda: http)
|
|
740
824
|
c._read_loop_polling = mock.AsyncMock()
|
|
741
825
|
c._read_loop_websocket = mock.AsyncMock()
|
|
742
826
|
c._write_loop = mock.AsyncMock()
|
|
743
827
|
on_connect = mock.MagicMock()
|
|
744
828
|
c.on('connect', on_connect)
|
|
745
829
|
await c.connect('ws://foo', transports=['websocket'])
|
|
746
|
-
|
|
830
|
+
http.ws_connect.assert_awaited_once_with(
|
|
747
831
|
'ws://foo/engine.io/?transport=websocket&EIO=4&t=123.456',
|
|
748
832
|
headers={},
|
|
749
833
|
timeout=5,
|
|
@@ -753,10 +837,9 @@ class TestAsyncClient:
|
|
|
753
837
|
@mock.patch('engineio.async_client.aiohttp.ClientWSTimeout',
|
|
754
838
|
new=mock_ws_timeout)
|
|
755
839
|
async def test_websocket_connection_with_cookie_header(self, _time):
|
|
756
|
-
|
|
757
|
-
|
|
758
|
-
|
|
759
|
-
ws = c.http.ws_connect.return_value
|
|
840
|
+
http = mock.MagicMock(closed=False)
|
|
841
|
+
http.ws_connect = mock.AsyncMock()
|
|
842
|
+
ws = http.ws_connect.return_value
|
|
760
843
|
ws.receive = mock.AsyncMock()
|
|
761
844
|
ws.receive.return_value.data = packet.Packet(
|
|
762
845
|
packet.OPEN,
|
|
@@ -767,7 +850,8 @@ class TestAsyncClient:
|
|
|
767
850
|
'pingTimeout': 2000,
|
|
768
851
|
},
|
|
769
852
|
).encode()
|
|
770
|
-
|
|
853
|
+
http._cookie_jar = []
|
|
854
|
+
c = async_client.AsyncClient(http_session=lambda: http)
|
|
771
855
|
c._read_loop_polling = mock.AsyncMock()
|
|
772
856
|
c._read_loop_websocket = mock.AsyncMock()
|
|
773
857
|
c._write_loop = mock.AsyncMock()
|
|
@@ -778,12 +862,12 @@ class TestAsyncClient:
|
|
|
778
862
|
headers={'Cookie': 'key=value; key2=value2; key3="value3="'},
|
|
779
863
|
transports=['websocket'],
|
|
780
864
|
)
|
|
781
|
-
|
|
865
|
+
http.ws_connect.assert_awaited_once_with(
|
|
782
866
|
'ws://foo/engine.io/?transport=websocket&EIO=4&t=123.456',
|
|
783
867
|
headers={},
|
|
784
868
|
timeout=5,
|
|
785
869
|
)
|
|
786
|
-
|
|
870
|
+
http.cookie_jar.update_cookies.assert_called_once_with(
|
|
787
871
|
{'key': 'value', 'key2': 'value2', 'key3': 'value3='}
|
|
788
872
|
)
|
|
789
873
|
|
|
@@ -791,10 +875,9 @@ class TestAsyncClient:
|
|
|
791
875
|
@mock.patch('engineio.async_client.aiohttp.ClientWSTimeout',
|
|
792
876
|
new=mock_ws_timeout)
|
|
793
877
|
async def test_websocket_connection_with_cookies_and_headers(self, _time):
|
|
794
|
-
|
|
795
|
-
|
|
796
|
-
|
|
797
|
-
ws = c.http.ws_connect.return_value
|
|
878
|
+
http = mock.MagicMock(closed=False)
|
|
879
|
+
http.ws_connect = mock.AsyncMock()
|
|
880
|
+
ws = http.ws_connect.return_value
|
|
798
881
|
ws.receive = mock.AsyncMock()
|
|
799
882
|
ws.receive.return_value.data = packet.Packet(
|
|
800
883
|
packet.OPEN,
|
|
@@ -805,11 +888,12 @@ class TestAsyncClient:
|
|
|
805
888
|
'pingTimeout': 2000,
|
|
806
889
|
},
|
|
807
890
|
).encode()
|
|
808
|
-
|
|
809
|
-
|
|
810
|
-
|
|
811
|
-
|
|
812
|
-
|
|
891
|
+
http._cookie_jar = [mock.MagicMock(), mock.MagicMock()]
|
|
892
|
+
http._cookie_jar[0].key = 'key'
|
|
893
|
+
http._cookie_jar[0].value = 'value'
|
|
894
|
+
http._cookie_jar[1].key = 'key2'
|
|
895
|
+
http._cookie_jar[1].value = 'value2'
|
|
896
|
+
c = async_client.AsyncClient(http_session=lambda: http)
|
|
813
897
|
c._read_loop_polling = mock.AsyncMock()
|
|
814
898
|
c._read_loop_websocket = mock.AsyncMock()
|
|
815
899
|
c._write_loop = mock.AsyncMock()
|
|
@@ -820,20 +904,19 @@ class TestAsyncClient:
|
|
|
820
904
|
headers={'Foo': 'Bar', 'Cookie': 'key3=value3'},
|
|
821
905
|
transports=['websocket'],
|
|
822
906
|
)
|
|
823
|
-
|
|
907
|
+
http.ws_connect.assert_awaited_once_with(
|
|
824
908
|
'ws://foo/engine.io/?transport=websocket&EIO=4&t=123.456',
|
|
825
909
|
headers={'Foo': 'Bar'},
|
|
826
910
|
timeout=5,
|
|
827
911
|
)
|
|
828
|
-
|
|
912
|
+
http.cookie_jar.update_cookies.assert_called_once_with(
|
|
829
913
|
{'key3': 'value3'}
|
|
830
914
|
)
|
|
831
915
|
|
|
832
916
|
async def test_websocket_upgrade_no_pong(self):
|
|
833
|
-
|
|
834
|
-
|
|
835
|
-
|
|
836
|
-
ws = c.http.ws_connect.return_value
|
|
917
|
+
http = mock.MagicMock(closed=False)
|
|
918
|
+
http.ws_connect = mock.AsyncMock()
|
|
919
|
+
ws = http.ws_connect.return_value
|
|
837
920
|
ws.receive = mock.AsyncMock()
|
|
838
921
|
ws.receive.return_value.data = packet.Packet(
|
|
839
922
|
packet.OPEN,
|
|
@@ -845,6 +928,7 @@ class TestAsyncClient:
|
|
|
845
928
|
},
|
|
846
929
|
).encode()
|
|
847
930
|
ws.send_str = mock.AsyncMock()
|
|
931
|
+
c = async_client.AsyncClient(http_session=lambda: http)
|
|
848
932
|
c.sid = '123'
|
|
849
933
|
c.current_transport = 'polling'
|
|
850
934
|
c._read_loop_polling = mock.AsyncMock()
|
|
@@ -862,15 +946,15 @@ class TestAsyncClient:
|
|
|
862
946
|
ws.send_str.assert_awaited_once_with('2probe')
|
|
863
947
|
|
|
864
948
|
async def test_websocket_upgrade_successful(self):
|
|
865
|
-
|
|
866
|
-
|
|
867
|
-
|
|
868
|
-
ws = c.http.ws_connect.return_value
|
|
949
|
+
http = mock.MagicMock(closed=False)
|
|
950
|
+
http.ws_connect = mock.AsyncMock()
|
|
951
|
+
ws = http.ws_connect.return_value
|
|
869
952
|
ws.receive = mock.AsyncMock()
|
|
870
953
|
ws.receive.return_value.data = packet.Packet(
|
|
871
954
|
packet.PONG, 'probe'
|
|
872
955
|
).encode()
|
|
873
956
|
ws.send_str = mock.AsyncMock()
|
|
957
|
+
c = async_client.AsyncClient(http_session=lambda: http)
|
|
874
958
|
c.sid = '123'
|
|
875
959
|
c.base_url = 'http://foo'
|
|
876
960
|
c.current_transport = 'polling'
|
|
@@ -716,6 +716,18 @@ class TestAsyncServer:
|
|
|
716
716
|
assert len(s.sockets) == 0
|
|
717
717
|
assert a._async['make_response'].call_args[0][0] == '400 BAD REQUEST'
|
|
718
718
|
|
|
719
|
+
@mock.patch('importlib.import_module')
|
|
720
|
+
async def test_post_request_after_upgrade(self, import_module):
|
|
721
|
+
a = self.get_async_mock(
|
|
722
|
+
{'REQUEST_METHOD': 'POST', 'QUERY_STRING': 'sid=foo'}
|
|
723
|
+
)
|
|
724
|
+
import_module.side_effect = [a]
|
|
725
|
+
s = async_server.AsyncServer()
|
|
726
|
+
s.sockets['foo'] = self._get_mock_socket()
|
|
727
|
+
s.sockets['foo'].upgraded = True
|
|
728
|
+
await s.handle_request('request')
|
|
729
|
+
assert a._async['make_response'].call_args[0][0] == '400 BAD REQUEST'
|
|
730
|
+
|
|
719
731
|
@mock.patch('importlib.import_module')
|
|
720
732
|
async def test_send(self, import_module):
|
|
721
733
|
a = self.get_async_mock()
|
|
@@ -44,6 +44,17 @@ class TestClient:
|
|
|
44
44
|
assert c.queue.__class__.__name__ == 'Queue'
|
|
45
45
|
assert c.queue_empty.__name__ == 'Empty'
|
|
46
46
|
|
|
47
|
+
def test_external_session(self):
|
|
48
|
+
c = client.Client(http_session='foo')
|
|
49
|
+
assert c.http == 'foo'
|
|
50
|
+
assert c.external_http
|
|
51
|
+
|
|
52
|
+
def test_callable_session(self):
|
|
53
|
+
c = client.Client(http_session=lambda: 'foo')
|
|
54
|
+
assert c.http is None
|
|
55
|
+
assert c.http_factory() == 'foo'
|
|
56
|
+
assert c.external_http is False
|
|
57
|
+
|
|
47
58
|
def test_custom_json(self):
|
|
48
59
|
client.Client()
|
|
49
60
|
assert packet.Packet.json == json
|
|
@@ -352,6 +363,22 @@ class TestClient:
|
|
|
352
363
|
e.set()
|
|
353
364
|
assert e.is_set()
|
|
354
365
|
|
|
366
|
+
@mock.patch('engineio.client.requests.Session')
|
|
367
|
+
def test_polling_connection_default_session(self, _session):
|
|
368
|
+
_session.return_value.request.return_value.status_code = 200
|
|
369
|
+
_session.return_value.request.return_value.content = payload.Payload(
|
|
370
|
+
packets=[
|
|
371
|
+
packet.Packet(
|
|
372
|
+
packet.MESSAGE, # incorrect on purpose
|
|
373
|
+
{},
|
|
374
|
+
)
|
|
375
|
+
]
|
|
376
|
+
).encode().encode('utf-8')
|
|
377
|
+
c = client.Client()
|
|
378
|
+
with pytest.raises(exceptions.ConnectionError,
|
|
379
|
+
match='OPEN packet not returned by server'):
|
|
380
|
+
c.connect('http://foo', headers={'Foo': 'Bar'})
|
|
381
|
+
|
|
355
382
|
@mock.patch('engineio.client.time.time', return_value=123.456)
|
|
356
383
|
@mock.patch('engineio.client.Client._send_request', return_value=None)
|
|
357
384
|
def test_polling_connection_failed(self, _send_request, _time):
|
|
@@ -796,7 +823,7 @@ class TestClient:
|
|
|
796
823
|
http.auth = None
|
|
797
824
|
http.proxies = None
|
|
798
825
|
http.cert = None
|
|
799
|
-
c = client.Client(http_session=http)
|
|
826
|
+
c = client.Client(http_session=lambda: http)
|
|
800
827
|
c._read_loop_polling = mock.MagicMock()
|
|
801
828
|
c._read_loop_websocket = mock.MagicMock()
|
|
802
829
|
c._write_loop = mock.MagicMock()
|
|
@@ -829,7 +856,7 @@ class TestClient:
|
|
|
829
856
|
http.auth = None
|
|
830
857
|
http.proxies = None
|
|
831
858
|
http.cert = None
|
|
832
|
-
c = client.Client(http_session=http)
|
|
859
|
+
c = client.Client(http_session=lambda: http)
|
|
833
860
|
c._read_loop_polling = mock.MagicMock()
|
|
834
861
|
c._read_loop_websocket = mock.MagicMock()
|
|
835
862
|
c._write_loop = mock.MagicMock()
|
|
@@ -872,7 +899,7 @@ class TestClient:
|
|
|
872
899
|
http.auth = None
|
|
873
900
|
http.proxies = None
|
|
874
901
|
http.cert = None
|
|
875
|
-
c = client.Client(http_session=http)
|
|
902
|
+
c = client.Client(http_session=lambda: http)
|
|
876
903
|
c._read_loop_polling = mock.MagicMock()
|
|
877
904
|
c._read_loop_websocket = mock.MagicMock()
|
|
878
905
|
c._write_loop = mock.MagicMock()
|
|
@@ -909,7 +936,7 @@ class TestClient:
|
|
|
909
936
|
http.auth = ('foo', 'bar')
|
|
910
937
|
http.proxies = None
|
|
911
938
|
http.cert = None
|
|
912
|
-
c = client.Client(http_session=http)
|
|
939
|
+
c = client.Client(http_session=lambda: http)
|
|
913
940
|
c._read_loop_polling = mock.MagicMock()
|
|
914
941
|
c._read_loop_websocket = mock.MagicMock()
|
|
915
942
|
c._write_loop = mock.MagicMock()
|
|
@@ -941,7 +968,7 @@ class TestClient:
|
|
|
941
968
|
http.auth = None
|
|
942
969
|
http.proxies = None
|
|
943
970
|
http.cert = 'foo.crt'
|
|
944
|
-
c = client.Client(http_session=http, ssl_verify=False)
|
|
971
|
+
c = client.Client(http_session=lambda: http, ssl_verify=False)
|
|
945
972
|
c._read_loop_polling = mock.MagicMock()
|
|
946
973
|
c._read_loop_websocket = mock.MagicMock()
|
|
947
974
|
c._write_loop = mock.MagicMock()
|
|
@@ -974,7 +1001,7 @@ class TestClient:
|
|
|
974
1001
|
http.auth = None
|
|
975
1002
|
http.proxies = None
|
|
976
1003
|
http.cert = ('foo.crt', 'key.pem')
|
|
977
|
-
c = client.Client(http_session=http)
|
|
1004
|
+
c = client.Client(http_session=lambda: http)
|
|
978
1005
|
c._read_loop_polling = mock.MagicMock()
|
|
979
1006
|
c._read_loop_websocket = mock.MagicMock()
|
|
980
1007
|
c._write_loop = mock.MagicMock()
|
|
@@ -1010,7 +1037,7 @@ class TestClient:
|
|
|
1010
1037
|
http.proxies = None
|
|
1011
1038
|
http.cert = ('foo.crt', 'key.pem')
|
|
1012
1039
|
http.verify = 'ca-bundle.crt'
|
|
1013
|
-
c = client.Client(http_session=http)
|
|
1040
|
+
c = client.Client(http_session=lambda: http)
|
|
1014
1041
|
c._read_loop_polling = mock.MagicMock()
|
|
1015
1042
|
c._read_loop_websocket = mock.MagicMock()
|
|
1016
1043
|
c._write_loop = mock.MagicMock()
|
|
@@ -1076,7 +1103,7 @@ class TestClient:
|
|
|
1076
1103
|
http.auth = None
|
|
1077
1104
|
http.proxies = proxies
|
|
1078
1105
|
http.cert = None
|
|
1079
|
-
c = client.Client(http_session=http)
|
|
1106
|
+
c = client.Client(http_session=lambda: http)
|
|
1080
1107
|
c._read_loop_polling = mock.MagicMock()
|
|
1081
1108
|
c._read_loop_websocket = mock.MagicMock()
|
|
1082
1109
|
c._write_loop = mock.MagicMock()
|
|
@@ -1115,7 +1142,7 @@ class TestClient:
|
|
|
1115
1142
|
http.proxies = None
|
|
1116
1143
|
http.cert = None
|
|
1117
1144
|
http.verify = False
|
|
1118
|
-
c = client.Client(http_session=http)
|
|
1145
|
+
c = client.Client(http_session=lambda: http)
|
|
1119
1146
|
c._read_loop_polling = mock.MagicMock()
|
|
1120
1147
|
c._read_loop_websocket = mock.MagicMock()
|
|
1121
1148
|
c._write_loop = mock.MagicMock()
|
|
@@ -1149,7 +1176,7 @@ class TestClient:
|
|
|
1149
1176
|
http.proxies = None
|
|
1150
1177
|
http.cert = None
|
|
1151
1178
|
http.verify = 'ca-bundle.crt'
|
|
1152
|
-
c = client.Client(http_session=http)
|
|
1179
|
+
c = client.Client(http_session=lambda: http)
|
|
1153
1180
|
c._read_loop_polling = mock.MagicMock()
|
|
1154
1181
|
c._read_loop_websocket = mock.MagicMock()
|
|
1155
1182
|
c._write_loop = mock.MagicMock()
|
|
@@ -85,6 +85,8 @@ class TestWSGIApp:
|
|
|
85
85
|
'Not Found')
|
|
86
86
|
check_path('/bar/foo', '404 Not Found', 'text/plain', 'Not Found')
|
|
87
87
|
check_path('', '404 Not Found', 'text/plain', 'Not Found')
|
|
88
|
+
check_path('/static/../../LICENSE', '404 Not Found', 'text/plain',
|
|
89
|
+
'Not Found')
|
|
88
90
|
|
|
89
91
|
m.static_files[''] = 'index.html'
|
|
90
92
|
check_path('/static/test/', '200 OK', 'text/html', '<html></html>\n')
|
|
@@ -859,6 +859,17 @@ class TestServer:
|
|
|
859
859
|
s.handle_request(environ, start_response)
|
|
860
860
|
assert start_response.call_args[0][0] == '400 BAD REQUEST'
|
|
861
861
|
|
|
862
|
+
def test_post_request_after_upgrade(self):
|
|
863
|
+
s = server.Server()
|
|
864
|
+
mock_socket = self._get_mock_socket()
|
|
865
|
+
mock_socket.upgraded = True
|
|
866
|
+
mock_socket.handle_post_request = mock.MagicMock()
|
|
867
|
+
s.sockets['foo'] = mock_socket
|
|
868
|
+
environ = {'REQUEST_METHOD': 'POST', 'QUERY_STRING': 'EIO=4&sid=foo'}
|
|
869
|
+
start_response = mock.MagicMock()
|
|
870
|
+
s.handle_request(environ, start_response)
|
|
871
|
+
assert start_response.call_args[0][0] == '400 BAD REQUEST'
|
|
872
|
+
|
|
862
873
|
def test_send(self):
|
|
863
874
|
s = server.Server()
|
|
864
875
|
mock_socket = self._get_mock_socket()
|
|
@@ -17,6 +17,12 @@ deps=
|
|
|
17
17
|
commands=
|
|
18
18
|
flake8 --exclude=".*" --ignore=W503,E402,E722 src/engineio tests examples
|
|
19
19
|
|
|
20
|
+
[testenv:zizmor]
|
|
21
|
+
deps=
|
|
22
|
+
zizmor
|
|
23
|
+
commands=
|
|
24
|
+
zizmor --offline .forgejo/workflows/tests.yml
|
|
25
|
+
|
|
20
26
|
[testenv:docs]
|
|
21
27
|
changedir=docs
|
|
22
28
|
deps=
|
|
@@ -26,3 +32,16 @@ allowlist_externals=
|
|
|
26
32
|
make
|
|
27
33
|
commands=
|
|
28
34
|
make html
|
|
35
|
+
|
|
36
|
+
[testenv:lint]
|
|
37
|
+
deps=
|
|
38
|
+
flake8
|
|
39
|
+
zizmor
|
|
40
|
+
sphinx
|
|
41
|
+
furo
|
|
42
|
+
allowlist_externals=
|
|
43
|
+
make
|
|
44
|
+
commands=
|
|
45
|
+
flake8 --exclude=".*" --ignore=W503,E402,E722 src/engineio tests examples
|
|
46
|
+
zizmor --offline .forgejo/workflows/tests.yml
|
|
47
|
+
make -C docs html
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{python_engineio-4.14.0 → python_engineio-4.15.0}/src/engineio/async_drivers/_websocket_wsgi.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{python_engineio-4.14.0 → python_engineio-4.15.0}/src/engineio/async_drivers/gevent_uwsgi.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{python_engineio-4.14.0 → python_engineio-4.15.0}/src/python_engineio.egg-info/dependency_links.txt
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
{python_engineio-4.14.0 → python_engineio-4.15.0}/src/python_engineio.egg-info/top_level.txt
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|