1
0
mirror of https://github.com/esphome/esphome.git synced 2025-10-09 13:23:47 +01:00

[web_server_idf] Optimize parameter storage to reduce flash usage and memory overhead (#11003)

This commit is contained in:
J. Nick Koston
2025-10-05 15:57:59 -05:00
committed by GitHub
parent 9b6d62cd69
commit c0fb0ae06f
2 changed files with 39 additions and 15 deletions

View File

@@ -204,8 +204,8 @@ esp_err_t AsyncWebServer::request_handler_(AsyncWebServerRequest *request) const
AsyncWebServerRequest::~AsyncWebServerRequest() { AsyncWebServerRequest::~AsyncWebServerRequest() {
delete this->rsp_; delete this->rsp_;
for (const auto &pair : this->params_) { for (auto *param : this->params_) {
delete pair.second; // NOLINT(cppcoreguidelines-owning-memory) delete param; // NOLINT(cppcoreguidelines-owning-memory)
} }
} }
@@ -245,10 +245,22 @@ void AsyncWebServerRequest::redirect(const std::string &url) {
} }
void AsyncWebServerRequest::init_response_(AsyncWebServerResponse *rsp, int code, const char *content_type) { void AsyncWebServerRequest::init_response_(AsyncWebServerResponse *rsp, int code, const char *content_type) {
httpd_resp_set_status(*this, code == 200 ? HTTPD_200 // Set status code - use constants for common codes to avoid string allocation
: code == 404 ? HTTPD_404 const char *status = nullptr;
: code == 409 ? HTTPD_409 switch (code) {
: to_string(code).c_str()); case 200:
status = HTTPD_200;
break;
case 404:
status = HTTPD_404;
break;
case 409:
status = HTTPD_409;
break;
default:
break;
}
httpd_resp_set_status(*this, status == nullptr ? to_string(code).c_str() : status);
if (content_type && *content_type) { if (content_type && *content_type) {
httpd_resp_set_type(*this, content_type); httpd_resp_set_type(*this, content_type);
@@ -305,11 +317,14 @@ void AsyncWebServerRequest::requestAuthentication(const char *realm) const {
#endif #endif
AsyncWebParameter *AsyncWebServerRequest::getParam(const std::string &name) { AsyncWebParameter *AsyncWebServerRequest::getParam(const std::string &name) {
auto find = this->params_.find(name); // Check cache first - only successful lookups are cached
if (find != this->params_.end()) { for (auto *param : this->params_) {
return find->second; if (param->name() == name) {
return param;
}
} }
// Look up value from query strings
optional<std::string> val = query_key_value(this->post_query_, name); optional<std::string> val = query_key_value(this->post_query_, name);
if (!val.has_value()) { if (!val.has_value()) {
auto url_query = request_get_url_query(*this); auto url_query = request_get_url_query(*this);
@@ -318,11 +333,14 @@ AsyncWebParameter *AsyncWebServerRequest::getParam(const std::string &name) {
} }
} }
AsyncWebParameter *param = nullptr; // Don't cache misses to avoid wasting memory when handlers check for
if (val.has_value()) { // optional parameters that don't exist in the request
param = new AsyncWebParameter(val.value()); // NOLINT(cppcoreguidelines-owning-memory) if (!val.has_value()) {
return nullptr;
} }
this->params_.insert({name, param});
auto *param = new AsyncWebParameter(name, val.value()); // NOLINT(cppcoreguidelines-owning-memory)
this->params_.push_back(param);
return param; return param;
} }

View File

@@ -30,10 +30,12 @@ using String = std::string;
class AsyncWebParameter { class AsyncWebParameter {
public: public:
AsyncWebParameter(std::string value) : value_(std::move(value)) {} AsyncWebParameter(std::string name, std::string value) : name_(std::move(name)), value_(std::move(value)) {}
const std::string &name() const { return this->name_; }
const std::string &value() const { return this->value_; } const std::string &value() const { return this->value_; }
protected: protected:
std::string name_;
std::string value_; std::string value_;
}; };
@@ -174,7 +176,11 @@ class AsyncWebServerRequest {
protected: protected:
httpd_req_t *req_; httpd_req_t *req_;
AsyncWebServerResponse *rsp_{}; AsyncWebServerResponse *rsp_{};
std::map<std::string, AsyncWebParameter *> params_; // Use vector instead of map/unordered_map: most requests have 0-3 params, so linear search
// is faster than tree/hash overhead. AsyncWebParameter stores both name and value to avoid
// duplicate storage. Only successful lookups are cached to prevent cache pollution when
// handlers check for optional parameters that don't exist.
std::vector<AsyncWebParameter *> params_;
std::string post_query_; std::string post_query_;
AsyncWebServerRequest(httpd_req_t *req) : req_(req) {} AsyncWebServerRequest(httpd_req_t *req) : req_(req) {}
AsyncWebServerRequest(httpd_req_t *req, std::string post_query) : req_(req), post_query_(std::move(post_query)) {} AsyncWebServerRequest(httpd_req_t *req, std::string post_query) : req_(req), post_query_(std::move(post_query)) {}