mirror of
https://github.com/esphome/esphome.git
synced 2026-02-18 15:35:59 -07:00
[web_server_idf] Replace heap-allocated url() with stack-based url_to() (#13407)
This commit is contained in:
@@ -96,10 +96,16 @@ void CaptivePortal::start() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void CaptivePortal::handleRequest(AsyncWebServerRequest *req) {
|
void CaptivePortal::handleRequest(AsyncWebServerRequest *req) {
|
||||||
if (req->url() == ESPHOME_F("/config.json")) {
|
#ifdef USE_ESP32
|
||||||
|
char url_buf[AsyncWebServerRequest::URL_BUF_SIZE];
|
||||||
|
StringRef url = req->url_to(url_buf);
|
||||||
|
#else
|
||||||
|
const auto &url = req->url();
|
||||||
|
#endif
|
||||||
|
if (url == ESPHOME_F("/config.json")) {
|
||||||
this->handle_config(req);
|
this->handle_config(req);
|
||||||
return;
|
return;
|
||||||
} else if (req->url() == ESPHOME_F("/wifisave")) {
|
} else if (url == ESPHOME_F("/wifisave")) {
|
||||||
this->handle_wifisave(req);
|
this->handle_wifisave(req);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -41,12 +41,14 @@ class PrometheusHandler : public AsyncWebHandler, public Component {
|
|||||||
void add_label_name(EntityBase *obj, const std::string &value) { relabel_map_name_.insert({obj, value}); }
|
void add_label_name(EntityBase *obj, const std::string &value) { relabel_map_name_.insert({obj, value}); }
|
||||||
|
|
||||||
bool canHandle(AsyncWebServerRequest *request) const override {
|
bool canHandle(AsyncWebServerRequest *request) const override {
|
||||||
if (request->method() == HTTP_GET) {
|
if (request->method() != HTTP_GET)
|
||||||
if (request->url() == "/metrics")
|
return false;
|
||||||
return true;
|
#ifdef USE_ESP32
|
||||||
}
|
char url_buf[AsyncWebServerRequest::URL_BUF_SIZE];
|
||||||
|
return request->url_to(url_buf) == "/metrics";
|
||||||
return false;
|
#else
|
||||||
|
return request->url() == ESPHOME_F("/metrics");
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
void handleRequest(AsyncWebServerRequest *req) override;
|
void handleRequest(AsyncWebServerRequest *req) override;
|
||||||
|
|||||||
@@ -32,8 +32,15 @@ class OTARequestHandler : public AsyncWebHandler {
|
|||||||
void handleUpload(AsyncWebServerRequest *request, const PlatformString &filename, size_t index, uint8_t *data,
|
void handleUpload(AsyncWebServerRequest *request, const PlatformString &filename, size_t index, uint8_t *data,
|
||||||
size_t len, bool final) override;
|
size_t len, bool final) override;
|
||||||
bool canHandle(AsyncWebServerRequest *request) const override {
|
bool canHandle(AsyncWebServerRequest *request) const override {
|
||||||
// Check if this is an OTA update request
|
if (request->method() != HTTP_POST)
|
||||||
bool is_ota_request = request->url() == "/update" && request->method() == HTTP_POST;
|
return false;
|
||||||
|
// Check if this is an OTA update request
|
||||||
|
#ifdef USE_ESP32
|
||||||
|
char url_buf[AsyncWebServerRequest::URL_BUF_SIZE];
|
||||||
|
bool is_ota_request = request->url_to(url_buf) == "/update";
|
||||||
|
#else
|
||||||
|
bool is_ota_request = request->url() == ESPHOME_F("/update");
|
||||||
|
#endif
|
||||||
|
|
||||||
#if defined(USE_WEBSERVER_OTA_DISABLED) && defined(USE_CAPTIVE_PORTAL)
|
#if defined(USE_WEBSERVER_OTA_DISABLED) && defined(USE_CAPTIVE_PORTAL)
|
||||||
// IMPORTANT: USE_WEBSERVER_OTA_DISABLED only disables OTA for the web_server component
|
// IMPORTANT: USE_WEBSERVER_OTA_DISABLED only disables OTA for the web_server component
|
||||||
|
|||||||
@@ -2187,7 +2187,12 @@ std::string WebServer::update_json_(update::UpdateEntity *obj, JsonDetail start_
|
|||||||
#endif
|
#endif
|
||||||
|
|
||||||
bool WebServer::canHandle(AsyncWebServerRequest *request) const {
|
bool WebServer::canHandle(AsyncWebServerRequest *request) const {
|
||||||
|
#ifdef USE_ESP32
|
||||||
|
char url_buf[AsyncWebServerRequest::URL_BUF_SIZE];
|
||||||
|
StringRef url = request->url_to(url_buf);
|
||||||
|
#else
|
||||||
const auto &url = request->url();
|
const auto &url = request->url();
|
||||||
|
#endif
|
||||||
const auto method = request->method();
|
const auto method = request->method();
|
||||||
|
|
||||||
// Static URL checks - use ESPHOME_F to keep strings in flash on ESP8266
|
// Static URL checks - use ESPHOME_F to keep strings in flash on ESP8266
|
||||||
@@ -2323,30 +2328,35 @@ bool WebServer::canHandle(AsyncWebServerRequest *request) const {
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
void WebServer::handleRequest(AsyncWebServerRequest *request) {
|
void WebServer::handleRequest(AsyncWebServerRequest *request) {
|
||||||
|
#ifdef USE_ESP32
|
||||||
|
char url_buf[AsyncWebServerRequest::URL_BUF_SIZE];
|
||||||
|
StringRef url = request->url_to(url_buf);
|
||||||
|
#else
|
||||||
const auto &url = request->url();
|
const auto &url = request->url();
|
||||||
|
#endif
|
||||||
|
|
||||||
// Handle static routes first
|
// Handle static routes first
|
||||||
if (url == "/") {
|
if (url == ESPHOME_F("/")) {
|
||||||
this->handle_index_request(request);
|
this->handle_index_request(request);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
#if !defined(USE_ESP32) && defined(USE_ARDUINO)
|
#if !defined(USE_ESP32) && defined(USE_ARDUINO)
|
||||||
if (url == "/events") {
|
if (url == ESPHOME_F("/events")) {
|
||||||
this->events_.add_new_client(this, request);
|
this->events_.add_new_client(this, request);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#ifdef USE_WEBSERVER_CSS_INCLUDE
|
#ifdef USE_WEBSERVER_CSS_INCLUDE
|
||||||
if (url == "/0.css") {
|
if (url == ESPHOME_F("/0.css")) {
|
||||||
this->handle_css_request(request);
|
this->handle_css_request(request);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#ifdef USE_WEBSERVER_JS_INCLUDE
|
#ifdef USE_WEBSERVER_JS_INCLUDE
|
||||||
if (url == "/0.js") {
|
if (url == ESPHOME_F("/0.js")) {
|
||||||
this->handle_js_request(request);
|
this->handle_js_request(request);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -246,21 +246,16 @@ optional<std::string> AsyncWebServerRequest::get_header(const char *name) const
|
|||||||
return request_get_header(*this, name);
|
return request_get_header(*this, name);
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string AsyncWebServerRequest::url() const {
|
StringRef AsyncWebServerRequest::url_to(std::span<char, URL_BUF_SIZE> buffer) const {
|
||||||
auto *query_start = strchr(this->req_->uri, '?');
|
const char *uri = this->req_->uri;
|
||||||
std::string result;
|
const char *query_start = strchr(uri, '?');
|
||||||
if (query_start == nullptr) {
|
size_t uri_len = query_start ? static_cast<size_t>(query_start - uri) : strlen(uri);
|
||||||
result = this->req_->uri;
|
size_t copy_len = std::min(uri_len, URL_BUF_SIZE - 1);
|
||||||
} else {
|
memcpy(buffer.data(), uri, copy_len);
|
||||||
result = std::string(this->req_->uri, query_start - this->req_->uri);
|
buffer[copy_len] = '\0';
|
||||||
}
|
|
||||||
// Decode URL-encoded characters in-place (e.g., %20 -> space)
|
// Decode URL-encoded characters in-place (e.g., %20 -> space)
|
||||||
// This matches AsyncWebServer behavior on Arduino
|
size_t decoded_len = url_decode(buffer.data());
|
||||||
if (!result.empty()) {
|
return StringRef(buffer.data(), decoded_len);
|
||||||
size_t new_len = url_decode(&result[0]);
|
|
||||||
result.resize(new_len);
|
|
||||||
}
|
|
||||||
return result;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string AsyncWebServerRequest::host() const { return this->get_header("Host").value(); }
|
std::string AsyncWebServerRequest::host() const { return this->get_header("Host").value(); }
|
||||||
|
|||||||
@@ -3,12 +3,14 @@
|
|||||||
|
|
||||||
#include "esphome/core/defines.h"
|
#include "esphome/core/defines.h"
|
||||||
#include "esphome/core/helpers.h"
|
#include "esphome/core/helpers.h"
|
||||||
|
#include "esphome/core/string_ref.h"
|
||||||
#include <esp_http_server.h>
|
#include <esp_http_server.h>
|
||||||
|
|
||||||
#include <atomic>
|
#include <atomic>
|
||||||
#include <functional>
|
#include <functional>
|
||||||
#include <list>
|
#include <list>
|
||||||
#include <map>
|
#include <map>
|
||||||
|
#include <span>
|
||||||
#include <string>
|
#include <string>
|
||||||
#include <utility>
|
#include <utility>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
@@ -110,7 +112,15 @@ class AsyncWebServerRequest {
|
|||||||
~AsyncWebServerRequest();
|
~AsyncWebServerRequest();
|
||||||
|
|
||||||
http_method method() const { return static_cast<http_method>(this->req_->method); }
|
http_method method() const { return static_cast<http_method>(this->req_->method); }
|
||||||
std::string url() const;
|
static constexpr size_t URL_BUF_SIZE = CONFIG_HTTPD_MAX_URI_LEN + 1; ///< Buffer size for url_to()
|
||||||
|
/// Write URL (without query string) to buffer, returns StringRef pointing to buffer.
|
||||||
|
/// URL is decoded (e.g., %20 -> space).
|
||||||
|
StringRef url_to(std::span<char, URL_BUF_SIZE> buffer) const;
|
||||||
|
/// Get URL as std::string. Prefer url_to() to avoid heap allocation.
|
||||||
|
std::string url() const {
|
||||||
|
char buffer[URL_BUF_SIZE];
|
||||||
|
return std::string(this->url_to(buffer));
|
||||||
|
}
|
||||||
std::string host() const;
|
std::string host() const;
|
||||||
// NOLINTNEXTLINE(readability-identifier-naming)
|
// NOLINTNEXTLINE(readability-identifier-naming)
|
||||||
size_t contentLength() const { return this->req_->content_len; }
|
size_t contentLength() const { return this->req_->content_len; }
|
||||||
@@ -306,7 +316,10 @@ class AsyncEventSource : public AsyncWebHandler {
|
|||||||
|
|
||||||
// NOLINTNEXTLINE(readability-identifier-naming)
|
// NOLINTNEXTLINE(readability-identifier-naming)
|
||||||
bool canHandle(AsyncWebServerRequest *request) const override {
|
bool canHandle(AsyncWebServerRequest *request) const override {
|
||||||
return request->method() == HTTP_GET && request->url() == this->url_;
|
if (request->method() != HTTP_GET)
|
||||||
|
return false;
|
||||||
|
char url_buf[AsyncWebServerRequest::URL_BUF_SIZE];
|
||||||
|
return request->url_to(url_buf) == this->url_;
|
||||||
}
|
}
|
||||||
// NOLINTNEXTLINE(readability-identifier-naming)
|
// NOLINTNEXTLINE(readability-identifier-naming)
|
||||||
void handleRequest(AsyncWebServerRequest *request) override;
|
void handleRequest(AsyncWebServerRequest *request) override;
|
||||||
|
|||||||
Reference in New Issue
Block a user