Web: replace unreliable post-OTA device poll with a countdown timer
After a successful OTA upload the web panel polled the device by fetching "/" and waiting for a 200 OK response. This approach is fundamentally broken when the new firmware contains a freshly generated self-signed certificate (e.g. from a clean CI build): - The browser rejects the TLS handshake with a certificate error (MOZILLA_PKIX_ERROR_SELF_SIGNED_CERT in Firefox; other browsers report different error names but behave identically). The fetch() call throws a generic TypeError — the same type thrown for any other network failure such as a refused or timed-out connection. Browsers intentionally provide no way to distinguish a cert rejection from a plain connectivity failure, so the catch block cannot tell whether the device is up-but-cert-changed or simply not yet online. - Switching to an explicit http:// URL to sidestep TLS is not an option: the web panel is served over HTTPS, and browsers block active mixed content (fetch/XHR to HTTP) unconditionally from an HTTPS origin. Because no network-based probe can reliably detect device readiness under these constraints without changing how the certificate is generated, replace the polling loop with a simple 10-second countdown timer that unconditionally redirects to the login page. The device is typically back online within ~7 seconds, so the 10-second wait provides a reasonable safety margin.
Esse commit está contido em:
@@ -2641,22 +2641,14 @@ const char kWebPanelAppHtml[] PROGMEM = R"HTML(
|
|||||||
}
|
}
|
||||||
if (xhr.status === 200) {
|
if (xhr.status === 200) {
|
||||||
barEl.style.width = "100%";
|
barEl.style.width = "100%";
|
||||||
msgEl.textContent = "Done. Device is rebooting";
|
let secs = 10;
|
||||||
let wait = 4;
|
const iv = setInterval(() => {
|
||||||
const iv = setInterval(async () => {
|
if (--secs <= 0) {
|
||||||
msgEl.textContent += '.';
|
clearInterval(iv);
|
||||||
if (msgEl.textContent.length > 85) { clearInterval(iv); msgEl.textContent = "Device did not come back online. =("; return; }
|
redirectToLogin();
|
||||||
if (--wait) { return; }
|
return;
|
||||||
wait = 1000; // prevent concurrent fetch
|
}
|
||||||
try {
|
msgEl.textContent = `Done. Device is rebooting. Redirecting in ${secs}s...`;
|
||||||
if ((await fetch("/", { cache: "no-store" })).ok) {
|
|
||||||
clearInterval(iv);
|
|
||||||
msgEl.textContent = "Device is back online. Redirecting to login...";
|
|
||||||
setTimeout(redirectToLogin, 1500);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
} catch (_) {}
|
|
||||||
wait = 4;
|
|
||||||
}, 1000);
|
}, 1000);
|
||||||
} else {
|
} else {
|
||||||
msgEl.textContent = "Failed: " + (xhr.responseText || String(xhr.status));
|
msgEl.textContent = "Failed: " + (xhr.responseText || String(xhr.status));
|
||||||
|
|||||||
Referência em uma Nova Issue
Bloquear um usuário