mirror of
https://github.com/esphome/esphome.git
synced 2026-02-08 00:31:58 +00:00
[web_server_idf] Reduce heap usage in DefaultHeaders and auth (#13141)
This commit is contained in:
@@ -34,6 +34,8 @@ async def to_code(config):
|
||||
cg.add(cg.RawExpression(f"{web_server_base_ns}::global_web_server_base = {var}"))
|
||||
|
||||
if CORE.is_esp32:
|
||||
# Count for StaticVector in web_server_idf - matches headers added in init()
|
||||
cg.add_define("WEB_SERVER_DEFAULT_HEADERS_COUNT", 1)
|
||||
return
|
||||
|
||||
if CORE.using_arduino:
|
||||
|
||||
@@ -100,6 +100,8 @@ class WebServerBase : public Component {
|
||||
}
|
||||
this->server_ = std::make_unique<AsyncWebServer>(this->port_);
|
||||
// All content is controlled and created by user - so allowing all origins is fine here.
|
||||
// NOTE: Currently 1 header. If more are added, update in __init__.py:
|
||||
// cg.add_define("WEB_SERVER_DEFAULT_HEADERS_COUNT", 1)
|
||||
DefaultHeaders::Instance().addHeader(ESPHOME_F("Access-Control-Allow-Origin"), ESPHOME_F("*"));
|
||||
this->server_->begin();
|
||||
|
||||
|
||||
@@ -309,8 +309,8 @@ void AsyncWebServerRequest::init_response_(AsyncWebServerResponse *rsp, int code
|
||||
}
|
||||
httpd_resp_set_hdr(*this, "Accept-Ranges", "none");
|
||||
|
||||
for (const auto &pair : DefaultHeaders::Instance().headers_) {
|
||||
httpd_resp_set_hdr(*this, pair.first.c_str(), pair.second.c_str());
|
||||
for (const auto &header : DefaultHeaders::Instance().headers_) {
|
||||
httpd_resp_set_hdr(*this, header.name, header.value);
|
||||
}
|
||||
|
||||
delete this->rsp_;
|
||||
@@ -335,17 +335,29 @@ bool AsyncWebServerRequest::authenticate(const char *username, const char *passw
|
||||
return false;
|
||||
}
|
||||
|
||||
std::string user_info;
|
||||
user_info += username;
|
||||
user_info += ':';
|
||||
user_info += password;
|
||||
// Build user:pass in stack buffer to avoid heap allocation
|
||||
constexpr size_t max_user_info_len = 256;
|
||||
char user_info[max_user_info_len];
|
||||
size_t user_len = strlen(username);
|
||||
size_t pass_len = strlen(password);
|
||||
size_t user_info_len = user_len + 1 + pass_len;
|
||||
|
||||
if (user_info_len >= max_user_info_len) {
|
||||
ESP_LOGW(TAG, "Credentials too long for authentication");
|
||||
return false;
|
||||
}
|
||||
|
||||
memcpy(user_info, username, user_len);
|
||||
user_info[user_len] = ':';
|
||||
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<const uint8_t *>(user_info.c_str()), user_info.size());
|
||||
esp_crypto_base64_encode(nullptr, 0, &n, reinterpret_cast<const uint8_t *>(user_info), user_info_len);
|
||||
|
||||
auto digest = std::unique_ptr<char[]>(new char[n + 1]);
|
||||
esp_crypto_base64_encode(reinterpret_cast<uint8_t *>(digest.get()), n, &out,
|
||||
reinterpret_cast<const uint8_t *>(user_info.c_str()), user_info.size());
|
||||
reinterpret_cast<const uint8_t *>(user_info), user_info_len);
|
||||
|
||||
return strcmp(digest.get(), auth_str + auth_prefix_len) == 0;
|
||||
}
|
||||
@@ -483,8 +495,8 @@ AsyncEventSourceResponse::AsyncEventSourceResponse(const AsyncWebServerRequest *
|
||||
httpd_resp_set_hdr(req, "Cache-Control", "no-cache");
|
||||
httpd_resp_set_hdr(req, "Connection", "keep-alive");
|
||||
|
||||
for (const auto &pair : DefaultHeaders::Instance().headers_) {
|
||||
httpd_resp_set_hdr(req, pair.first.c_str(), pair.second.c_str());
|
||||
for (const auto &header : DefaultHeaders::Instance().headers_) {
|
||||
httpd_resp_set_hdr(req, header.name, header.value);
|
||||
}
|
||||
|
||||
httpd_resp_send_chunk(req, CRLF_STR, CRLF_LEN);
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
#ifdef USE_ESP32
|
||||
|
||||
#include "esphome/core/defines.h"
|
||||
#include "esphome/core/helpers.h"
|
||||
#include <esp_http_server.h>
|
||||
|
||||
#include <atomic>
|
||||
@@ -327,6 +328,11 @@ class AsyncEventSource : public AsyncWebHandler {
|
||||
};
|
||||
#endif // USE_WEBSERVER
|
||||
|
||||
struct HttpHeader {
|
||||
const char *name;
|
||||
const char *value;
|
||||
};
|
||||
|
||||
class DefaultHeaders {
|
||||
friend class AsyncWebServerRequest;
|
||||
#ifdef USE_WEBSERVER
|
||||
@@ -335,13 +341,14 @@ class DefaultHeaders {
|
||||
|
||||
public:
|
||||
// NOLINTNEXTLINE(readability-identifier-naming)
|
||||
void addHeader(const char *name, const char *value) { this->headers_.emplace_back(name, value); }
|
||||
void addHeader(const char *name, const char *value) { this->headers_.push_back({name, value}); }
|
||||
|
||||
// NOLINTNEXTLINE(readability-identifier-naming)
|
||||
static DefaultHeaders &Instance();
|
||||
|
||||
protected:
|
||||
std::vector<std::pair<std::string, std::string>> headers_;
|
||||
// Stack-allocated, no reallocation machinery. Count defined in web_server_base where headers are added.
|
||||
StaticVector<HttpHeader, WEB_SERVER_DEFAULT_HEADERS_COUNT> headers_;
|
||||
};
|
||||
|
||||
} // namespace web_server_idf
|
||||
|
||||
@@ -213,6 +213,7 @@
|
||||
#define USE_WEBSERVER_PORT 80 // NOLINT
|
||||
#define USE_WEBSERVER_GZIP
|
||||
#define USE_WEBSERVER_SORTING
|
||||
#define WEB_SERVER_DEFAULT_HEADERS_COUNT 1
|
||||
#define USE_CAPTIVE_PORTAL_GZIP
|
||||
#define USE_WIFI_11KV_SUPPORT
|
||||
#define USE_WIFI_FAST_CONNECT
|
||||
|
||||
Reference in New Issue
Block a user