mirror of
https://github.com/nesquena/hermes-webui.git
synced 2026-05-25 03:00:23 +00:00
fix: keep shell route errors html
This commit is contained in:
committed by
nesquena-hermes
parent
740e5412a5
commit
78c09e1fd9
+41
-10
@@ -2509,6 +2509,34 @@ def _handle_plugins(handler, parsed) -> bool:
|
||||
)
|
||||
|
||||
|
||||
_SHELL_ERROR_HTML = """<!doctype html>
|
||||
<html lang=\"en\">
|
||||
<head>
|
||||
<meta charset=\"utf-8\">
|
||||
<meta name=\"viewport\" content=\"width=device-width, initial-scale=1\">
|
||||
<title>Hermes is restarting</title>
|
||||
</head>
|
||||
<body style=\"margin:0;padding:2rem;font-family:-apple-system,BlinkMacSystemFont,'Segoe UI',sans-serif;background:#111827;color:#e5e7eb;\">
|
||||
<main style=\"max-width:40rem;margin:10vh auto;line-height:1.5;\">
|
||||
<h1 style=\"font-size:1.5rem;margin:0 0 0.75rem;\">Hermes is restarting…</h1>
|
||||
<p style=\"margin:0;color:#cbd5e1;\">The WebUI shell could not load cleanly. Refresh in a moment if this page does not update automatically.</p>
|
||||
</main>
|
||||
</body>
|
||||
</html>"""
|
||||
|
||||
|
||||
def _serve_shell_unavailable(handler, exc: Exception) -> bool:
|
||||
"""Return HTML for shell-route failures so `/` never renders JSON."""
|
||||
logger.warning("Failed to serve WebUI shell route: %s", exc)
|
||||
t(
|
||||
handler,
|
||||
_SHELL_ERROR_HTML,
|
||||
status=503,
|
||||
content_type="text/html; charset=utf-8",
|
||||
)
|
||||
return True
|
||||
|
||||
|
||||
def handle_get(handler, parsed) -> bool:
|
||||
"""Handle all GET routes. Returns True if handled, False for 404."""
|
||||
|
||||
@@ -2520,17 +2548,20 @@ def handle_get(handler, parsed) -> bool:
|
||||
return _serve_static(handler, stripped)
|
||||
|
||||
if parsed.path in ("/", "/index.html") or parsed.path.startswith("/session/"):
|
||||
from urllib.parse import quote
|
||||
from api.updates import WEBUI_VERSION
|
||||
version_token = quote(WEBUI_VERSION, safe="")
|
||||
from api.extensions import inject_extension_tags
|
||||
try:
|
||||
from urllib.parse import quote
|
||||
from api.updates import WEBUI_VERSION
|
||||
version_token = quote(WEBUI_VERSION, safe="")
|
||||
from api.extensions import inject_extension_tags
|
||||
|
||||
html = _INDEX_HTML_PATH.read_text(encoding="utf-8").replace("__WEBUI_VERSION__", version_token)
|
||||
return t(
|
||||
handler,
|
||||
inject_extension_tags(html),
|
||||
content_type="text/html; charset=utf-8",
|
||||
)
|
||||
html = _INDEX_HTML_PATH.read_text(encoding="utf-8").replace("__WEBUI_VERSION__", version_token)
|
||||
return t(
|
||||
handler,
|
||||
inject_extension_tags(html),
|
||||
content_type="text/html; charset=utf-8",
|
||||
)
|
||||
except Exception as exc:
|
||||
return _serve_shell_unavailable(handler, exc)
|
||||
|
||||
if parsed.path == "/login":
|
||||
_settings = load_settings()
|
||||
|
||||
Binary file not shown.
|
After Width: | Height: | Size: 136 KiB |
@@ -0,0 +1,58 @@
|
||||
"""Regression coverage for the shell/home route fallback.
|
||||
|
||||
The WebUI shell should never render a JSON error page for `/`, even if
|
||||
index.html serving fails during a restart/update race. API routes still keep
|
||||
their normal JSON error behavior; this only pins the shell route contract.
|
||||
"""
|
||||
|
||||
from urllib.parse import urlparse
|
||||
|
||||
|
||||
class _FakeHandler:
|
||||
def __init__(self):
|
||||
self.status = None
|
||||
self.sent_headers = []
|
||||
self.body = bytearray()
|
||||
self.wfile = self
|
||||
self.headers = {}
|
||||
|
||||
def send_response(self, status):
|
||||
self.status = status
|
||||
|
||||
def send_header(self, name, value):
|
||||
self.sent_headers.append((name, value))
|
||||
|
||||
def end_headers(self):
|
||||
pass
|
||||
|
||||
def write(self, data):
|
||||
self.body.extend(data)
|
||||
|
||||
def header(self, name):
|
||||
for key, value in self.sent_headers:
|
||||
if key.lower() == name.lower():
|
||||
return value
|
||||
return None
|
||||
|
||||
|
||||
class _BrokenIndexPath:
|
||||
def read_text(self, *args, **kwargs):
|
||||
raise RuntimeError("simulated index.html read failure")
|
||||
|
||||
|
||||
def test_home_route_internal_error_returns_html_503_not_json(monkeypatch):
|
||||
from api import routes
|
||||
|
||||
monkeypatch.setattr(routes, "_INDEX_HTML_PATH", _BrokenIndexPath())
|
||||
|
||||
handler = _FakeHandler()
|
||||
assert routes.handle_get(handler, urlparse("http://example.com/")) is True
|
||||
|
||||
assert handler.status == 503
|
||||
assert (handler.header("Content-Type") or "").startswith("text/html; charset=utf-8")
|
||||
assert handler.header("Cache-Control") == "no-store"
|
||||
|
||||
body = bytes(handler.body).decode("utf-8")
|
||||
assert "Hermes is restarting" in body
|
||||
assert "application/json" not in (handler.header("Content-Type") or "")
|
||||
assert '"error"' not in body
|
||||
Reference in New Issue
Block a user