1
0
mirror of https://github.com/esphome/esphome.git synced 2025-10-06 20:03:46 +01:00

Merge branch 'idf_query' into integration

This commit is contained in:
J. Nick Koston
2025-10-03 15:32:20 -05:00
2 changed files with 39 additions and 15 deletions

View File

@@ -190,8 +190,8 @@ esp_err_t AsyncWebServer::request_handler_(AsyncWebServerRequest *request) const
AsyncWebServerRequest::~AsyncWebServerRequest() {
delete this->rsp_;
for (const auto &pair : this->params_) {
delete pair.second; // NOLINT(cppcoreguidelines-owning-memory)
for (auto *param : this->params_) {
delete param; // NOLINT(cppcoreguidelines-owning-memory)
}
}
@@ -231,10 +231,23 @@ void AsyncWebServerRequest::redirect(const std::string &url) {
}
void AsyncWebServerRequest::init_response_(AsyncWebServerResponse *rsp, int code, const char *content_type) {
httpd_resp_set_status(*this, code == 200 ? HTTPD_200
: code == 404 ? HTTPD_404
: code == 409 ? HTTPD_409
: to_string(code).c_str());
// Set status code - use constants for common codes to avoid string allocation
const char *status;
switch (code) {
case 200:
status = HTTPD_200;
break;
case 404:
status = HTTPD_404;
break;
case 409:
status = HTTPD_409;
break;
default:
status = to_string(code).c_str();
break;
}
httpd_resp_set_status(*this, status);
if (content_type && *content_type) {
httpd_resp_set_type(*this, content_type);
@@ -291,11 +304,14 @@ void AsyncWebServerRequest::requestAuthentication(const char *realm) const {
#endif
AsyncWebParameter *AsyncWebServerRequest::getParam(const std::string &name) {
auto find = this->params_.find(name);
if (find != this->params_.end()) {
return find->second;
// Check cache first - only successful lookups are cached
for (auto *param : this->params_) {
if (param->name() == name) {
return param;
}
}
// Look up value from query strings
optional<std::string> val = query_key_value(this->post_query_, name);
if (!val.has_value()) {
auto url_query = request_get_url_query(*this);
@@ -304,11 +320,14 @@ AsyncWebParameter *AsyncWebServerRequest::getParam(const std::string &name) {
}
}
AsyncWebParameter *param = nullptr;
if (val.has_value()) {
param = new AsyncWebParameter(val.value()); // NOLINT(cppcoreguidelines-owning-memory)
// Don't cache misses to prevent memory exhaustion from malicious requests
// with thousands of non-existent parameter lookups
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;
}

View File

@@ -24,10 +24,12 @@ namespace web_server_idf {
class AsyncWebParameter {
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_; }
protected:
std::string name_;
std::string value_;
};
@@ -168,7 +170,10 @@ class AsyncWebServerRequest {
protected:
httpd_req_t *req_;
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 memory exhaustion attacks.
std::vector<AsyncWebParameter *> params_;
std::string post_query_;
AsyncWebServerRequest(httpd_req_t *req) : req_(req) {}
AsyncWebServerRequest(httpd_req_t *req, std::string post_query) : req_(req), post_query_(std::move(post_query)) {}