forwarded.py 1.7 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243
  1. from starlette.types import ASGIApp, Receive, Scope, Send
  2. class ForwardedHostPortMiddleware:
  3. """
  4. Middleware to support X-Forwarded-Host.
  5. It rewrites the 'server' and 'headers' in the ASGI scope accordingly.
  6. """
  7. def __init__(self, app: ASGIApp):
  8. self.app = app
  9. async def __call__(self, scope: Scope, receive: Receive, send: Send):
  10. if scope["type"] == "http":
  11. headers = dict((k.lower(), v) for k, v in scope.get("headers", []))
  12. # X-Forwarded-Host
  13. xfh = headers.get(b"x-forwarded-host")
  14. if xfh:
  15. # Only use the first value if multiple hosts are present
  16. host = xfh.split(b",")[0].strip()
  17. # Update the host header
  18. new_headers = [
  19. (k, v) if k != b"host" else (b"host", host)
  20. for k, v in scope["headers"]
  21. ]
  22. # If no host header, add it
  23. if not any(k == b"host" for k, _ in new_headers):
  24. new_headers.append((b"host", host))
  25. scope["headers"] = new_headers
  26. # Optionally update scope["server"]
  27. server = list(scope.get("server", (None, None)))
  28. try:
  29. host_str = host.decode()
  30. if ":" in host_str:
  31. host_name, host_port = host_str.rsplit(":", 1)
  32. server[0] = host_name
  33. server[1] = int(host_port)
  34. else:
  35. server[0] = host_str
  36. except Exception:
  37. pass
  38. scope["server"] = tuple(server)
  39. await self.app(scope, receive, send)