"""Same-origin static UI/gateway for the isolated room demo; never proxies arbitrary URLs.""" import argparse import json import hint_library import re from functools import partial from http.server import SimpleHTTPRequestHandler, ThreadingHTTPServer from pathlib import Path from urllib.parse import urlsplit import urllib.request import urllib.error ROOT = Path(__file__).resolve().parent ROUTES = {"/room/state": (18776, "/room/state"), "/room/trace": (18776, "/room/trace"), "/room/command": (18776, "/room/command"), "/speech/health": (18778, "/health")} class Handler(SimpleHTTPRequestHandler): def list_directory(self, path): self.send_error(403) def relay(self): path = urlsplit(self.path).path route = ROUTES.get(path) if re.fullmatch(r"/speech/audio/[a-f0-9]{64}\.wav", path): route = (18778, path.removeprefix("/speech")) if not route or (self.command == "POST" and path != "/room/command") or (self.command == "GET" and path == "/room/command"): self.send_error(404) return if self.command == "POST": origin = self.headers.get("Origin") if origin and origin != "http://" + self.headers.get("Host", ""): self.send_error(403, "Use the room demo page to send commands") return try: size = int(self.headers.get("Content-Length", "0")) if size < 0 or size > 65536: self.send_error(413) return body = self.rfile.read(size) if self.command == "POST" else None request = urllib.request.Request(f"http://127.0.0.1:{route[0]}{route[1]}", data=body, method=self.command, headers={"Content-Type":"application/json", **({"Range":self.headers["Range"]} if "Range" in self.headers else {})}) try: with urllib.request.urlopen(request, timeout=8) as response: data, status = response.read(), response.status content_type = response.headers.get("Content-Type","application/json") content_range = response.headers.get("Content-Range") except urllib.error.HTTPError as error: data, status = error.read(), error.code content_type, content_range = "text/plain", None self.send_response(status) self.send_header("Content-Type",content_type) self.send_header("Accept-Ranges","bytes") if content_range: self.send_header("Content-Range",content_range) self.send_header("Content-Length",str(len(data))) self.send_header("Cache-Control","no-store") self.end_headers() self.wfile.write(data) except (OSError, ValueError): self.send_error(503, "Local lab service unavailable") def hints(self): try: if self.command == "POST": origin=self.headers.get("Origin") if origin and origin != "http://" + self.headers.get("Host",""): self.send_error(403) return size=int(self.headers.get("Content-Length","0")) if not 0