error-pages/templates/connection.html
2024-07-03 18:12:13 +04:00

462 lines
14 KiB
HTML

<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta name="robots" content="nofollow,noarchive,noindex">
<title>{{ code }} | {{ message }}</title>
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<!-- {{ if or (eq code 408) (eq code 425) (eq code 429) (eq code 500) (eq code 502) (eq code 503) (eq code 504) }} -->
<meta http-equiv="refresh" content="30">
<!-- {{ end }} -->
<meta name="title" content="{{ code }}: {{ message | escape }}">
<meta name="description" content="{{ description | escape }}">
<meta property="og:title" content="{{ code }}: {{ message | escape }}">
<meta property="og:description" content="{{ description | escape }}">
<meta property="twitter:title" content="{{ code }}: {{ message | escape }}">
<meta property="twitter:description" content="{{ description | escape }}">
<style>
:root {
--color-bg-primary: #fff;
--color-text-primary: #000;
--color-text-secondary: #575958;
--ui-card-color-bg: #f2f2f2;
--color-text-ok: #137333;
--color-bg-ok: #e6f4ea;
--color-text-error: #c5221f;
--color-bg-error: #fce8e6;
--color-text-warning: #b05a00;
--color-bg-warning: #fef7e0;
--icon-size: 48px;
}
@media (prefers-color-scheme: dark) {
:root {
--color-bg-primary: #111;
--color-text-primary: rgba(255, 255, 255, 0.86);
--color-text-secondary: rgba(255, 255, 255, 0.4);
--ui-card-color-bg: rgba(40, 40, 40, 0.73);
--color-bg-ok: #07220f;
--color-bg-error: #270501;
--color-bg-warning: #392605;
}
}
/** Idea author: https://github.com/186526/CloudflareCustomErrorPage */
html, body {
margin: 0;
padding: 0;
min-height: 100%;
color: var(--color-text-primary);
background-color: var(--color-bg-primary);
font-family: sans-serif;
font-size: 16px;
}
@media screen and (min-width: 2000px) {
html, body {
font-size: 20px;
}
}
body {
margin: 2em 2em;
}
header {
margin-left: 1em;
}
header .error-code {
font-size: 3.2em;
font-family: monospace;
font-weight: 400;
margin: 0 0 0 10px;
}
header .error-description {
font-family: sans-serif;
font-size: 1.4em;
color: var(--color-text-secondary);
margin: 0 0 0 10px;
}
code {
font-family: monospace;
}
.status {
margin-top: 2.5em;
display: flex;
flex-direction: row;
flex-wrap: wrap;
justify-content: center;
align-items: center;
}
.card {
background-color: var(--ui-card-color-bg);
padding: 2em;
margin: 1em 1em;
min-height: 3em;
border-radius: 9px;
flex-grow: 1;
}
.arrows svg {
fill: var(--color-text-secondary);
}
.icon svg {
width: var(--icon-size);
height: auto;
fill: var(--color-text-primary);
}
.card.ok {
background-color: var(--color-bg-ok);
}
.card.ok .status-text {
color: var(--color-text-ok);
}
.card.ok svg {
fill: var(--color-text-ok);
}
.card.error {
background-color: var(--color-bg-error);
}
.card.error .status-text {
color: var(--color-text-error);
}
.card.error svg {
fill: var(--color-text-error);
}
.card.warning {
background-color: var(--color-bg-warning);
}
.card.warning .status-text {
color: var(--color-text-warning);
}
.card.warning svg {
fill: var(--color-text-warning);
}
.card .caption {
font-size: 1.37em;
}
.card .status-text, .reason p {
margin: 0;
font-family: sans-serif;
}
.reason p {
line-height: 125%;
}
a {
text-decoration: none;
color: #1967d2;
}
.reason {
display: flex;
flex-direction: row;
flex-wrap: wrap;
justify-content: space-between;
align-items: baseline;
}
.reason > * {
display: block;
margin: 1em;
flex-grow: 1;
max-width: 40%;
}
.reason h2 {
font-size: 1.45em;
margin: 0 0 .6em 0;
font-weight: normal;
}
footer {
margin: 1em;
color: var(--color-text-secondary);
}
/* {{ if show_details }} */
footer .details {
margin-top: 20px;
}
footer .details ul {
padding: 0;
font-size: 0.7em;
list-style: none;
}
footer .details code {
padding-left: 0.3em;
}
/* {{ end }} */
@media screen and (max-width: 820px) {
.arrows {
display: none;
}
}
@media screen and (max-width: 480px) {
.reason > * {
max-width: 100%;
}
}
@media screen and (min-width: 768px) {
body {
margin: 8% 10%;
}
header > * {
display: inline-block;
margin-left: 1%;
}
}
</style>
</head>
<body>
<header>
<h1 class="error-code">{{ code }}</h1>
<p class="error-description">{{ message }}</p>
</header>
<div class="status">
<div class="card warning" id="client-status-card">
<i class="icon">
<svg xmlns="http://www.w3.org/2000/svg" height="24px" viewBox="0 0 24 24" width="24px" fill="#000000">
<path d="M0 0h24v24H0V0z" fill="none"/>
<path d="M19 4H5c-1.11 0-2 .9-2 2v12c0 1.1.89 2 2 2h14c1.1 0 2-.9 2-2V6c0-1.1-.89-2-2-2zm0 14H5V8h14v10z"/>
</svg>
</i>
<div class="caption" data-l10n>Your Client</div>
<p class="status-text" data-l10n>Unknown</p>
</div>
<div class="arrows">
<svg xmlns="http://www.w3.org/2000/svg" height="24px" width="24px" fill="#000000">
<defs>
<symbol id="arrows-horizontal" viewBox="0 0 24 24">
<rect fill="none" height="24" width="24" x="0"/>
<polygon points="7.41,13.41 6,12 2,16 6,20 7.41,18.59 5.83,17 21,17 21,15 5.83,15"/>
<polygon points="16.59,10.59 18,12 22,8 18,4 16.59,5.41 18.17,7 3,7 3,9 18.17,9"/>
</symbol>
</defs>
<use href="#arrows-horizontal"/>
</svg>
</div>
<div class="card ok" id="network-status-card">
<i class="icon">
<svg xmlns="http://www.w3.org/2000/svg" height="24px" viewBox="0 0 24 24" width="24px" fill="#000000">
<path d="M0 0h24v24H0V0z" fill="none"/>
<path d="M12 6c2.62 0 4.88 1.86 5.39 4.43l.3 1.5 1.53.11c1.56.1 2.78 1.41 2.78 2.96 0 1.65-1.35 3-3 3H6c-2.21
0-4-1.79-4-4 0-2.05 1.53-3.76 3.56-3.97l1.07-.11.5-.95C8.08 7.14 9.94 6 12 6m0-2C9.11 4 6.6 5.64 5.35
8.04 2.34 8.36 0 10.91 0 14c0 3.31 2.69 6 6 6h13c2.76 0 5-2.24 5-5 0-2.64-2.05-4.78-4.65-4.96C18.67
6.59 15.64 4 12 4z"/>
</svg>
</i>
<div class="caption" data-l10n>Network</div>
<p class="status-text" data-l10n>Working</p>
</div>
<div class="arrows">
<svg xmlns="http://www.w3.org/2000/svg" height="24px" width="24px" fill="#000000">
<use href="#arrows-horizontal"/>
</svg>
</div>
<div class="card warning" id="server-status-card">
<i class="icon">
<svg xmlns="http://www.w3.org/2000/svg" height="24px" viewBox="0 0 24 24" width="24px" fill="#000000">
<path d="M0 0h24v24H0V0z" fill="none"/>
<path d="M19 15v4H5v-4h14m1-2H4c-.55 0-1 .45-1 1v6c0 .55.45 1 1 1h16c.55 0 1-.45 1-1v-6c0-.55-.45-1-1-1zM7
18.5c-.82 0-1.5-.67-1.5-1.5s.68-1.5 1.5-1.5 1.5.67 1.5 1.5-.67 1.5-1.5 1.5zM19 5v4H5V5h14m1-2H4c-.55 0-1
.45-1 1v6c0 .55.45 1 1 1h16c.55 0 1-.45 1-1V4c0-.55-.45-1-1-1zM7 8.5c-.82 0-1.5-.67-1.5-1.5S6.18 5.5 7
5.5s1.5.68 1.5 1.5S7.83 8.5 7 8.5z"/>
</svg>
</i>
<div class="caption" data-l10n>Web Server</div>
<p class="status-text" data-l10n>Unknown</p>
</div>
</div>
<div class="reason">
<div class="what-happened">
<h2 data-l10n>What happened?</h2>
<p class="description" data-l10n>{{ description }}</p>
</div>
<div class="what-can-i-do">
<h2 data-l10n>What can I do?</h2>
<p class="description" data-l10n>Please try again in a few minutes</p>
</div>
</div>
<footer>
<!-- {{- if show_details -}} -->
<div class="details">
<ul>
<!-- {{- if host -}} -->
<li><span data-l10n>Host</span>: <code>{{ host }}</code></li>
<!-- {{- end }}{{ if original_uri -}} -->
<li><span data-l10n>Original URI</span>: <code>{{ original_uri }}</code></li>
<!-- {{- end }}{{ if forwarded_for -}} -->
<li><span data-l10n>Forwarded for</span>: <code>{{ forwarded_for }}</code></li>
<!-- {{- end }}{{ if namespace -}} -->
<li><span data-l10n>Namespace</span>: <code>{{ namespace }}</code></li>
<!-- {{- end }}{{ if ingress_name -}} -->
<li><span data-l10n>Ingress name</span>: <code>{{ ingress_name }}</code></li>
<!-- {{- end }}{{ if service_name -}} -->
<li><span data-l10n>Service name</span>: <code>{{ service_name }}</code></li>
<!-- {{- end }}{{ if service_port -}} -->
<li><span data-l10n>Service port</span>: <code>{{ service_port }}</code></li>
<!-- {{- end }}{{ if request_id -}} -->
<li><span data-l10n>Request ID</span>: <code>{{ request_id }}</code></li>
<!-- {{- end -}} -->
<li><span data-l10n>Timestamp</span>: <code>{{ nowUnix }}</code></li>
</ul>
</div>
<!-- {{- end -}} -->
</footer>
<script>
const errorCode = parseInt(`{{ code }}`, 10);
if (errorCode && !isNaN(errorCode)) {
/**
* @param {HTMLElement} $card
* @param { {isOk?: boolean, isWarning?: boolean, isError?: boolean} } state
* @param {string} statusText
*/
const setCardState = ($card, state, statusText) => {
const [okClass, warnClass, errClass] = ['ok', 'warning', 'error'];
const $statusText = $card.querySelectorAll('.status-text');
switch (true) {
case state.isOk === true:
$card.classList.remove(errClass, warnClass);
$card.classList.add(okClass);
$statusText.forEach(($statusText) => $statusText.innerText = statusText);
break;
case state.isWarning === true:
$card.classList.remove(okClass, errClass);
$card.classList.add(warnClass);
$statusText.forEach(($statusText) => $statusText.innerText = statusText);
break;
case state.isError === true:
$card.classList.remove(okClass, warnClass);
$card.classList.add(errClass);
$statusText.forEach(($statusText) => $statusText.innerText = statusText);
break;
}
};
/** @param { {whatHappened?: string, whatToDo?: string} } reasons */
const setReasons = (reasons) => {
const descSelector = '.description';
[...document.getElementsByClassName('what-happened')].forEach(($el) => {
if (typeof reasons.whatHappened === 'string' && reasons.whatHappened.length > 0) {
[...$el.querySelectorAll(descSelector)].forEach(($desc) => $desc.innerText = reasons.whatHappened);
} else {
$el.remove();
}
});
[...document.getElementsByClassName('what-can-i-do')].forEach(($el) => {
if (typeof reasons.whatToDo === 'string' && reasons.whatToDo.length > 0) {
[...$el.querySelectorAll(descSelector)].forEach(($desc) => $desc.innerText = reasons.whatToDo);
} else {
$el.remove();
}
});
};
/**
* @param {string} text
*/
const setErrorDescription = function (text) {
[...document.getElementsByClassName('error-description')].forEach(($el) => $el.innerHTML = text);
};
const message = `{{ message }}`.trim();
const cards = {
$client: document.getElementById('client-status-card'),
$network: document.getElementById('network-status-card'),
$server: document.getElementById('server-status-card'),
};
let whatToDo = 'Please try again in a few minutes';
switch (true) {
case errorCode >= 400 && errorCode <= 499:
switch (errorCode) {
case 400:
case 405:
case 411:
case 413:
whatToDo = 'Please try to change the request method, headers, payload, or URL';
break;
case 401:
case 403:
case 407:
whatToDo = 'Please check your authorization data';
break;
case 404:
whatToDo = 'Please double-check the URL and try again';
break;
case 409:
case 410:
case 418:
whatToDo = '¯\\_(ツ)_/¯';
break;
}
setErrorDescription(`<span data-l10n>${message}</span> (<span data-l10n>client-side error</span>)`);
setCardState(cards.$client, {isError: true}, message)
setCardState(cards.$network, {isOk: true}, 'Working')
setCardState(cards.$server, {isOk: true}, 'Working')
break;
case errorCode >= 500 && errorCode <= 599:
setErrorDescription(`<span data-l10n>${message}</span> (<span data-l10n>server-side error</span>)`);
setCardState(cards.$client, {isOk: true}, 'Working')
setCardState(cards.$network, {isOk: true}, 'Working')
setCardState(cards.$server, {isError: true}, message)
break;
default:
setErrorDescription(message);
setCardState(cards.$client, {isWarning: true}, 'Unknown')
setCardState(cards.$network, {isOk: true}, 'Working')
setCardState(cards.$server, {isWarning: true}, 'Unknown')
break;
}
setReasons({whatHappened: `{{ description }}`.trim(), whatToDo: whatToDo.trim()});
} else {
console.warn('Cannot parse the error code:', errorCode);
}
</script>
<!-- {{- if l10n_enabled -}} -->
<script>// {{ l10nScript }}</script>
<!-- {{- end -}} -->
</body>
</html>