e4dcfc49aa
Tests / Import Check (Python 3.13) (push) Has been cancelled
Tests / Import Check (Python 3.14) (push) Has been cancelled
Tests / Python Tests (Python 3.11) (push) Has been cancelled
Tests / Python Tests (Python 3.12) (push) Has been cancelled
Tests / Python Tests (Python 3.14) (push) Has been cancelled
Tests / Test Summary (push) Has been cancelled
Tests / Lint and Format (push) Has been cancelled
Tests / Web Node Tests (push) Has been cancelled
Tests / Import Check (Python 3.11) (push) Has been cancelled
Tests / Import Check (Python 3.12) (push) Has been cancelled
Tests / Python Tests (Python 3.13) (push) Has been cancelled
56 lines
1.6 KiB
Python
56 lines
1.6 KiB
Python
from __future__ import annotations
|
|
|
|
import re
|
|
from typing import Any, Iterable
|
|
from urllib.parse import urlparse
|
|
|
|
_ORIGIN_SEPARATORS = re.compile(r"[,;\n]+")
|
|
|
|
|
|
def _raw_origin_items(value: Any) -> Iterable[str]:
|
|
if value is None:
|
|
return []
|
|
if isinstance(value, (list, tuple, set)):
|
|
items: list[str] = []
|
|
for item in value:
|
|
items.extend(_raw_origin_items(item))
|
|
return items
|
|
return _ORIGIN_SEPARATORS.split(str(value))
|
|
|
|
|
|
def normalize_origin(value: Any) -> str:
|
|
"""Normalize a browser Origin value for CORS allowlists.
|
|
|
|
Operators often paste values as ``host:port`` or separate multiple origins
|
|
with semicolons. Browsers always send an Origin as ``scheme://host[:port]``.
|
|
This helper makes common deployment input tolerant while keeping the output
|
|
as exact origins for Starlette's CORSMiddleware.
|
|
"""
|
|
|
|
origin = str(value or "").strip().rstrip("/")
|
|
if not origin:
|
|
return ""
|
|
if origin in {"*", "null"}:
|
|
return origin
|
|
if "://" not in origin:
|
|
origin = f"http://{origin}"
|
|
|
|
try:
|
|
parsed = urlparse(origin)
|
|
except ValueError:
|
|
return origin
|
|
if parsed.scheme in {"http", "https"} and parsed.netloc:
|
|
return f"{parsed.scheme}://{parsed.netloc}".rstrip("/")
|
|
return origin
|
|
|
|
|
|
def normalize_origins(value: Any) -> list[str]:
|
|
origins: list[str] = []
|
|
seen: set[str] = set()
|
|
for raw in _raw_origin_items(value):
|
|
origin = normalize_origin(raw)
|
|
if origin and origin not in seen:
|
|
origins.append(origin)
|
|
seen.add(origin)
|
|
return origins
|