Static site server for the published MAMUT-routing website.
Replaces the Julia HTTP.jl webapp on the serving side: the public website
is fully static, so this serves exactly three things and nothing else:
- the built
dist/ tree (resolved first, like the Julia server did);
- the repo artifact roots that payload links reference by repo-relative
path (
LICENSE, benchmarks, dist), with traversal containment;
/healthz (also mirrored at /api/healthz so existing smoke tests
and monitoring keep working across the cutover).
Serving quality the Julia server lacked in rootless mode: real
Cache-Control policy instead of a universal no-store, strong ETags
with conditional 304s, Range support (via Starlette's FileResponse), and
precompressed .gz/.br sidecar negotiation (see precompress.py).
One deliberate rule: files whose own name ends in .gz (the
.atf.json.gz sidecars, the collection geo sidecars) are opaque
application/gzip bytes with NO Content-Encoding header. The
frontend fetches them raw and decompresses via DecompressionStream;
transparent decompression by the browser would break that contract.
normalize_request_path
normalize_request_path(raw_path: str) -> str | None
Collapse a request path to /segment/... form; None rejects traversal.
Source code in src/mamut_routing_publish/server.py
| def normalize_request_path(raw_path: str) -> str | None:
"""Collapse a request path to /segment/... form; None rejects traversal."""
candidate = raw_path.replace("\\", "/")
keep_trailing_slash = candidate.endswith("/")
segments: list[str] = []
for segment in candidate.split("/"):
if not segment or segment == ".":
continue
if segment == ".." or "\x00" in segment:
return None
segments.append(segment)
if not segments:
return "/"
return "/" + "/".join(segments) + ("/" if keep_trailing_slash else "")
|
resolve_public_file
resolve_public_file(
repo_root: Path,
request_path: str,
site_root: Path | None = None,
) -> Path | None
Port of the Julia server's dual-root resolution.
The dist tree is tried first (with the extensionless -> index.html
and trailing-slash -> index.html conventions the shells rely on), then
the whitelisted repo artifact roots for repo-relative payload links.
Source code in src/mamut_routing_publish/server.py
| def resolve_public_file(repo_root: Path, request_path: str, site_root: Path | None = None) -> Path | None:
"""Port of the Julia server's dual-root resolution.
The ``dist`` tree is tried first (with the extensionless -> index.html
and trailing-slash -> index.html conventions the shells rely on), then
the whitelisted repo artifact roots for repo-relative payload links.
"""
relative_candidates: list[str] = []
if request_path == "/":
relative_candidates.append("index.html")
elif request_path.endswith("/"):
relative_candidates.append(f"{request_path[1:-1]}/index.html")
else:
relative = request_path[1:]
relative_candidates.append(relative)
if "." not in relative.rsplit("/", 1)[-1]:
relative_candidates.append(f"{relative}/index.html")
site_root = repo_root / "dist" if site_root is None else site_root
for relative_candidate in relative_candidates:
site_candidate = site_root / relative_candidate
if site_candidate.is_file() and _contained(site_candidate, site_root):
return site_candidate
first_segment = relative_candidate.split("/", 1)[0]
if first_segment not in REPO_ARTIFACT_ROOT_ENTRIES:
continue
repo_candidate = repo_root / relative_candidate
if repo_candidate.is_file() and _contained(repo_candidate, repo_root / first_segment):
return repo_candidate
return None
|
negotiate_variant
negotiate_variant(
path: Path, accept_encoding: str
) -> tuple[Path, str | None]
Pick a precompressed sidecar when the client accepts its encoding.
Files that are themselves .gz/.br content are never negotiated:
they are opaque bytes by contract.
Source code in src/mamut_routing_publish/server.py
| def negotiate_variant(path: Path, accept_encoding: str) -> tuple[Path, str | None]:
"""Pick a precompressed sidecar when the client accepts its encoding.
Files that are themselves ``.gz``/``.br`` content are never negotiated:
they are opaque bytes by contract.
"""
if path.name.endswith((".gz", ".br")):
return path, None
accepted = accepted_encodings(accept_encoding)
for encoding, suffix in (("br", ".br"), ("gzip", ".gz")):
if encoding in accepted:
variant = path.with_name(path.name + suffix)
if variant.is_file():
return variant, encoding
return path, None
|
create_app
create_app(
repo_root: str | Path,
site_dir: str | Path | None = None,
) -> Starlette
The static app: site_dir (default <repo_root>/dist) plus the repo artifact roots.
site_dir lets a staging build (site build --site-output-dir) be
previewed without touching the live dist tree; repo-relative artifact
links (benchmarks/, LICENSE, dist/ caches) still resolve
against repo_root.
Source code in src/mamut_routing_publish/server.py
| def create_app(repo_root: str | Path, site_dir: str | Path | None = None) -> Starlette:
"""The static app: ``site_dir`` (default ``<repo_root>/dist``) plus the repo artifact roots.
``site_dir`` lets a staging build (``site build --site-output-dir``) be
previewed without touching the live ``dist`` tree; repo-relative artifact
links (``benchmarks/``, ``LICENSE``, ``dist/`` caches) still resolve
against ``repo_root``.
"""
root = Path(repo_root).resolve()
site_root = (root / "dist") if site_dir is None else Path(site_dir).resolve()
if not site_root.is_dir():
raise FileNotFoundError(f"No site tree at {site_root}. Run `site build` first.")
app = Starlette(
routes=[
Route("/healthz", healthz, methods=["GET", "HEAD"]),
Route("/api/healthz", healthz, methods=["GET", "HEAD"]),
Route("/{path:path}", serve_site_file, methods=["GET", "HEAD"]),
]
)
app.state.repo_root = root
app.state.site_root = site_root
return app
|