diff --git a/engineio/async_drivers/asgi.py b/engineio/async_drivers/asgi.py index 64ac4d40..9f8d9ceb 100644 --- a/engineio/async_drivers/asgi.py +++ b/engineio/async_drivers/asgi.py @@ -40,54 +40,50 @@ def __init__(self, engineio_server, other_asgi_app=None, self.engineio_path = engineio_path.strip('/') self.static_files = static_files or {} - def __call__(self, scope): + async def __call__(self, scope, receive, send): if scope['type'] in ['http', 'websocket'] and \ scope['path'].startswith('/{0}/'.format(self.engineio_path)): - return self.engineio_asgi_app(scope) + await self.engineio_asgi_app(scope, receive, send) elif scope['type'] == 'http' and scope['path'] in self.static_files: - return self.serve_static_file(scope) + await self.serve_static_file(scope, receive, send) elif self.other_asgi_app is not None: - return self.other_asgi_app(scope) + await self.other_asgi_app(scope, receive, send) elif scope['type'] == 'lifespan': - return self.lifespan + await self.lifespan(scope, receive, send) else: - return self.not_found + await self.not_found(scope, receive, send) - def engineio_asgi_app(self, scope): - async def _app(receive, send): - await self.engineio_server.handle_request(scope, receive, send) - return _app + async def engineio_asgi_app(self, scope, receive, send): + await self.engineio_server.handle_request(scope, receive, send) - def serve_static_file(self, scope): - async def _send_static_file(receive, send): # pragma: no cover - event = await receive() - if event['type'] == 'http.request': - if scope['path'] in self.static_files: - content_type = self.static_files[scope['path']][ - 'content_type'].encode('utf-8') - filename = self.static_files[scope['path']]['filename'] - status_code = 200 - with open(filename, 'rb') as f: - payload = f.read() - else: - content_type = b'text/plain' - status_code = 404 - payload = b'not found' - await send({'type': 'http.response.start', - 'status': status_code, - 'headers': [(b'Content-Type', content_type)]}) - await send({'type': 'http.response.body', - 'body': payload}) - return _send_static_file - - async def lifespan(self, receive, send): + async def serve_static_file(self, scope, receive, send): + event = await receive() + if event['type'] == 'http.request': + if scope['path'] in self.static_files: + content_type = self.static_files[scope['path']][ + 'content_type'].encode('utf-8') + filename = self.static_files[scope['path']]['filename'] + status_code = 200 + with open(filename, 'rb') as f: + payload = f.read() + else: + content_type = b'text/plain' + status_code = 404 + payload = b'not found' + await send({'type': 'http.response.start', + 'status': status_code, + 'headers': [(b'Content-Type', content_type)]}) + await send({'type': 'http.response.body', + 'body': payload}) + + async def lifespan(self, scope, receive, send): event = await receive() if event['type'] == 'lifespan.startup': await send({'type': 'lifespan.startup.complete'}) elif event['type'] == 'lifespan.shutdown': await send({'type': 'lifespan.shutdown.complete'}) - async def not_found(self, receive, send): + async def not_found(self, scope, receive, send): """Return a 404 Not Found error to the client.""" await send({'type': 'http.response.start', 'status': 404, diff --git a/tests/asyncio/test_async_asgi.py b/tests/asyncio/test_async_asgi.py index 035bf65f..a5e7b9e0 100644 --- a/tests/asyncio/test_async_asgi.py +++ b/tests/asyncio/test_async_asgi.py @@ -45,17 +45,16 @@ def test_engineio_routing(self): mock_server.handle_request = AsyncMock() app = async_asgi.ASGIApp(mock_server) scope = {'type': 'http', 'path': '/engine.io/'} - handler = app(scope) - _run(handler('receive', 'send')) + _run(app(scope, 'receive', 'send')) mock_server.handle_request.mock.assert_called_once_with( scope, 'receive', 'send') def test_other_app_routing(self): - other_app = mock.MagicMock() + other_app = AsyncMock() app = async_asgi.ASGIApp('eio', other_app) scope = {'type': 'http', 'path': '/foo'} - app(scope) - other_app.assert_called_once_with(scope) + _run(app(scope, 'receive', 'send')) + other_app.mock.assert_called_once_with(scope, 'receive', 'send') def test_static_file_routing(self): root_dir = os.path.dirname(__file__) @@ -63,45 +62,45 @@ def test_static_file_routing(self): '/foo': {'content_type': 'text/html', 'filename': root_dir + '/index.html'} }) - handler = app({'type': 'http', 'path': '/foo'}) + scope = {'type': 'http', 'path': '/foo'} receive = AsyncMock(return_value={'type': 'http.request'}) send = AsyncMock() - _run(handler(receive, send)) + _run(app(scope, receive, send)) send.mock.assert_called_with({'type': 'http.response.body', 'body': b'\n'}) def test_lifespan_startup(self): app = async_asgi.ASGIApp('eio') - handler = app({'type': 'lifespan'}) + scope = {'type': 'lifespan'} receive = AsyncMock(return_value={'type': 'lifespan.startup'}) send = AsyncMock() - _run(handler(receive, send)) + _run(app(scope, receive, send)) send.mock.assert_called_once_with( {'type': 'lifespan.startup.complete'}) def test_lifespan_shutdown(self): app = async_asgi.ASGIApp('eio') - handler = app({'type': 'lifespan'}) + scope = {'type': 'lifespan'} receive = AsyncMock(return_value={'type': 'lifespan.shutdown'}) send = AsyncMock() - _run(handler(receive, send)) + _run(app(scope, receive, send)) send.mock.assert_called_once_with( {'type': 'lifespan.shutdown.complete'}) def test_lifespan_invalid(self): app = async_asgi.ASGIApp('eio') - handler = app({'type': 'lifespan'}) + scope = {'type': 'lifespan'} receive = AsyncMock(return_value={'type': 'lifespan.foo'}) send = AsyncMock() - _run(handler(receive, send)) + _run(app(scope, receive, send)) send.mock.assert_not_called() def test_not_found(self): app = async_asgi.ASGIApp('eio') - handler = app({'type': 'http', 'path': '/foo'}) + scope = {'type': 'http', 'path': '/foo'} receive = AsyncMock(return_value={'type': 'http.request'}) send = AsyncMock() - _run(handler(receive, send)) + _run(app(scope, receive, send)) send.mock.assert_any_call( {'type': 'http.response.start', 'status': 404, 'headers': [(b'Content-Type', b'text/plain')]})