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.
This commit is contained in:
@@ -2641,22 +2641,14 @@ const char kWebPanelAppHtml[] PROGMEM = R"HTML(
|
||||
}
|
||||
if (xhr.status === 200) {
|
||||
barEl.style.width = "100%";
|
||||
msgEl.textContent = "Done. Device is rebooting";
|
||||
let wait = 4;
|
||||
const iv = setInterval(async () => {
|
||||
msgEl.textContent += '.';
|
||||
if (msgEl.textContent.length > 85) { clearInterval(iv); msgEl.textContent = "Device did not come back online. =("; return; }
|
||||
if (--wait) { return; }
|
||||
wait = 1000; // prevent concurrent fetch
|
||||
try {
|
||||
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;
|
||||
let secs = 10;
|
||||
const iv = setInterval(() => {
|
||||
if (--secs <= 0) {
|
||||
clearInterval(iv);
|
||||
redirectToLogin();
|
||||
return;
|
||||
}
|
||||
msgEl.textContent = `Done. Device is rebooting. Redirecting in ${secs}s...`;
|
||||
}, 1000);
|
||||
} else {
|
||||
msgEl.textContent = "Failed: " + (xhr.responseText || String(xhr.status));
|
||||
|
||||
Reference in New Issue
Block a user