From c15bfd243a3bf368def91b8a6edd6885bf5d483d Mon Sep 17 00:00:00 2001 From: "J. Nick Koston" Date: Sun, 25 Jan 2026 23:55:11 -1000 Subject: [PATCH] [web_server_idf] Reduce heap allocations by using stack buffers --- esphome/components/web_server_idf/utils.cpp | 7 ++----- .../web_server_idf/web_server_idf.cpp | 21 ++++++++++--------- 2 files changed, 13 insertions(+), 15 deletions(-) diff --git a/esphome/components/web_server_idf/utils.cpp b/esphome/components/web_server_idf/utils.cpp index f27814062c..a5b480bb77 100644 --- a/esphome/components/web_server_idf/utils.cpp +++ b/esphome/components/web_server_idf/utils.cpp @@ -78,11 +78,8 @@ optional query_key_value(const std::string &query_url, const std::s return {}; } - auto val = std::unique_ptr(new char[query_url.size()]); - if (!val) { - ESP_LOGE(TAG, "Not enough memory to the query key value"); - return {}; - } + // Use stack buffer for typical query strings, heap fallback for large ones + SmallBufferWithHeapFallback<256, char> val(query_url.size()); if (httpd_query_key_value(query_url.c_str(), key.c_str(), val.get(), query_url.size()) != ESP_OK) { return {}; diff --git a/esphome/components/web_server_idf/web_server_idf.cpp b/esphome/components/web_server_idf/web_server_idf.cpp index abeda5fc46..082aecf69f 100644 --- a/esphome/components/web_server_idf/web_server_idf.cpp +++ b/esphome/components/web_server_idf/web_server_idf.cpp @@ -352,14 +352,15 @@ bool AsyncWebServerRequest::authenticate(const char *username, const char *passw memcpy(user_info + user_len + 1, password, pass_len); user_info[user_info_len] = '\0'; - size_t n = 0, out; - esp_crypto_base64_encode(nullptr, 0, &n, reinterpret_cast(user_info), user_info_len); - - auto digest = std::unique_ptr(new char[n + 1]); - esp_crypto_base64_encode(reinterpret_cast(digest.get()), n, &out, + // Base64 output size is ceil(input_len * 4/3) + 1, with input bounded to 256 bytes + // max output is ceil(256 * 4/3) + 1 = 343 bytes, use 350 for safety + constexpr size_t max_digest_len = 350; + char digest[max_digest_len]; + size_t out; + esp_crypto_base64_encode(reinterpret_cast(digest), max_digest_len, &out, reinterpret_cast(user_info), user_info_len); - return strcmp(digest.get(), auth_str + auth_prefix_len) == 0; + return strcmp(digest, auth_str + auth_prefix_len) == 0; } void AsyncWebServerRequest::requestAuthentication(const char *realm) const { @@ -869,12 +870,12 @@ esp_err_t AsyncWebServer::handle_multipart_upload_(httpd_req_t *r, const char *c } }); - // Process data - std::unique_ptr buffer(new char[MULTIPART_CHUNK_SIZE]); + // Process data - use stack buffer to avoid heap allocation + char buffer[MULTIPART_CHUNK_SIZE]; size_t bytes_since_yield = 0; for (size_t remaining = r->content_len; remaining > 0;) { - int recv_len = httpd_req_recv(r, buffer.get(), std::min(remaining, MULTIPART_CHUNK_SIZE)); + int recv_len = httpd_req_recv(r, buffer, std::min(remaining, MULTIPART_CHUNK_SIZE)); if (recv_len <= 0) { httpd_resp_send_err(r, recv_len == HTTPD_SOCK_ERR_TIMEOUT ? HTTPD_408_REQ_TIMEOUT : HTTPD_400_BAD_REQUEST, @@ -882,7 +883,7 @@ esp_err_t AsyncWebServer::handle_multipart_upload_(httpd_req_t *r, const char *c return recv_len == HTTPD_SOCK_ERR_TIMEOUT ? ESP_ERR_TIMEOUT : ESP_FAIL; } - if (reader->parse(buffer.get(), recv_len) != static_cast(recv_len)) { + if (reader->parse(buffer, recv_len) != static_cast(recv_len)) { ESP_LOGW(TAG, "Multipart parser error"); httpd_resp_send_err(r, HTTPD_400_BAD_REQUEST, nullptr); return ESP_FAIL;