fix(discord-bridge): dashboard-ul ramanea gol la /claude — lipsea <base href>

Simptom: pagina se incarca prin tailscale, dar niciun API nu era cerut; in
dashboard.log se vedea doar GET / si nimic altceva.

Cauza: --set-path taie prefixul, deci /claude si /claude/ ajung la server
identic, ca "/". Fara slash final, URL-urile relative se rezolvau la radacina
hostului (https://host/api/status), unde proxy-ul nu trimite nimic incoace.
Cererile nici nu ajungeau la noi, iar pagina ramanea goala fara nicio eroare.
Redirectul 301 adaugat anterior nu putea ajuta: serverul nu vede forma
originala a adresei.

Paginile se servesc acum printr-un handler propriu care pune <base href> din
DASHBOARD_PREFIX, plus Cache-Control: no-store, fiindca HTML-ul poarta de acum
configuratie si o copie veche ar trimite cererile aiurea.

Patru teste noi. Verificat in browser pe cazul reprodus (pagina servita pe
radacina, ca prin proxy): toate cererile pleaca cu /claude/ si datele se incarca.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01B29CApsP1JkSdjYaGaHpE7
This commit is contained in:
Claude Agent
2026-08-30 14:11:24 +00:00
parent 6b6f6644f9
commit e0ea85005d
2 changed files with 61 additions and 1 deletions

View File

@@ -426,9 +426,43 @@ class Handler(SimpleHTTPRequestHandler):
self.send_header("Content-Length", "0") self.send_header("Content-Length", "0")
self.end_headers() self.end_headers()
return return
self.path = "/index.html" if path == "/" else path if path in ("/", "/index.html"):
return self.send_html("index.html")
if path == "/login.html":
return self.send_html("login.html")
self.path = path
return super().do_GET() return super().do_GET()
def send_html(self, name: str):
"""Trimite o pagina, cu `<base href>` pus la servire.
De ce e nevoie: `tailscale serve --set-path /claude` TAIE prefixul, deci
serverul nu poate sti daca browserul e la `/claude` sau la `/claude/` —
ambele ajung aici ca `/`. Fara slash final, un URL relativ (`api/status`)
se rezolva la radacina hostului, unde proxy-ul nu mai trimite nimic
incoace: pagina se incarca si ramane goala, fara nicio eroare vizibila.
`<base href="/claude/">` fixeaza rezolvarea indiferent de forma adresei.
"""
try:
body = (_DASH / name).read_text(encoding="utf-8")
except OSError:
return self.send_error(404)
pfx = mount_prefix()
if pfx:
body = body.replace("<head>", f'<head>\n<base href="{pfx}/">', 1)
data = body.encode("utf-8")
self.send_response(200)
self.send_header("Content-Type", "text/html; charset=utf-8")
self.send_header("Content-Length", str(len(data)))
# no-store: paginile poarta acum si configuratia (base href), deci o
# copie veche din cache ar trimite cererile in alta parte.
self.send_header("Cache-Control", "no-store")
self.end_headers()
try:
self.wfile.write(data)
except (BrokenPipeError, ConnectionResetError):
pass
def route_get(self, path: str): def route_get(self, path: str):
qs = parse_qs(urlparse(self.path).query) qs = parse_qs(urlparse(self.path).query)
if path == "/api/status": if path == "/api/status":

View File

@@ -381,3 +381,29 @@ def test_static_servit_si_sub_prefix(server_cu_prefix):
server_cu_prefix.login() server_cu_prefix.login()
status, data, _ = server_cu_prefix.call("/claude/static/app.css") status, data, _ = server_cu_prefix.call("/claude/static/app.css")
assert status == 200 and ".card" in data["_html"] assert status == 200 and ".card" in data["_html"]
def test_base_href_pus_cand_exista_prefix(server_cu_prefix):
"""Proxy-ul taie prefixul, deci serverul nu poate sti daca browserul e la
`/claude` sau `/claude/`. `<base href>` face rezolvarea determinista."""
server_cu_prefix.login()
_, data, _ = server_cu_prefix.call("/")
assert '<base href="/claude/">' in data["_html"]
def test_base_href_si_pe_pagina_de_login(server_cu_prefix):
_, data, _ = server_cu_prefix.call("/login.html")
assert '<base href="/claude/">' in data["_html"]
def test_fara_prefix_nu_se_pune_base(server):
server.login()
_, data, _ = server.call("/")
assert "<base" not in data["_html"]
def test_paginile_nu_se_pun_in_cache(server_cu_prefix):
"""O copie veche ar purta un `base href` gresit si ar trimite cererile aiurea."""
server_cu_prefix.login()
_, _, resp = server_cu_prefix.call("/")
assert resp.headers.get("Cache-Control") == "no-store"