mirror of
https://github.com/esphome/esphome.git
synced 2025-07-28 14:16:40 +00:00
Refactor WebServer request handling for improved maintainability (#9470)
This commit is contained in:
parent
e231d334a3
commit
f8c45573f3
@ -1711,162 +1711,161 @@ std::string WebServer::update_json(update::UpdateEntity *obj, JsonDetail start_c
|
|||||||
#endif
|
#endif
|
||||||
|
|
||||||
bool WebServer::canHandle(AsyncWebServerRequest *request) const {
|
bool WebServer::canHandle(AsyncWebServerRequest *request) const {
|
||||||
if (request->url() == "/")
|
const auto &url = request->url();
|
||||||
|
const auto method = request->method();
|
||||||
|
|
||||||
|
// Simple URL checks
|
||||||
|
if (url == "/")
|
||||||
return true;
|
return true;
|
||||||
|
|
||||||
#ifdef USE_ARDUINO
|
#ifdef USE_ARDUINO
|
||||||
if (request->url() == "/events") {
|
if (url == "/events")
|
||||||
return true;
|
return true;
|
||||||
}
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#ifdef USE_WEBSERVER_CSS_INCLUDE
|
#ifdef USE_WEBSERVER_CSS_INCLUDE
|
||||||
if (request->url() == "/0.css")
|
if (url == "/0.css")
|
||||||
return true;
|
return true;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#ifdef USE_WEBSERVER_JS_INCLUDE
|
#ifdef USE_WEBSERVER_JS_INCLUDE
|
||||||
if (request->url() == "/0.js")
|
if (url == "/0.js")
|
||||||
return true;
|
return true;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#ifdef USE_WEBSERVER_PRIVATE_NETWORK_ACCESS
|
#ifdef USE_WEBSERVER_PRIVATE_NETWORK_ACCESS
|
||||||
if (request->method() == HTTP_OPTIONS && request->hasHeader(HEADER_CORS_REQ_PNA)) {
|
if (method == HTTP_OPTIONS && request->hasHeader(HEADER_CORS_REQ_PNA))
|
||||||
return true;
|
return true;
|
||||||
}
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
// Store the URL to prevent temporary string destruction
|
// Parse URL for component checks
|
||||||
// request->url() returns a reference to a String (on Arduino) or std::string (on ESP-IDF)
|
|
||||||
// UrlMatch stores pointers to the string's data, so we must ensure the string outlives match_url()
|
|
||||||
const auto &url = request->url();
|
|
||||||
UrlMatch match = match_url(url.c_str(), url.length(), true);
|
UrlMatch match = match_url(url.c_str(), url.length(), true);
|
||||||
if (!match.valid)
|
if (!match.valid)
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
|
// Common pattern check
|
||||||
|
bool is_get = method == HTTP_GET;
|
||||||
|
bool is_post = method == HTTP_POST;
|
||||||
|
bool is_get_or_post = is_get || is_post;
|
||||||
|
|
||||||
|
if (!is_get_or_post)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
// GET-only components
|
||||||
|
if (is_get) {
|
||||||
#ifdef USE_SENSOR
|
#ifdef USE_SENSOR
|
||||||
if (request->method() == HTTP_GET && match.domain_equals("sensor"))
|
if (match.domain_equals("sensor"))
|
||||||
return true;
|
return true;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#ifdef USE_SWITCH
|
|
||||||
if ((request->method() == HTTP_POST || request->method() == HTTP_GET) && match.domain_equals("switch"))
|
|
||||||
return true;
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#ifdef USE_BUTTON
|
|
||||||
if ((request->method() == HTTP_POST || request->method() == HTTP_GET) && match.domain_equals("button"))
|
|
||||||
return true;
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#ifdef USE_BINARY_SENSOR
|
#ifdef USE_BINARY_SENSOR
|
||||||
if (request->method() == HTTP_GET && match.domain_equals("binary_sensor"))
|
if (match.domain_equals("binary_sensor"))
|
||||||
return true;
|
return true;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#ifdef USE_FAN
|
|
||||||
if ((request->method() == HTTP_POST || request->method() == HTTP_GET) && match.domain_equals("fan"))
|
|
||||||
return true;
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#ifdef USE_LIGHT
|
|
||||||
if ((request->method() == HTTP_POST || request->method() == HTTP_GET) && match.domain_equals("light"))
|
|
||||||
return true;
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#ifdef USE_TEXT_SENSOR
|
#ifdef USE_TEXT_SENSOR
|
||||||
if (request->method() == HTTP_GET && match.domain_equals("text_sensor"))
|
if (match.domain_equals("text_sensor"))
|
||||||
return true;
|
return true;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#ifdef USE_COVER
|
|
||||||
if ((request->method() == HTTP_POST || request->method() == HTTP_GET) && match.domain_equals("cover"))
|
|
||||||
return true;
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#ifdef USE_NUMBER
|
|
||||||
if ((request->method() == HTTP_POST || request->method() == HTTP_GET) && match.domain_equals("number"))
|
|
||||||
return true;
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#ifdef USE_DATETIME_DATE
|
|
||||||
if ((request->method() == HTTP_POST || request->method() == HTTP_GET) && match.domain_equals("date"))
|
|
||||||
return true;
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#ifdef USE_DATETIME_TIME
|
|
||||||
if ((request->method() == HTTP_POST || request->method() == HTTP_GET) && match.domain_equals("time"))
|
|
||||||
return true;
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#ifdef USE_DATETIME_DATETIME
|
|
||||||
if ((request->method() == HTTP_POST || request->method() == HTTP_GET) && match.domain_equals("datetime"))
|
|
||||||
return true;
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#ifdef USE_TEXT
|
|
||||||
if ((request->method() == HTTP_POST || request->method() == HTTP_GET) && match.domain_equals("text"))
|
|
||||||
return true;
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#ifdef USE_SELECT
|
|
||||||
if ((request->method() == HTTP_POST || request->method() == HTTP_GET) && match.domain_equals("select"))
|
|
||||||
return true;
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#ifdef USE_CLIMATE
|
|
||||||
if ((request->method() == HTTP_POST || request->method() == HTTP_GET) && match.domain_equals("climate"))
|
|
||||||
return true;
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#ifdef USE_LOCK
|
|
||||||
if ((request->method() == HTTP_POST || request->method() == HTTP_GET) && match.domain_equals("lock"))
|
|
||||||
return true;
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#ifdef USE_VALVE
|
|
||||||
if ((request->method() == HTTP_POST || request->method() == HTTP_GET) && match.domain_equals("valve"))
|
|
||||||
return true;
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#ifdef USE_ALARM_CONTROL_PANEL
|
|
||||||
if ((request->method() == HTTP_GET || request->method() == HTTP_POST) && match.domain_equals("alarm_control_panel"))
|
|
||||||
return true;
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#ifdef USE_EVENT
|
#ifdef USE_EVENT
|
||||||
if (request->method() == HTTP_GET && match.domain_equals("event"))
|
if (match.domain_equals("event"))
|
||||||
return true;
|
return true;
|
||||||
#endif
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
#ifdef USE_UPDATE
|
// GET+POST components
|
||||||
if ((request->method() == HTTP_POST || request->method() == HTTP_GET) && match.domain_equals("update"))
|
if (is_get_or_post) {
|
||||||
return true;
|
#ifdef USE_SWITCH
|
||||||
|
if (match.domain_equals("switch"))
|
||||||
|
return true;
|
||||||
#endif
|
#endif
|
||||||
|
#ifdef USE_BUTTON
|
||||||
|
if (match.domain_equals("button"))
|
||||||
|
return true;
|
||||||
|
#endif
|
||||||
|
#ifdef USE_FAN
|
||||||
|
if (match.domain_equals("fan"))
|
||||||
|
return true;
|
||||||
|
#endif
|
||||||
|
#ifdef USE_LIGHT
|
||||||
|
if (match.domain_equals("light"))
|
||||||
|
return true;
|
||||||
|
#endif
|
||||||
|
#ifdef USE_COVER
|
||||||
|
if (match.domain_equals("cover"))
|
||||||
|
return true;
|
||||||
|
#endif
|
||||||
|
#ifdef USE_NUMBER
|
||||||
|
if (match.domain_equals("number"))
|
||||||
|
return true;
|
||||||
|
#endif
|
||||||
|
#ifdef USE_DATETIME_DATE
|
||||||
|
if (match.domain_equals("date"))
|
||||||
|
return true;
|
||||||
|
#endif
|
||||||
|
#ifdef USE_DATETIME_TIME
|
||||||
|
if (match.domain_equals("time"))
|
||||||
|
return true;
|
||||||
|
#endif
|
||||||
|
#ifdef USE_DATETIME_DATETIME
|
||||||
|
if (match.domain_equals("datetime"))
|
||||||
|
return true;
|
||||||
|
#endif
|
||||||
|
#ifdef USE_TEXT
|
||||||
|
if (match.domain_equals("text"))
|
||||||
|
return true;
|
||||||
|
#endif
|
||||||
|
#ifdef USE_SELECT
|
||||||
|
if (match.domain_equals("select"))
|
||||||
|
return true;
|
||||||
|
#endif
|
||||||
|
#ifdef USE_CLIMATE
|
||||||
|
if (match.domain_equals("climate"))
|
||||||
|
return true;
|
||||||
|
#endif
|
||||||
|
#ifdef USE_LOCK
|
||||||
|
if (match.domain_equals("lock"))
|
||||||
|
return true;
|
||||||
|
#endif
|
||||||
|
#ifdef USE_VALVE
|
||||||
|
if (match.domain_equals("valve"))
|
||||||
|
return true;
|
||||||
|
#endif
|
||||||
|
#ifdef USE_ALARM_CONTROL_PANEL
|
||||||
|
if (match.domain_equals("alarm_control_panel"))
|
||||||
|
return true;
|
||||||
|
#endif
|
||||||
|
#ifdef USE_UPDATE
|
||||||
|
if (match.domain_equals("update"))
|
||||||
|
return true;
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
void WebServer::handleRequest(AsyncWebServerRequest *request) {
|
void WebServer::handleRequest(AsyncWebServerRequest *request) {
|
||||||
if (request->url() == "/") {
|
const auto &url = request->url();
|
||||||
|
|
||||||
|
// Handle static routes first
|
||||||
|
if (url == "/") {
|
||||||
this->handle_index_request(request);
|
this->handle_index_request(request);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifdef USE_ARDUINO
|
#ifdef USE_ARDUINO
|
||||||
if (request->url() == "/events") {
|
if (url == "/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 (request->url() == "/0.css") {
|
if (url == "/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 (request->url() == "/0.js") {
|
if (url == "/0.js") {
|
||||||
this->handle_js_request(request);
|
this->handle_js_request(request);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@ -1879,147 +1878,85 @@ void WebServer::handleRequest(AsyncWebServerRequest *request) {
|
|||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
// See comment in canHandle() for why we store the URL reference
|
// Parse URL for component routing
|
||||||
const auto &url = request->url();
|
|
||||||
UrlMatch match = match_url(url.c_str(), url.length(), false);
|
UrlMatch match = match_url(url.c_str(), url.length(), false);
|
||||||
|
|
||||||
|
// Component routing using minimal code repetition
|
||||||
|
struct ComponentRoute {
|
||||||
|
const char *domain;
|
||||||
|
void (WebServer::*handler)(AsyncWebServerRequest *, const UrlMatch &);
|
||||||
|
};
|
||||||
|
|
||||||
|
static const ComponentRoute routes[] = {
|
||||||
#ifdef USE_SENSOR
|
#ifdef USE_SENSOR
|
||||||
if (match.domain_equals("sensor")) {
|
{"sensor", &WebServer::handle_sensor_request},
|
||||||
this->handle_sensor_request(request, match);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#ifdef USE_SWITCH
|
#ifdef USE_SWITCH
|
||||||
if (match.domain_equals("switch")) {
|
{"switch", &WebServer::handle_switch_request},
|
||||||
this->handle_switch_request(request, match);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#ifdef USE_BUTTON
|
#ifdef USE_BUTTON
|
||||||
if (match.domain_equals("button")) {
|
{"button", &WebServer::handle_button_request},
|
||||||
this->handle_button_request(request, match);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#ifdef USE_BINARY_SENSOR
|
#ifdef USE_BINARY_SENSOR
|
||||||
if (match.domain_equals("binary_sensor")) {
|
{"binary_sensor", &WebServer::handle_binary_sensor_request},
|
||||||
this->handle_binary_sensor_request(request, match);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#ifdef USE_FAN
|
#ifdef USE_FAN
|
||||||
if (match.domain_equals("fan")) {
|
{"fan", &WebServer::handle_fan_request},
|
||||||
this->handle_fan_request(request, match);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#ifdef USE_LIGHT
|
#ifdef USE_LIGHT
|
||||||
if (match.domain_equals("light")) {
|
{"light", &WebServer::handle_light_request},
|
||||||
this->handle_light_request(request, match);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#ifdef USE_TEXT_SENSOR
|
#ifdef USE_TEXT_SENSOR
|
||||||
if (match.domain_equals("text_sensor")) {
|
{"text_sensor", &WebServer::handle_text_sensor_request},
|
||||||
this->handle_text_sensor_request(request, match);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#ifdef USE_COVER
|
#ifdef USE_COVER
|
||||||
if (match.domain_equals("cover")) {
|
{"cover", &WebServer::handle_cover_request},
|
||||||
this->handle_cover_request(request, match);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#ifdef USE_NUMBER
|
#ifdef USE_NUMBER
|
||||||
if (match.domain_equals("number")) {
|
{"number", &WebServer::handle_number_request},
|
||||||
this->handle_number_request(request, match);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#ifdef USE_DATETIME_DATE
|
#ifdef USE_DATETIME_DATE
|
||||||
if (match.domain_equals("date")) {
|
{"date", &WebServer::handle_date_request},
|
||||||
this->handle_date_request(request, match);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#ifdef USE_DATETIME_TIME
|
#ifdef USE_DATETIME_TIME
|
||||||
if (match.domain_equals("time")) {
|
{"time", &WebServer::handle_time_request},
|
||||||
this->handle_time_request(request, match);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#ifdef USE_DATETIME_DATETIME
|
#ifdef USE_DATETIME_DATETIME
|
||||||
if (match.domain_equals("datetime")) {
|
{"datetime", &WebServer::handle_datetime_request},
|
||||||
this->handle_datetime_request(request, match);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#ifdef USE_TEXT
|
#ifdef USE_TEXT
|
||||||
if (match.domain_equals("text")) {
|
{"text", &WebServer::handle_text_request},
|
||||||
this->handle_text_request(request, match);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#ifdef USE_SELECT
|
#ifdef USE_SELECT
|
||||||
if (match.domain_equals("select")) {
|
{"select", &WebServer::handle_select_request},
|
||||||
this->handle_select_request(request, match);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#ifdef USE_CLIMATE
|
#ifdef USE_CLIMATE
|
||||||
if (match.domain_equals("climate")) {
|
{"climate", &WebServer::handle_climate_request},
|
||||||
this->handle_climate_request(request, match);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#ifdef USE_LOCK
|
#ifdef USE_LOCK
|
||||||
if (match.domain_equals("lock")) {
|
{"lock", &WebServer::handle_lock_request},
|
||||||
this->handle_lock_request(request, match);
|
|
||||||
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#ifdef USE_VALVE
|
#ifdef USE_VALVE
|
||||||
if (match.domain_equals("valve")) {
|
{"valve", &WebServer::handle_valve_request},
|
||||||
this->handle_valve_request(request, match);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#ifdef USE_ALARM_CONTROL_PANEL
|
#ifdef USE_ALARM_CONTROL_PANEL
|
||||||
if (match.domain_equals("alarm_control_panel")) {
|
{"alarm_control_panel", &WebServer::handle_alarm_control_panel_request},
|
||||||
this->handle_alarm_control_panel_request(request, match);
|
|
||||||
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#ifdef USE_UPDATE
|
#ifdef USE_UPDATE
|
||||||
if (match.domain_equals("update")) {
|
{"update", &WebServer::handle_update_request},
|
||||||
this->handle_update_request(request, match);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
#endif
|
#endif
|
||||||
|
};
|
||||||
|
|
||||||
|
// Check each route
|
||||||
|
for (const auto &route : routes) {
|
||||||
|
if (match.domain_equals(route.domain)) {
|
||||||
|
(this->*route.handler)(request, match);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// No matching handler found - send 404
|
// No matching handler found - send 404
|
||||||
ESP_LOGV(TAG, "Request for unknown URL: %s", request->url().c_str());
|
ESP_LOGV(TAG, "Request for unknown URL: %s", url.c_str());
|
||||||
request->send(404, "text/plain", "Not Found");
|
request->send(404, "text/plain", "Not Found");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user