From 9fcdfd976acd3fc3babe45b98425c2af568c15ac Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Thu, 27 Nov 2025 11:48:16 +0000 Subject: [PATCH 1/8] Initial plan From c9ac77a2b7fc4bbaa2507537fdb36dd5c08fb85f Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Thu, 27 Nov 2025 11:54:48 +0000 Subject: [PATCH 2/8] Add must-revalidate to Cache-Control header for better cache invalidation Co-authored-by: DedeHai <6280424+DedeHai@users.noreply.github.com> --- wled00/wled_server.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/wled00/wled_server.cpp b/wled00/wled_server.cpp index d899d3113b..35c3c1c2fa 100644 --- a/wled00/wled_server.cpp +++ b/wled00/wled_server.cpp @@ -78,7 +78,8 @@ static void setStaticContentCacheHeaders(AsyncWebServerResponse *response, int c #ifndef WLED_DEBUG // this header name is misleading, "no-cache" will not disable cache, // it just revalidates on every load using the "If-None-Match" header with the last ETag value - response->addHeader(FPSTR(s_cache_control), F("no-cache")); + // must-revalidate ensures the browser MUST check with the server before using cached content + response->addHeader(FPSTR(s_cache_control), F("no-cache, must-revalidate")); #else response->addHeader(FPSTR(s_cache_control), F("no-store,max-age=0")); // prevent caching if debug build #endif From 2dfe09e1b52cba678c841f88cba5f1f4b3afd792 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Thu, 27 Nov 2025 11:55:55 +0000 Subject: [PATCH 3/8] Add must-revalidate to Cache-Control header for better cache invalidation Co-authored-by: DedeHai <6280424+DedeHai@users.noreply.github.com> --- _codeql_detected_source_root | 1 + 1 file changed, 1 insertion(+) create mode 120000 _codeql_detected_source_root diff --git a/_codeql_detected_source_root b/_codeql_detected_source_root new file mode 120000 index 0000000000..945c9b46d6 --- /dev/null +++ b/_codeql_detected_source_root @@ -0,0 +1 @@ +. \ No newline at end of file From 441bd62ad6c6789fa9f394c8f488f079d01e7433 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Thu, 27 Nov 2025 11:56:17 +0000 Subject: [PATCH 4/8] Remove CodeQL artifact and add to gitignore Co-authored-by: DedeHai <6280424+DedeHai@users.noreply.github.com> --- .gitignore | 1 + _codeql_detected_source_root | 1 - 2 files changed, 1 insertion(+), 1 deletion(-) delete mode 120000 _codeql_detected_source_root diff --git a/.gitignore b/.gitignore index ec9d4efcc3..256d7260c8 100644 --- a/.gitignore +++ b/.gitignore @@ -25,3 +25,4 @@ wled-update.sh /wled00/Release /wled00/wled00.ino.cpp /wled00/html_*.h +_codeql* diff --git a/_codeql_detected_source_root b/_codeql_detected_source_root deleted file mode 120000 index 945c9b46d6..0000000000 --- a/_codeql_detected_source_root +++ /dev/null @@ -1 +0,0 @@ -. \ No newline at end of file From 54f650a0e903688727374114c518fb1c19cd7b97 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Thu, 27 Nov 2025 13:00:02 +0000 Subject: [PATCH 5/8] Add WEB_BUILD_TIME to html_ui.h and use it for ETag generation Co-authored-by: DedeHai <6280424+DedeHai@users.noreply.github.com> --- tools/cdata.js | 14 ++++++++++++++ wled00/wled_server.cpp | 2 +- 2 files changed, 15 insertions(+), 1 deletion(-) diff --git a/tools/cdata.js b/tools/cdata.js index c569a6f2aa..01921dd1d8 100644 --- a/tools/cdata.js +++ b/tools/cdata.js @@ -38,6 +38,17 @@ const wledBanner = ` \t\t\x1b[36m build script for web UI \x1b[0m`; +// Generate build timestamp in format compatible with VERSION (yymmddb) +function generateBuildTime() { + const now = new Date(); + const yy = String(now.getFullYear() % 100).padStart(2, '0'); + const mm = String(now.getMonth() + 1).padStart(2, '0'); + const dd = String(now.getDate()).padStart(2, '0'); + // Build number 0-5 based on 4-hour time slots (6 slots per day) + const b = Math.floor(now.getHours() / 4); + return Number(`${yy}${mm}${dd}${b}`); +} + const singleHeader = `/* * Binary array for the Web UI. * gzip is used for smaller size and improved speeds. @@ -45,6 +56,9 @@ const singleHeader = `/* * Please see https://kno.wled.ge/advanced/custom-features/#changing-web-ui * to find out how to easily modify the web UI source! */ + +// Automatically generated build time for cache busting +#define WEB_BUILD_TIME ${generateBuildTime()} `; diff --git a/wled00/wled_server.cpp b/wled00/wled_server.cpp index 35c3c1c2fa..474a44d0a5 100644 --- a/wled00/wled_server.cpp +++ b/wled00/wled_server.cpp @@ -67,7 +67,7 @@ static bool inLocalSubnet(const IPAddress &client) { */ static void generateEtag(char *etag, uint16_t eTagSuffix) { - sprintf_P(etag, PSTR("%7d-%02x-%04x"), VERSION, cacheInvalidate, eTagSuffix); + sprintf_P(etag, PSTR("%7d-%02x-%04x"), WEB_BUILD_TIME, cacheInvalidate, eTagSuffix); } static void setStaticContentCacheHeaders(AsyncWebServerResponse *response, int code, uint16_t eTagSuffix = 0) { From 0adfc17617025cad69edd5ea8de22def557806dc Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Thu, 27 Nov 2025 13:13:42 +0000 Subject: [PATCH 6/8] Change WEB_BUILD_TIME format to YYMMDD_hhmmss (UTC) Co-authored-by: Aircoookie <21045690+Aircoookie@users.noreply.github.com> --- tools/cdata.js | 19 ++++++++++--------- wled00/wled_server.cpp | 2 +- 2 files changed, 11 insertions(+), 10 deletions(-) diff --git a/tools/cdata.js b/tools/cdata.js index 01921dd1d8..30b327fcfd 100644 --- a/tools/cdata.js +++ b/tools/cdata.js @@ -38,15 +38,16 @@ const wledBanner = ` \t\t\x1b[36m build script for web UI \x1b[0m`; -// Generate build timestamp in format compatible with VERSION (yymmddb) +// Generate build timestamp in YYMMDD_hhmmss format (UTC) function generateBuildTime() { const now = new Date(); - const yy = String(now.getFullYear() % 100).padStart(2, '0'); - const mm = String(now.getMonth() + 1).padStart(2, '0'); - const dd = String(now.getDate()).padStart(2, '0'); - // Build number 0-5 based on 4-hour time slots (6 slots per day) - const b = Math.floor(now.getHours() / 4); - return Number(`${yy}${mm}${dd}${b}`); + const yy = String(now.getUTCFullYear() % 100).padStart(2, '0'); + const mm = String(now.getUTCMonth() + 1).padStart(2, '0'); + const dd = String(now.getUTCDate()).padStart(2, '0'); + const hh = String(now.getUTCHours()).padStart(2, '0'); + const min = String(now.getUTCMinutes()).padStart(2, '0'); + const ss = String(now.getUTCSeconds()).padStart(2, '0'); + return `${yy}${mm}${dd}_${hh}${min}${ss}`; } const singleHeader = `/* @@ -57,8 +58,8 @@ const singleHeader = `/* * to find out how to easily modify the web UI source! */ -// Automatically generated build time for cache busting -#define WEB_BUILD_TIME ${generateBuildTime()} +// Automatically generated build time for cache busting (YYMMDD_hhmmss UTC) +#define WEB_BUILD_TIME "${generateBuildTime()}" `; diff --git a/wled00/wled_server.cpp b/wled00/wled_server.cpp index 474a44d0a5..d1db7c93d1 100644 --- a/wled00/wled_server.cpp +++ b/wled00/wled_server.cpp @@ -67,7 +67,7 @@ static bool inLocalSubnet(const IPAddress &client) { */ static void generateEtag(char *etag, uint16_t eTagSuffix) { - sprintf_P(etag, PSTR("%7d-%02x-%04x"), WEB_BUILD_TIME, cacheInvalidate, eTagSuffix); + sprintf_P(etag, PSTR("%s-%02x-%04x"), WEB_BUILD_TIME, cacheInvalidate, eTagSuffix); } static void setStaticContentCacheHeaders(AsyncWebServerResponse *response, int code, uint16_t eTagSuffix = 0) { From 714a7f816cd3dc5239d56743fddba1d94976fac0 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Thu, 27 Nov 2025 13:52:25 +0000 Subject: [PATCH 7/8] Change WEB_BUILD_TIME to UNIX timestamp integer for flash savings Co-authored-by: DedeHai <6280424+DedeHai@users.noreply.github.com> --- tools/cdata.js | 15 ++++----------- wled00/wled_server.cpp | 2 +- 2 files changed, 5 insertions(+), 12 deletions(-) diff --git a/tools/cdata.js b/tools/cdata.js index 30b327fcfd..759d24c2da 100644 --- a/tools/cdata.js +++ b/tools/cdata.js @@ -38,16 +38,9 @@ const wledBanner = ` \t\t\x1b[36m build script for web UI \x1b[0m`; -// Generate build timestamp in YYMMDD_hhmmss format (UTC) +// Generate build timestamp as UNIX timestamp (seconds since epoch) function generateBuildTime() { - const now = new Date(); - const yy = String(now.getUTCFullYear() % 100).padStart(2, '0'); - const mm = String(now.getUTCMonth() + 1).padStart(2, '0'); - const dd = String(now.getUTCDate()).padStart(2, '0'); - const hh = String(now.getUTCHours()).padStart(2, '0'); - const min = String(now.getUTCMinutes()).padStart(2, '0'); - const ss = String(now.getUTCSeconds()).padStart(2, '0'); - return `${yy}${mm}${dd}_${hh}${min}${ss}`; + return Math.floor(Date.now() / 1000); } const singleHeader = `/* @@ -58,8 +51,8 @@ const singleHeader = `/* * to find out how to easily modify the web UI source! */ -// Automatically generated build time for cache busting (YYMMDD_hhmmss UTC) -#define WEB_BUILD_TIME "${generateBuildTime()}" +// Automatically generated build time for cache busting (UNIX timestamp) +#define WEB_BUILD_TIME ${generateBuildTime()} `; diff --git a/wled00/wled_server.cpp b/wled00/wled_server.cpp index d1db7c93d1..d4e266d6a2 100644 --- a/wled00/wled_server.cpp +++ b/wled00/wled_server.cpp @@ -67,7 +67,7 @@ static bool inLocalSubnet(const IPAddress &client) { */ static void generateEtag(char *etag, uint16_t eTagSuffix) { - sprintf_P(etag, PSTR("%s-%02x-%04x"), WEB_BUILD_TIME, cacheInvalidate, eTagSuffix); + sprintf_P(etag, PSTR("%u-%02x-%04x"), WEB_BUILD_TIME, cacheInvalidate, eTagSuffix); } static void setStaticContentCacheHeaders(AsyncWebServerResponse *response, int code, uint16_t eTagSuffix = 0) { From db71cf3289c961f694313dd8366b1fcf6961fa0c Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Fri, 28 Nov 2025 06:12:11 +0000 Subject: [PATCH 8/8] Remove unnecessary must-revalidate and _codeql gitignore entry Co-authored-by: DedeHai <6280424+DedeHai@users.noreply.github.com> --- .gitignore | 1 - wled00/wled_server.cpp | 3 +-- 2 files changed, 1 insertion(+), 3 deletions(-) diff --git a/.gitignore b/.gitignore index 256d7260c8..ec9d4efcc3 100644 --- a/.gitignore +++ b/.gitignore @@ -25,4 +25,3 @@ wled-update.sh /wled00/Release /wled00/wled00.ino.cpp /wled00/html_*.h -_codeql* diff --git a/wled00/wled_server.cpp b/wled00/wled_server.cpp index d4e266d6a2..09aeaccff2 100644 --- a/wled00/wled_server.cpp +++ b/wled00/wled_server.cpp @@ -78,8 +78,7 @@ static void setStaticContentCacheHeaders(AsyncWebServerResponse *response, int c #ifndef WLED_DEBUG // this header name is misleading, "no-cache" will not disable cache, // it just revalidates on every load using the "If-None-Match" header with the last ETag value - // must-revalidate ensures the browser MUST check with the server before using cached content - response->addHeader(FPSTR(s_cache_control), F("no-cache, must-revalidate")); + response->addHeader(FPSTR(s_cache_control), F("no-cache")); #else response->addHeader(FPSTR(s_cache_control), F("no-store,max-age=0")); // prevent caching if debug build #endif