HR-ATS-Portal/devserver.py

51 lines
1.9 KiB
Python

#!/usr/bin/env python3
"""Static dev server for the ATS dashboard.
Identical to `python3 -m http.server` except it disables caching. The stdlib
server answers conditional requests from Last-Modified, which has one-second
granularity — so a file edited twice within the same second keeps serving the
stale copy and the browser never sees the change.
"""
import os
import sys
from functools import partial
from http.server import SimpleHTTPRequestHandler, ThreadingHTTPServer
# Prefixes served by a client-side router rather than by files on disk.
SPA_ROOTS = ("/auth/",)
class NoCacheHandler(SimpleHTTPRequestHandler):
def send_head(self):
# Deep links like /auth/confirm-email?token=… are router paths, not files.
# Hand back the SPA shell and let react-router resolve them; its assets are
# referenced absolutely (/auth/assets/…), so nothing needs rewriting.
for root in SPA_ROOTS:
if self.path.startswith(root) and not os.path.exists(self.translate_path(self.path)):
self.path = root + "index.html"
break
return super().send_head()
def end_headers(self):
self.send_header("Cache-Control", "no-store, no-cache, must-revalidate, max-age=0")
self.send_header("Pragma", "no-cache")
self.send_header("Expires", "0")
super().end_headers()
def send_header(self, keyword, value):
# Drop the validator entirely so conditional GETs can't 304.
if keyword.lower() == "last-modified":
return
super().send_header(keyword, value)
def log_message(self, fmt, *args):
pass
if __name__ == "__main__":
port = int(sys.argv[1]) if len(sys.argv) > 1 else 4173
directory = sys.argv[2] if len(sys.argv) > 2 else "."
handler = partial(NoCacheHandler, directory=directory)
print(f"Serving {directory} on http://localhost:{port} (no-cache)")
ThreadingHTTPServer(("127.0.0.1", port), handler).serve_forever()