From 16066547fa641d8f645f347a4362bac543daa785 Mon Sep 17 00:00:00 2001 From: "Valentin V. Bartenev" Date: Wed, 6 May 2026 22:33:00 +0300 Subject: [PATCH] Web: use sizeof instead of strlen for PROGMEM HTML page sizes MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The HTML pages (login, app, stats) are string literals compiled into PROGMEM. Their sizes are known at compile time, but the previous sendProgmemChunked() called strlen() on every request to determine the length, requiring a full scan of potentially tens of kilobytes of PROGMEM data before the first byte was sent. Replace sendProgmemChunked() with a sendWhole() function that accepts an explicit length parameter, and introduce a sendProgmem() macro that passes sizeof(mem) - 1 at the call site. For array literals this resolves to a compile-time constant, eliminating the runtime strlen scan entirely. The rename from sendProgmemChunked() to sendWhole() also better reflects what the function does — it sends the entire buffer in chunks — rather than where the data comes from. --- src/helpers/web/WebPanelServer.cpp | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/src/helpers/web/WebPanelServer.cpp b/src/helpers/web/WebPanelServer.cpp index bd457293..2510f987 100644 --- a/src/helpers/web/WebPanelServer.cpp +++ b/src/helpers/web/WebPanelServer.cpp @@ -65,12 +65,13 @@ esp_err_t sendChunk(httpd_req_t* req, const char* text) { return httpd_resp_sendstr_chunk(req, text != nullptr ? text : ""); } -esp_err_t sendProgmemChunked(httpd_req_t* req, const char* text) { +#define sendProgmem(req, mem) sendWhole(req, mem, sizeof(mem) - 1) + +esp_err_t sendWhole(httpd_req_t* req, const char* text, const size_t len) { if (text == nullptr) { return httpd_resp_send_chunk(req, nullptr, 0); } - const size_t len = strlen(text); size_t offset = 0; while (offset < len) { const size_t chunk_len = ((len - offset) > kWebPageChunkSize) ? kWebPageChunkSize : (len - offset); @@ -2682,7 +2683,7 @@ esp_err_t WebPanelServer::handleIndex(httpd_req_t* req) { } ctx->self->noteActivity(); httpd_resp_set_type(req, "text/html; charset=utf-8"); - return sendProgmemChunked(req, kWebPanelLoginHtml); + return sendProgmem(req, kWebPanelLoginHtml); } esp_err_t WebPanelServer::handleHttpRedirect(httpd_req_t* req) { @@ -2708,7 +2709,7 @@ esp_err_t WebPanelServer::handleApp(httpd_req_t* req) { } ctx->self->noteActivity(); httpd_resp_set_type(req, "text/html; charset=utf-8"); - return sendProgmemChunked(req, kWebPanelAppHtml); + return sendProgmem(req, kWebPanelAppHtml); } esp_err_t WebPanelServer::handleStatsPage(httpd_req_t* req) { @@ -2719,9 +2720,9 @@ esp_err_t WebPanelServer::handleStatsPage(httpd_req_t* req) { ctx->self->noteActivity(); httpd_resp_set_type(req, "text/html; charset=utf-8"); if (ctx->self->_runner != nullptr && !ctx->self->_runner->isWebStatsEnabled()) { - return sendProgmemChunked(req, kWebPanelStatsDisabledHtml); + return sendProgmem(req, kWebPanelStatsDisabledHtml); } - return sendProgmemChunked(req, kWebPanelAppHtml); + return sendProgmem(req, kWebPanelAppHtml); } esp_err_t WebPanelServer::handleLogin(httpd_req_t* req) {