diff --git a/src/engineio/async_drivers/asgi.py b/src/engineio/async_drivers/asgi.py index cd1dd0e..bd50226 100644 --- a/src/engineio/async_drivers/asgi.py +++ b/src/engineio/async_drivers/asgi.py @@ -63,7 +63,8 @@ async def __call__(self, scope, receive, send): await self.lifespan(scope, receive, send) elif scope['type'] in ['http', 'websocket'] and ( self.engineio_path is None - or scope['path'].startswith(self.engineio_path)): + or self._ensure_trailing_slash(scope['path']).startswith( + self.engineio_path)): await self.engineio_server.handle_request(scope, receive, send) else: static_file = get_static_file(scope['path'], self.static_files) \ @@ -127,6 +128,11 @@ async def not_found(self, receive, send): await send({'type': 'http.response.body', 'body': b'Not Found'}) + def _ensure_trailing_slash(self, path): + if not path.endswith('/'): + path += '/' + return path + async def translate_request(scope, receive, send): class AwaitablePayload(object): # pragma: no cover diff --git a/tests/async/test_asgi.py b/tests/async/test_asgi.py index 62a6447..d45b63c 100644 --- a/tests/async/test_asgi.py +++ b/tests/async/test_asgi.py @@ -38,12 +38,55 @@ def test_create_app(self): def test_engineio_routing(self): mock_server = mock.MagicMock() mock_server.handle_request = AsyncMock() + app = async_asgi.ASGIApp(mock_server) scope = {'type': 'http', 'path': '/engine.io/'} _run(app(scope, 'receive', 'send')) mock_server.handle_request.mock.assert_called_once_with( scope, 'receive', 'send' ) + mock_server.handle_request.mock.reset_mock() + scope = {'type': 'http', 'path': '/engine.io/'} + _run(app(scope, 'receive', 'send')) + mock_server.handle_request.mock.assert_called_once_with( + scope, 'receive', 'send' + ) + mock_server.handle_request.mock.reset_mock() + scope = {'type': 'http', 'path': '/engine.iofoo/'} + _run(app(scope, 'receive', AsyncMock())) + mock_server.handle_request.mock.assert_not_called() + + app = async_asgi.ASGIApp(mock_server, engineio_path=None) + mock_server.handle_request.mock.reset_mock() + scope = {'type': 'http', 'path': '/foo'} + _run(app(scope, 'receive', 'send')) + mock_server.handle_request.mock.assert_called_once_with( + scope, 'receive', 'send' + ) + + app = async_asgi.ASGIApp(mock_server, engineio_path='mysocket.io') + mock_server.handle_request.mock.reset_mock() + scope = {'type': 'http', 'path': '/mysocket.io'} + _run(app(scope, 'receive', 'send')) + mock_server.handle_request.mock.assert_called_once_with( + scope, 'receive', 'send' + ) + mock_server.handle_request.mock.reset_mock() + scope = {'type': 'http', 'path': '/mysocket.io/'} + _run(app(scope, 'receive', 'send')) + mock_server.handle_request.mock.assert_called_once_with( + scope, 'receive', 'send' + ) + mock_server.handle_request.mock.reset_mock() + scope = {'type': 'http', 'path': '/mysocket.io/foo'} + _run(app(scope, 'receive', 'send')) + mock_server.handle_request.mock.assert_called_once_with( + scope, 'receive', 'send' + ) + mock_server.handle_request.mock.reset_mock() + scope = {'type': 'http', 'path': '/mysocket.iofoo'} + _run(app(scope, 'receive', AsyncMock())) + mock_server.handle_request.mock.assert_not_called() def test_other_app_routing(self): other_app = AsyncMock()