pgjones / hypercorn

Hypercorn is an ASGI and WSGI Server based on Hyper libraries and inspired by Gunicorn.

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

Support for add_middleware()

gellnerm opened this issue · comments

Thank you for making hypercorn.

As per the fastapi documentation the recommended way to add a middleware is to use

app.add_middleware(Middleware)

However, this does not work, at least for the ProxyFixMiddleware. When used this way, this is the exception stack when making a request:

[2024-01-02 12:42:02 +0100] [36653] [ERROR] Error in ASGI Framework
Traceback (most recent call last):
File "lib/python3.11/site-packages/hypercorn/asyncio/task_group.py", line 27, in _handle
await app(scope, receive, send, sync_spawn, call_soon)
File "lib/python3.11/site-packages/hypercorn/app_wrappers.py", line 34, in call
await self.app(scope, receive, send)
File "lib/python3.11/site-packages/fastapi/applications.py", line 1106, in call
await super().call(scope, receive, send)
File "lib/python3.11/site-packages/starlette/applications.py", line 122, in call
await self.middleware_stack(scope, receive, send)
File "lib/python3.11/site-packages/starlette/middleware/errors.py", line 184, in call
raise exc
File "lib/python3.11/site-packages/starlette/middleware/errors.py", line 162, in call
await self.app(scope, receive, _send)
File "lib/python3.11/site-packages/hypercorn/middleware/proxy_fix.py", line 22, in call
scope = deepcopy(scope)
^^^^^^^^^^^^^^^
File "lib/python3.11/copy.py", line 146, in deepcopy
y = copier(x, memo)
^^^^^^^^^^^^^^^
File "lib/python3.11/copy.py", line 231, in _deepcopy_dict
y[deepcopy(key, memo)] = deepcopy(value, memo)
^^^^^^^^^^^^^^^^^^^^^
File "lib/python3.11/copy.py", line 172, in deepcopy
y = _reconstruct(x, memo, *rv)
^^^^^^^^^^^^^^^^^^^^^^^^^^
File "lib/python3.11/copy.py", line 271, in _reconstruct
state = deepcopy(state, memo)
^^^^^^^^^^^^^^^^^^^^^
File "lib/python3.11/copy.py", line 146, in deepcopy
y = copier(x, memo)
^^^^^^^^^^^^^^^
File "lib/python3.11/copy.py", line 231, in _deepcopy_dict
y[deepcopy(key, memo)] = deepcopy(value, memo)
^^^^^^^^^^^^^^^^^^^^^
File "lib/python3.11/copy.py", line 172, in deepcopy
y = _reconstruct(x, memo, *rv)
^^^^^^^^^^^^^^^^^^^^^^^^^^
File "lib/python3.11/copy.py", line 272, in _reconstruct
if hasattr(y, 'setstate'):
^^^^^^^^^^^^^^^^^^^^^^^^^^
File "lib/python3.11/site-packages/starlette/datastructures.py", line 702, in getattr
return self._state[key]
^^^^^^^^^^^
File "lib/python3.11/site-packages/starlette/datastructures.py", line 702, in getattr
return self._state[key]
^^^^^^^^^^^
File "lib/python3.11/site-packages/starlette/datastructures.py", line 702, in getattr
return self._state[key]
^^^^^^^^^^^
[Previous line repeated 959 more times]
File "lib/python3.11/site-packages/starlette/datastructures.py", line 700, in getattr
def getattr(self, key: typing.Any) -> typing.Any:

File "lib/python3.11/site-packages/starlette/datastructures.py", line 700, in getattr
def getattr(self, key: typing.Any) -> typing.Any:

RecursionError: maximum recursion depth exceeded

Minimal example:

import asyncio

from fastapi import FastAPI, Request
from hypercorn.asyncio import serve
from hypercorn.config import Config
from hypercorn.middleware import ProxyFixMiddleware

app = FastAPI()
app.add_middleware(ProxyFixMiddleware, mode='modern', trusted_hops=1)

@app.get('/test1/{test}')
def test1(request: Request, test: str):  # @UnusedVariable
    return {'dd': 1}


if __name__ == '__main__':
    config = Config()
    config.bind = ['127.0.0.1:8000', '[::1]:8000']
    asyncio.run(serve(app, config))

@Kludex I think Starlette is doing the wrong thing here as per django/asgiref#343, what do you think?

I did fix that on the last release: encode/starlette#2352. What Starlette version is being used here?

Also, kind a related, it would be cool if you can check django/asgiref#424. 🙏

EDIT: I just saw there's FastAPI on the traceback - FastAPI still doesn't support the last Starlette version.

What Starlette version is being used here?

0.27.0