mirror of
https://github.com/esphome/esphome.git
synced 2026-09-20 03:28:41 +00:00
Merge branch 'web_server_use_arg_api' into integration
This commit is contained in:
@@ -1,17 +1,13 @@
|
||||
#ifdef USE_ESP32
|
||||
#include <memory>
|
||||
#include <cstring>
|
||||
#include <cctype>
|
||||
#include "esphome/core/helpers.h"
|
||||
#include "esphome/core/log.h"
|
||||
#include "http_parser.h"
|
||||
|
||||
#include "utils.h"
|
||||
|
||||
namespace esphome::web_server_idf {
|
||||
|
||||
static const char *const TAG = "web_server_idf_utils";
|
||||
|
||||
size_t url_decode(char *str) {
|
||||
char *start = str;
|
||||
char *ptr = str, buf;
|
||||
@@ -54,38 +50,29 @@ optional<std::string> request_get_header(httpd_req_t *req, const char *name) {
|
||||
return {str};
|
||||
}
|
||||
|
||||
optional<std::string> request_get_url_query(httpd_req_t *req) {
|
||||
auto len = httpd_req_get_url_query_len(req);
|
||||
if (len == 0) {
|
||||
return {};
|
||||
}
|
||||
|
||||
std::string str;
|
||||
str.resize(len);
|
||||
|
||||
auto res = httpd_req_get_url_query_str(req, &str[0], len + 1);
|
||||
if (res != ESP_OK) {
|
||||
ESP_LOGW(TAG, "Can't get query for request: %s", esp_err_to_name(res));
|
||||
return {};
|
||||
}
|
||||
|
||||
return {str};
|
||||
}
|
||||
|
||||
optional<std::string> query_key_value(const char *query_url, size_t query_len, const char *key) {
|
||||
if (query_url == nullptr || query_len == 0) {
|
||||
return {};
|
||||
}
|
||||
|
||||
// Use stack buffer for typical query strings, heap fallback for large ones
|
||||
SmallBufferWithHeapFallback<256, char> val(query_len);
|
||||
|
||||
if (httpd_query_key_value(query_url, key, val.get(), query_len) != ESP_OK) {
|
||||
char val[CONFIG_HTTPD_MAX_URI_LEN + 1];
|
||||
if (httpd_query_key_value(query_url, key, val, query_len) != ESP_OK) {
|
||||
return {};
|
||||
}
|
||||
|
||||
url_decode(val.get());
|
||||
return {val.get()};
|
||||
url_decode(val);
|
||||
return {val};
|
||||
}
|
||||
|
||||
bool query_has_key(const char *query_url, size_t query_len, const char *key) {
|
||||
if (query_url == nullptr || query_len == 0) {
|
||||
return false;
|
||||
}
|
||||
// Minimal buffer — we only care if the key exists, not the value
|
||||
char buf[1];
|
||||
// httpd_query_key_value returns ESP_OK if key found (even if buffer too small for value),
|
||||
// ESP_ERR_NOT_FOUND if key absent
|
||||
return httpd_query_key_value(query_url, key, buf, sizeof(buf)) != ESP_ERR_NOT_FOUND;
|
||||
}
|
||||
|
||||
// Helper function for case-insensitive string region comparison
|
||||
|
||||
@@ -13,11 +13,8 @@ size_t url_decode(char *str);
|
||||
|
||||
bool request_has_header(httpd_req_t *req, const char *name);
|
||||
optional<std::string> request_get_header(httpd_req_t *req, const char *name);
|
||||
optional<std::string> request_get_url_query(httpd_req_t *req);
|
||||
optional<std::string> query_key_value(const char *query_url, size_t query_len, const char *key);
|
||||
inline optional<std::string> query_key_value(const std::string &query_url, const std::string &key) {
|
||||
return query_key_value(query_url.c_str(), query_url.size(), key.c_str());
|
||||
}
|
||||
bool query_has_key(const char *query_url, size_t query_len, const char *key);
|
||||
|
||||
// Helper function for case-insensitive character comparison
|
||||
inline bool char_equals_ci(char a, char b) { return ::tolower(a) == ::tolower(b); }
|
||||
|
||||
@@ -393,13 +393,7 @@ AsyncWebParameter *AsyncWebServerRequest::getParam(const char *name) {
|
||||
}
|
||||
|
||||
// Look up value from query strings
|
||||
optional<std::string> val = query_key_value(this->post_query_.c_str(), this->post_query_.size(), name);
|
||||
if (!val.has_value()) {
|
||||
auto url_query = request_get_url_query(*this);
|
||||
if (url_query.has_value()) {
|
||||
val = query_key_value(url_query.value().c_str(), url_query.value().size(), name);
|
||||
}
|
||||
}
|
||||
auto val = this->find_query_value_(name);
|
||||
|
||||
// Don't cache misses to avoid wasting memory when handlers check for
|
||||
// optional parameters that don't exist in the request
|
||||
@@ -412,19 +406,37 @@ AsyncWebParameter *AsyncWebServerRequest::getParam(const char *name) {
|
||||
return param;
|
||||
}
|
||||
|
||||
optional<std::string> AsyncWebServerRequest::find_query_value_(const char *name) const {
|
||||
auto val = query_key_value(this->post_query_.c_str(), this->post_query_.size(), name);
|
||||
if (val.has_value()) {
|
||||
return val;
|
||||
/// Search post_query then URL query with a callback.
|
||||
/// Returns first truthy result, or value-initialized default.
|
||||
/// Uses stack buffer for URL query to avoid heap allocation.
|
||||
template<typename Func>
|
||||
static auto search_query_sources(httpd_req_t *req, const std::string &post_query, const char *name, Func func)
|
||||
-> decltype(func(nullptr, size_t{0}, name)) {
|
||||
if (!post_query.empty()) {
|
||||
auto result = func(post_query.c_str(), post_query.size(), name);
|
||||
if (result) {
|
||||
return result;
|
||||
}
|
||||
}
|
||||
auto url_query = request_get_url_query(*this);
|
||||
if (url_query.has_value()) {
|
||||
return query_key_value(url_query.value().c_str(), url_query.value().size(), name);
|
||||
auto len = httpd_req_get_url_query_len(req);
|
||||
if (len == 0) {
|
||||
return {};
|
||||
}
|
||||
return {};
|
||||
char buf[AsyncWebServerRequest::URL_BUF_SIZE];
|
||||
if (httpd_req_get_url_query_str(req, buf, len + 1) != ESP_OK) {
|
||||
return {};
|
||||
}
|
||||
return func(buf, len, name);
|
||||
}
|
||||
|
||||
bool AsyncWebServerRequest::hasArg(const char *name) { return this->find_query_value_(name).has_value(); }
|
||||
optional<std::string> AsyncWebServerRequest::find_query_value_(const char *name) const {
|
||||
return search_query_sources(this->req_, this->post_query_, name,
|
||||
[](const char *q, size_t len, const char *k) { return query_key_value(q, len, k); });
|
||||
}
|
||||
|
||||
bool AsyncWebServerRequest::hasArg(const char *name) {
|
||||
return search_query_sources(this->req_, this->post_query_, name, query_has_key);
|
||||
}
|
||||
|
||||
std::string AsyncWebServerRequest::arg(const char *name) {
|
||||
auto val = this->find_query_value_(name);
|
||||
|
||||
Reference in New Issue
Block a user