fix(theseus/bns): failed content fetches get a real error page naming the upstream and cause
A bns:// fetch that fails after the name resolved (relay unreachable, DNS stalling, the site's own server down) used to answer with the bare text "Theseus error: fetch failed", which reads as a broken browser. The handler now returns a styled page that names the host, the upstream it tried (navigate.st, the p-record origin or the ip record), the error and its cause code, explains the likely reason per cause (unreachable vs DNS), and offers a retry.
This commit is contained in:
parent
1596463b70
commit
d7d127d7b4
1 changed files with 29 additions and 1 deletions
30
main.js
30
main.js
|
|
@ -1412,7 +1412,35 @@ async function serveBns(request) {
|
|||
if (!isSubdomain && r.p) return await serveP();
|
||||
if (r.u) return Response.redirect(r.u, 302);
|
||||
return new Response(JSON.stringify(rec.entry, null, 2), { headers: { "content-type": "application/json" } });
|
||||
} catch (e) { return new Response("Theseus error: " + e.message, { status: 502 }); }
|
||||
} catch (e) {
|
||||
// The upstream fetch failed — relay unreachable, DNS stalling, site's
|
||||
// own server down. A bare "fetch failed" reads as "Theseus is broken";
|
||||
// name the upstream and the cause code so it reads as what it is,
|
||||
// and give a retry.
|
||||
const cause = e?.cause?.code || e?.cause?.message || "";
|
||||
const upstream = r.s3 ? new URL(GATEWAY).host : r.p ? (() => { try { return new URL(r.p).host; } catch { return r.p; } })() : r.ip ? String(r.ip) : "";
|
||||
return new Response(bnsErrorHtml({ host, message: e?.message || String(e), cause, upstream }),
|
||||
{ status: 502, headers: { "content-type": "text/html; charset=utf-8" } });
|
||||
}
|
||||
}
|
||||
// Error surface for a bns:// fetch that failed after the name resolved.
|
||||
// Self-contained HTML (this is a protocol handler response, not a tab
|
||||
// navigation, so error.html's loadFile path doesn't apply).
|
||||
function bnsErrorHtml({ host, message, cause, upstream }) {
|
||||
const esc = (s) => String(s || "").replace(/&/g, "&").replace(/</g, "<").replace(/>/g, ">").replace(/"/g, """);
|
||||
const hint = /ETIMEDOUT|ECONNREFUSED|ECONNRESET|EHOSTUNREACH|ENETUNREACH/.test(cause)
|
||||
? `Theseus resolved <b>${esc(host)}</b> but could not reach <b>${esc(upstream || "its server")}</b> from this network. Check your connection or VPN and try again.`
|
||||
: /ENOTFOUND|EAI_AGAIN/.test(cause)
|
||||
? `Your system DNS could not look up <b>${esc(upstream || "the server")}</b>. A stale or unreachable DNS server on one of your network adapters is the usual cause.`
|
||||
: `Theseus resolved <b>${esc(host)}</b> but the content fetch from <b>${esc(upstream || "its server")}</b> failed.`;
|
||||
return `<!doctype html><html><head><meta charset="utf-8"><title>Can’t reach ${esc(host)}</title>
|
||||
<style>:root{color-scheme:dark}body{margin:0;background:#0f1420;color:#e8ecf3;font:15px/1.5 system-ui,sans-serif;display:grid;place-items:center;min-height:100vh}
|
||||
.card{max-width:560px;padding:32px 36px;background:#1b2330;border:1px solid #ffffff1f;border-radius:14px}h1{font-size:20px;margin:0 0 10px}p{margin:8px 0;color:#b9c2d0}
|
||||
code{font:12.5px ui-monospace,monospace;color:#D6FF3D;background:#0f1420;padding:2px 6px;border-radius:5px}
|
||||
a.btn{display:inline-block;margin-top:16px;padding:9px 16px;border-radius:999px;background:#D6FF3D;color:#0f1420;font-weight:600;text-decoration:none}</style></head>
|
||||
<body><div class="card"><h1>Can’t reach ${esc(host)}</h1><p>${hint}</p>
|
||||
<p><code>${esc(message)}${cause ? " · " + esc(cause) : ""}</code></p>
|
||||
<a class="btn" href="javascript:location.reload()">Try again</a></div></body></html>`;
|
||||
}
|
||||
|
||||
// ---- window + tabs ----
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue