Fix ReverseProxied middleware and add docs (#1873)

Starlette introduced some new changes to how the `root_path` is handled,
which broke our `ReverseProxied` example and test.

This PR fixes both and adds documentation on how to run behind a proxy.
This commit is contained in:
Robbe Sneyders
2024-02-11 22:19:37 +01:00
committed by GitHub
parent f8f461c524
commit 3e64fe46e9
4 changed files with 38 additions and 9 deletions

View File

@@ -116,3 +116,32 @@ Starlette. You can add it to your application, ideally in front of the ``Routing
:noindex:
.. _CORSMiddleware: https://www.starlette.io/middleware/#corsmiddleware
Reverse Proxy
-------------
When running behind a reverse proxy with stripped path prefix, you need to configure your
application to properly handle this.
Single known path prefix
''''''''''''''''''''''''
If there is only a single known prefix your application will be running behind, you can simply
pass this path prefix as the `root_path` to your ASGI server:
.. code-block:: bash
$ uvicorn run:app --root-path <root_path>
.. code-block:: bash
$ gunicorn -k uvicorn.workers.UvicornWorker run:app --root-path <root_path>
Dynamic path prefix
'''''''''''''''''''
If you are running behind multiple proxies, or the path is not known, you can wrap your
application in a `ReverseProxied` middleware as shown in `this example`_.
.. _this example: https://github.com/spec-first/connexion/tree/main/examples/reverseproxy

View File

@@ -54,10 +54,10 @@ class ReverseProxied:
root_path = value.decode()
break
if root_path:
scope["root_path"] = "/" + root_path.strip("/")
path_info = scope.get("PATH_INFO", scope.get("path"))
if path_info.startswith(root_path):
scope["PATH_INFO"] = path_info[len(root_path) :]
root_path = "/" + root_path.strip("/")
scope["root_path"] = root_path
scope["path"] = root_path + scope.get("path", "")
scope["raw_path"] = root_path.encode() + scope.get("raw_path", "")
scope["scheme"] = scope.get("scheme") or self.scheme
scope["server"] = scope.get("server") or (self.server, None)

View File

@@ -53,7 +53,7 @@ Jinja2 = ">= 3.0.0"
python-multipart = ">= 0.0.5"
PyYAML = ">= 5.1"
requests = ">= 2.27"
starlette = ">= 0.27"
starlette = ">= 0.35"
typing-extensions = ">= 4"
werkzeug = ">= 2.2.1"

View File

@@ -73,10 +73,10 @@ def reverse_proxied_app(spec, app_class):
root_path = value.decode()
break
if root_path:
scope["root_path"] = "/" + root_path.strip("/")
path_info = scope.get("PATH_INFO", scope.get("path"))
if path_info.startswith(root_path):
scope["PATH_INFO"] = path_info[len(root_path) :]
root_path = "/" + root_path.strip("/")
scope["root_path"] = root_path
scope["path"] = root_path + scope.get("path", "")
scope["raw_path"] = root_path.encode() + scope.get("raw_path", "")
scope["scheme"] = scope.get("scheme") or self.scheme
scope["server"] = scope.get("server") or (self.server, None)