Fix WebConfig bootstrap for legacy Android Chrome
Physical LG Android 5.1.1 testing found Chrome 43 could decode gzip but failed on the bootstrap's arrow syntax. Use ES5 functions and Promises while preserving retries, version refresh, and optional abort handling. Keep Google Zopfli gzip compression at 1,000 iterations. Verified the flashed V4.3 through its WiFi link using the real Android browser: bootstrap and main page gzip responses completed, settings loaded at 910.525 MHz, and no JavaScript or transfer errors were reported. Add a loader syntax regression and document legacy browser support.
This commit is contained in:
1 parent
267773df7d
commit
6f6d1a2a7a
4 files changed
+52
-42
No files matched your search
@@ -112,6 +112,8 @@ Browsers decompress the pages automatically over ordinary HTTP. WebConfig
|
||||
returns HTTP 406 when a client explicitly excludes gzip. Its large page closes
|
||||
the TCP connection gracefully after the final acknowledged bytes so browsers
|
||||
do not report a completed download as aborted.
|
||||
The bootstrap uses ES5 syntax and Promise-based loading, including on Android
|
||||
5.1.1 with Chrome 43; newer JavaScript syntax must not prevent the page loading.
|
||||
|
||||
Most full-size ESP32 MQTT observer builds have the shared WebConfig portal. On a
|
||||
fresh device with no saved SSID:
|
||||
|
||||
@@ -135,16 +135,19 @@ def main():
|
||||
loader = ("<!doctype html><meta charset=utf-8><meta name=viewport "
|
||||
"content=\"width=device-width,initial-scale=1\"><title>MeshCore "
|
||||
"WebConfig</title><body>Loading MeshCore WebConfig…<script>"
|
||||
"(async()=>{let p;for(let n=0;n<3&&p===undefined;n++){const C="
|
||||
"window.AbortController,c=C&&new C(),t=c&&setTimeout(()=>c.abort()"
|
||||
",90000);try{const r=await fetch(\"/ui?v=%s\",c?{signal:c.signal}"
|
||||
":{});if(r.ok)p=await r.text();else if(r.status===409)return "
|
||||
"location.reload()}catch(e){}finally{if(t)clearTimeout(t)}if(p==="
|
||||
"undefined)await new Promise(r=>setTimeout(r,500*(n+1)))}if(p==="
|
||||
"undefined)throw Error(\"transfer failed\");document.open();"
|
||||
"document.write(p);document.close()})().catch(e=>"
|
||||
# Android 5.1's stock Chrome 43 supports fetch and Promises, but
|
||||
# cannot parse arrows or async functions. Match the main UI's
|
||||
# ES5 syntax so the bootstrap cannot strand those browsers.
|
||||
"(function(){var n=0;function load(){var C=window.AbortController,"
|
||||
"c=C&&new C(),t=c&&setTimeout(function(){c.abort()},90000);"
|
||||
"fetch(\"/ui?v=%s\",c?{signal:c.signal}:{}).then(function(r){"
|
||||
"if(r.ok)return r.text();if(r.status===409){location.reload();"
|
||||
"return null}throw Error(\"transfer failed\")}).then(function(p){"
|
||||
"if(t)clearTimeout(t);if(p===null)return;document.open();"
|
||||
"document.write(p);document.close()},function(e){"
|
||||
"if(t)clearTimeout(t);if(++n<3)setTimeout(load,500*n);else "
|
||||
"document.body.textContent=\"Unable to load WebConfig: \"+e+"
|
||||
"\". Reload to retry.\")</script>" % version)
|
||||
"\". Reload to retry.\"})}load()})()</script>" % version)
|
||||
loader_bytes = compress_page(loader.encode("utf-8"))
|
||||
success_bytes = compress_page(b"<HTML><HEAD><TITLE>Success</TITLE></HEAD><BODY>Success</BODY></HTML>")
|
||||
etag = hashlib.sha256(loader_bytes).hexdigest()[:16]
|
||||
|
||||
@@ -7,42 +7,40 @@
|
||||
#include <pgmspace.h>
|
||||
|
||||
const uint32_t WEBCONFIG_HTML_GZ_LEN = 33969;
|
||||
const char WEBCONFIG_HTML_ETAG[] = "\"96a1dfcd38a0ae5a\"";
|
||||
const char WEBCONFIG_HTML_ETAG[] = "\"25ca2f61b991b105\"";
|
||||
const char WEBCONFIG_HTML_VERSION[] = "4d14ae4de3268605";
|
||||
const uint16_t WEBCONFIG_HTML_LOADER_LEN = 493;
|
||||
const uint16_t WEBCONFIG_HTML_LOADER_LEN = 462;
|
||||
const uint16_t WEBCONFIG_HTML_SUCCESS_LEN = 65;
|
||||
const uint8_t WEBCONFIG_HTML_LOADER[] PROGMEM = {
|
||||
0x1f,0x8b,0x08,0x00,0x00,0x00,0x00,0x00,0x02,0xff,0xb2,0x51,0x4c,0x01,0xb4,0x49,
|
||||
0x1d,0xcb,0x91,0xc2,0x40,0xf4,0x57,0x54,0x0e,0x94,0x34,0x79,0x9c,0x6d,0x10,0x1b,
|
||||
0xa8,0x3d,0x6d,0xce,0x67,0x8d,0x68,0x8c,0x6a,0x85,0x44,0xb5,0x1a,0xe3,0xf8,0xef,
|
||||
0x2b,0x9c,0x53,0x5f,0x3a,0xe7,0xe7,0x35,0x9d,0xb5,0xc0,0x6a,0x6a,0x6c,0x9e,0x35,
|
||||
0x40,0x8a,0xe9,0x5a,0x61,0x00,0x92,0x1d,0x55,0xd3,0x83,0x5b,0x9b,0x53,0x0d,0xc8,
|
||||
0x13,0x03,0x7d,0xeb,0x91,0x98,0xf6,0x8e,0xc0,0x91,0x5c,0xeb,0x4d,0x49,0xb5,0x2c,
|
||||
0xe1,0xc4,0x68,0x98,0x5e,0x2b,0x13,0xe3,0x0c,0x19,0x65,0xa7,0x41,0x2b,0x0b,0x72,
|
||||
0xb9,0x96,0x67,0x64,0xc8,0x42,0xfe,0x19,0x42,0x5d,0x78,0x04,0xf6,0x17,0x56,0x85,
|
||||
0x77,0x95,0x39,0xce,0xe6,0x37,0x9e,0x6c,0xe5,0xcb,0xb3,0xfc,0x93,0x57,0xa5,0x71,
|
||||
0xc7,0xec,0x65,0x5c,0x52,0x83,0xb5,0xa6,0x4d,0xb3,0xa0,0xd1,0xb4,0x94,0x73,0x15,
|
||||
0xce,0x9c,0xe6,0x42,0xe6,0x17,0x16,0x88,0xb5,0x69,0xe5,0x91,0x0f,0x92,0x93,0x8b,
|
||||
0xd4,0x65,0xdb,0x49,0xd2,0x4a,0x29,0x3b,0x57,0x42,0x65,0x1c,0x94,0xa9,0x1b,0x8f,
|
||||
0xc5,0x85,0xf6,0x2e,0x10,0x2b,0x64,0x6f,0x5c,0xe9,0xfb,0xd9,0xbb,0x95,0x47,0x8a,
|
||||
0xe5,0x09,0xbd,0xb5,0x80,0x13,0x2d,0x8b,0x24,0x71,0xd0,0xb3,0x82,0x8b,0x09,0x49,
|
||||
0x9d,0x24,0x01,0xe8,0x97,0x69,0xc0,0x77,0xc4,0x87,0x56,0x7a,0xa6,0x86,0x94,0xe8,
|
||||
0x3d,0x5c,0x44,0x12,0x29,0xe1,0xd9,0x6d,0x51,0x94,0xaa,0x57,0x86,0x58,0x05,0xa4,
|
||||
0x6b,0xbe,0x36,0xef,0xcc,0x9b,0x13,0xb9,0x53,0x2e,0x77,0x14,0xec,0x94,0xb0,0xbd,
|
||||
0xb5,0x77,0xb0,0xb7,0xd8,0x5d,0x9b,0xe8,0x37,0x17,0xc1,0x1c,0x3b,0x65,0x8f,0xf4,
|
||||
0xec,0x46,0xb8,0x3a,0xba,0xb8,0x12,0xa9,0xa9,0x38,0xce,0xfc,0x3f,0xd1,0xde,0x96,
|
||||
0xc1,0x19,0xc1,0x69,0x6c,0x94,0x82,0x0d,0xc0,0xae,0xbd,0x81,0x14,0x75,0x41,0x4a,
|
||||
0xb9,0xb3,0x38,0x14,0x08,0xd4,0xa1,0x63,0xd6,0x6b,0x45,0xc6,0xbb,0x19,0x82,0x8d,
|
||||
0xa7,0xe3,0xe2,0x2a,0xea,0xb1,0x3f,0x88,0x8b,0xab,0xca,0xc4,0xea,0xf6,0xec,0x22,
|
||||
0x26,0x93,0xd0,0x16,0x14,0xde,0xae,0x12,0xd5,0xab,0x68,0x7c,0x72,0x1f,0x71,0xd3,
|
||||
0x76,0x58,0xfe,0x1b,0xfa,0xc6,0x04,0xe0,0x28,0xf3,0x47,0xeb,0xe3,0x64,0x77,0xb1,
|
||||
0x18,0x71,0x37,0x5e,0x0a,0xf1,0x4a,0x3a,0xd5,0xe8,0x7b,0xf6,0x01,0xd1,0x23,0x5f,
|
||||
0x23,0x54,0x2e,0x54,0x80,0xac,0x52,0xc6,0x42,0xb9,0x26,0xd2,0x08,0xb0,0xae,0x01,
|
||||
0x47,0x33,0xdf,0x82,0xe3,0x8f,0xf4,0x1e,0x0d,0x01,0x6f,0x1f,0x59,0xb4,0xf5,0x01,
|
||||
0xe2,0x22,0x82,0x8b,0xd9,0xed,0x32,0x32,0xbf,0xf7,0x0e,0x28,0xb9,0x3e,0x4d,0x71,
|
||||
0x87,0xbe,0xdf,0x4e,0xad,0x2c,0x30,0xf2,0x6c,0xb8,0xc0,0x03,0x60,0x8e,0xd8,0xda,
|
||||
0x18,0xc6,0x6b,0x33,0xf6,0x03,0x06,0xc7,0x10,0x80,0x40,0x78,0x36,0x5b,0x13,0xd9,
|
||||
0xfc,0x16,0x44,0xff,0x01,0x17,0x05,0x67,0x30,0xfa,0x02,0x00,0x00,
|
||||
0x1f,0x8b,0x08,0x00,0x00,0x00,0x00,0x00,0x02,0xff,0x75,0x52,0x47,0x77,0xdb,0x30,
|
||||
0x0c,0xfe,0x2b,0x6c,0xa6,0xe8,0xed,0xec,0x44,0xa2,0x3b,0xf4,0x7a,0xea,0xde,0x67,
|
||||
0x9a,0x82,0x2c,0xbe,0xd2,0x80,0x1e,0x04,0x59,0x59,0xfa,0xef,0x8d,0x57,0x77,0x70,
|
||||
0xc1,0xde,0x5f,0xf2,0x24,0x23,0x27,0x37,0x25,0xa8,0x42,0xe6,0x61,0x92,0xcc,0x41,
|
||||
0xac,0x72,0x85,0xe5,0x0a,0xc4,0xd4,0x92,0xf7,0x2f,0x36,0x36,0xb4,0x73,0x30,0x0b,
|
||||
0x0f,0x4d,0x49,0x2c,0xca,0x11,0x0a,0xa0,0x98,0x9d,0xc6,0x67,0x52,0x98,0x0c,0x16,
|
||||
0xde,0x41,0x7f,0xa5,0xf4,0x3c,0x7a,0xf1,0x36,0xf4,0x2b,0x67,0x03,0x98,0xf1,0xce,
|
||||
0x24,0x11,0x2f,0x01,0x26,0x6f,0xa0,0x2a,0x52,0x62,0x50,0xdf,0x60,0x9a,0x12,0xe6,
|
||||
0x7e,0x96,0x0c,0xd7,0x9e,0x64,0x4a,0xd9,0xcd,0xe4,0x35,0xd9,0xcc,0xe3,0x4c,0xfd,
|
||||
0x1b,0x77,0x50,0x40,0x08,0xbe,0x8c,0x93,0xca,0xb1,0x2f,0x65,0x12,0xe5,0x35,0x3a,
|
||||
0xf1,0x84,0x91,0xbe,0x5b,0x58,0x56,0x68,0x46,0xf1,0xd6,0xa4,0xc2,0x43,0x99,0x8d,
|
||||
0x3d,0x35,0x8d,0xc7,0x8c,0x9a,0xc1,0xf3,0x29,0xb1,0xa4,0x84,0xc2,0x14,0x02,0x70,
|
||||
0xcf,0x99,0xf4,0xe0,0x00,0xa1,0x51,0x69,0xa4,0x7b,0x62,0xdc,0xc1,0x41,0x05,0xf2,
|
||||
0xd9,0xcf,0x81,0x6a,0xf9,0xbd,0xb8,0x1b,0xd8,0x65,0x66,0xa4,0xdb,0xde,0xe5,0xe8,
|
||||
0x81,0x74,0x9c,0x83,0xb8,0x22,0xda,0x19,0xd6,0xfe,0xe9,0xc2,0x9c,0x64,0xe3,0x13,
|
||||
0x0b,0x27,0x19,0x1c,0x1f,0x9d,0x5d,0x9c,0x8d,0x4e,0x77,0x7a,0xee,0xe9,0x5d,0xe5,
|
||||
0x67,0x68,0xc3,0x95,0x1b,0xac,0x85,0xf6,0xea,0xae,0xd5,0x03,0x29,0x00,0x7f,0x15,
|
||||
0x66,0x7d,0xe7,0xf3,0x88,0x07,0xf4,0x5d,0x33,0x48,0xcd,0xa8,0x78,0x20,0x70,0x2d,
|
||||
0x91,0x8e,0x57,0xf6,0x4a,0xac,0xd4,0x95,0x31,0xe6,0x64,0x74,0xa9,0xef,0x02,0x39,
|
||||
0xbb,0x4c,0x1b,0x30,0xac,0x77,0x8b,0x37,0x49,0x58,0x87,0xd0,0x4a,0xc1,0xd4,0xa8,
|
||||
0x97,0xcc,0xc4,0xd1,0x8e,0xb0,0xc5,0x2a,0x07,0x56,0xb9,0xf5,0x01,0xb2,0x1d,0xfd,
|
||||
0x4f,0xeb,0x72,0xd5,0x5a,0xb4,0x0b,0x60,0x79,0xbb,0xb1,0xac,0xfa,0x96,0xc6,0x98,
|
||||
0x65,0xc9,0xcd,0x4c,0x71,0x46,0xae,0x9e,0x03,0xca,0x80,0x4a,0xc0,0x48,0xff,0xd2,
|
||||
0x1b,0xf6,0x02,0x51,0xf9,0x9b,0xc5,0x05,0xaa,0x60,0x79,0xa5,0x9f,0x7d,0xe0,0xf1,
|
||||
0x3e,0xdd,0x2e,0x26,0xc7,0xfa,0xb7,0x83,0x2f,0xb7,0xea,0x9d,0x8e,0x46,0x1d,0xd4,
|
||||
0x31,0x84,0x0a,0xd4,0xcf,0xba,0x4b,0x5c,0xac,0x2e,0x93,0x6e,0xf1,0xf6,0x05,0xed,
|
||||
0x34,0x80,0x12,0x5a,0xfd,0xf9,0x17,0x44,0xae,0xd4,0x4e,0x17,0xba,0x3b,0x03,0xf5,
|
||||
0x11,0x56,0x0e,0x21,0xc5,0x20,0x7c,0x33,0xd8,0x69,0x75,0xbb,0x3e,0x5b,0xab,0x23,
|
||||
0x9d,0x0c,0x37,0x10,0xfa,0x01,0x0f,0x69,0xb6,0x3f,0xf8,0x02,0x00,0x00,
|
||||
};
|
||||
|
||||
const uint8_t WEBCONFIG_HTML_GZ[] PROGMEM = {
|
||||
|
||||
@@ -52,6 +52,13 @@ class WebConfigGzipTest(unittest.TestCase):
|
||||
for page in (ROOT / "webui/pages").glob("*.html"):
|
||||
self.assertEqual(gzip.decompress(blobs["MESH_HTML_" + page.stem.upper()]), page.read_bytes())
|
||||
|
||||
def test_loader_matches_legacy_android_browser_syntax(self):
|
||||
blobs = arrays((ROOT / "src/helpers/esp32/WebConfigHtml.h").read_text())
|
||||
loader = gzip.decompress(blobs["WEBCONFIG_HTML_LOADER"]).decode()
|
||||
script = loader.split("<script>", 1)[1].split("</script>", 1)[0]
|
||||
self.assertNotIn("=>", script)
|
||||
self.assertNotRegex(script, r"\b(?:async|await|let|const)\b")
|
||||
|
||||
def test_gzip_binding_uses_1000_iterations_without_changing_raw_ota_default(self):
|
||||
with mock.patch.object(zopfli_compress._gzip, "compress",
|
||||
return_value=gzip.compress(b"page", mtime=0)) as compress:
|
||||
|
||||
Reference in new issue
Block a user