Neoteroi / BlackSheep

Fast ASGI web framework for Python
https://www.neoteroi.dev/blacksheep/
MIT License
1.86k stars 78 forks source link

Automatically use the ASGI scope `root_path` field #372

Closed waweber closed 1 year ago

waweber commented 1 year ago

🚀 Feature Request

ASGI servers sitting behind a reverse proxy often have their routes served at a URL prefix.

For example, this route:

@app.route("/example")
def example():
    return "Example"

Might be served at https://example.com/app/example, with a server like nginx rewriting requests for /app/example to /example before forwarding them to the ASGI application.

The application doesn't need to know about this, everything works just fine on the routing side. But if you use something like get_absolute_url_to_path() it would return https://example.com/example, which is incorrect.

The Request object has a base_path property that is taken into account, and the correct URL is returned when it is set to "/app", but nothing currently seems to set this value automatically.

The ASGI scope defines a field called "root_path" which contains the correct value to use for Request.base_path. It is configured/sent by the ASGI server (like uvicorn --root-path /app ...) so this value could very easily be used to automatically set the base_path without any specific configuration of the application.

In the meantime, I am using a very simple middleware to handle this, but it would be nice if this was included automatically:

async def set_base_path(request, handler):
    """Middleware to set base_path from the ASGI scope's root_path field."""
    request.base_path = request.scope.get("root_path", "")
    return await handler(request)
RobertoPrevato commented 1 year ago

Hi @waweber, Thank You for your recommendation! You are absolutely right, that is a right thing to do. I probably missed that the ASGI scope included that property, when I was working on that feature (I added the base_path and methods to build the full URL in the same period I worked on the built-in support for OpenID Connect).

RobertoPrevato commented 1 year ago

Fixed on main - can be fixed also on v1.

RobertoPrevato commented 1 year ago

Fixed at 1.2.17.