mirror of
https://github.com/esphome/esphome.git
synced 2025-07-29 14:46:40 +00:00
Optimize web_server UrlMatch to avoid heap allocations (#9263)
This commit is contained in:
parent
140ca070a2
commit
9890659f61
@ -49,26 +49,69 @@ static const char *const HEADER_CORS_ALLOW_PNA = "Access-Control-Allow-Private-N
|
||||
UrlMatch match_url(const std::string &url, bool only_domain = false) {
|
||||
UrlMatch match;
|
||||
match.valid = false;
|
||||
size_t domain_end = url.find('/', 1);
|
||||
if (domain_end == std::string::npos)
|
||||
match.domain = nullptr;
|
||||
match.id = nullptr;
|
||||
match.method = nullptr;
|
||||
match.domain_len = 0;
|
||||
match.id_len = 0;
|
||||
match.method_len = 0;
|
||||
|
||||
const char *url_ptr = url.c_str();
|
||||
size_t url_len = url.length();
|
||||
|
||||
// URL must start with '/'
|
||||
if (url_len < 2 || url_ptr[0] != '/')
|
||||
return match;
|
||||
match.domain = url.substr(1, domain_end - 1);
|
||||
|
||||
// Find domain
|
||||
size_t domain_start = 1;
|
||||
size_t domain_end = url.find('/', domain_start);
|
||||
|
||||
if (domain_end == std::string::npos) {
|
||||
// URL is just "/domain"
|
||||
match.domain = url_ptr + domain_start;
|
||||
match.domain_len = url_len - domain_start;
|
||||
match.valid = true;
|
||||
return match;
|
||||
}
|
||||
|
||||
// Set domain
|
||||
match.domain = url_ptr + domain_start;
|
||||
match.domain_len = domain_end - domain_start;
|
||||
|
||||
if (only_domain) {
|
||||
match.valid = true;
|
||||
return match;
|
||||
}
|
||||
if (url.length() == domain_end - 1)
|
||||
|
||||
// Check if there's anything after domain
|
||||
if (url_len == domain_end + 1)
|
||||
return match;
|
||||
|
||||
// Find ID
|
||||
size_t id_begin = domain_end + 1;
|
||||
size_t id_end = url.find('/', id_begin);
|
||||
|
||||
match.valid = true;
|
||||
|
||||
if (id_end == std::string::npos) {
|
||||
match.id = url.substr(id_begin, url.length() - id_begin);
|
||||
// URL is "/domain/id" with no method
|
||||
match.id = url_ptr + id_begin;
|
||||
match.id_len = url_len - id_begin;
|
||||
return match;
|
||||
}
|
||||
match.id = url.substr(id_begin, id_end - id_begin);
|
||||
|
||||
// Set ID
|
||||
match.id = url_ptr + id_begin;
|
||||
match.id_len = id_end - id_begin;
|
||||
|
||||
// Set method if present
|
||||
size_t method_begin = id_end + 1;
|
||||
match.method = url.substr(method_begin, url.length() - method_begin);
|
||||
if (method_begin < url_len) {
|
||||
match.method = url_ptr + method_begin;
|
||||
match.method_len = url_len - method_begin;
|
||||
}
|
||||
|
||||
return match;
|
||||
}
|
||||
|
||||
@ -386,9 +429,9 @@ void WebServer::on_sensor_update(sensor::Sensor *obj, float state) {
|
||||
}
|
||||
void WebServer::handle_sensor_request(AsyncWebServerRequest *request, const UrlMatch &match) {
|
||||
for (sensor::Sensor *obj : App.get_sensors()) {
|
||||
if (obj->get_object_id() != match.id)
|
||||
if (!match.id_equals(obj->get_object_id()))
|
||||
continue;
|
||||
if (request->method() == HTTP_GET && match.method.empty()) {
|
||||
if (request->method() == HTTP_GET && match.method_empty()) {
|
||||
auto detail = get_request_detail(request);
|
||||
std::string data = this->sensor_json(obj, obj->state, detail);
|
||||
request->send(200, "application/json", data.c_str());
|
||||
@ -431,9 +474,9 @@ void WebServer::on_text_sensor_update(text_sensor::TextSensor *obj, const std::s
|
||||
}
|
||||
void WebServer::handle_text_sensor_request(AsyncWebServerRequest *request, const UrlMatch &match) {
|
||||
for (text_sensor::TextSensor *obj : App.get_text_sensors()) {
|
||||
if (obj->get_object_id() != match.id)
|
||||
if (!match.id_equals(obj->get_object_id()))
|
||||
continue;
|
||||
if (request->method() == HTTP_GET && match.method.empty()) {
|
||||
if (request->method() == HTTP_GET && match.method_empty()) {
|
||||
auto detail = get_request_detail(request);
|
||||
std::string data = this->text_sensor_json(obj, obj->state, detail);
|
||||
request->send(200, "application/json", data.c_str());
|
||||
@ -469,20 +512,20 @@ void WebServer::on_switch_update(switch_::Switch *obj, bool state) {
|
||||
}
|
||||
void WebServer::handle_switch_request(AsyncWebServerRequest *request, const UrlMatch &match) {
|
||||
for (switch_::Switch *obj : App.get_switches()) {
|
||||
if (obj->get_object_id() != match.id)
|
||||
if (!match.id_equals(obj->get_object_id()))
|
||||
continue;
|
||||
|
||||
if (request->method() == HTTP_GET && match.method.empty()) {
|
||||
if (request->method() == HTTP_GET && match.method_empty()) {
|
||||
auto detail = get_request_detail(request);
|
||||
std::string data = this->switch_json(obj, obj->state, detail);
|
||||
request->send(200, "application/json", data.c_str());
|
||||
} else if (match.method == "toggle") {
|
||||
} else if (match.method_equals("toggle")) {
|
||||
this->schedule_([obj]() { obj->toggle(); });
|
||||
request->send(200);
|
||||
} else if (match.method == "turn_on") {
|
||||
} else if (match.method_equals("turn_on")) {
|
||||
this->schedule_([obj]() { obj->turn_on(); });
|
||||
request->send(200);
|
||||
} else if (match.method == "turn_off") {
|
||||
} else if (match.method_equals("turn_off")) {
|
||||
this->schedule_([obj]() { obj->turn_off(); });
|
||||
request->send(200);
|
||||
} else {
|
||||
@ -512,13 +555,13 @@ std::string WebServer::switch_json(switch_::Switch *obj, bool value, JsonDetail
|
||||
#ifdef USE_BUTTON
|
||||
void WebServer::handle_button_request(AsyncWebServerRequest *request, const UrlMatch &match) {
|
||||
for (button::Button *obj : App.get_buttons()) {
|
||||
if (obj->get_object_id() != match.id)
|
||||
if (!match.id_equals(obj->get_object_id()))
|
||||
continue;
|
||||
if (request->method() == HTTP_GET && match.method.empty()) {
|
||||
if (request->method() == HTTP_GET && match.method_empty()) {
|
||||
auto detail = get_request_detail(request);
|
||||
std::string data = this->button_json(obj, detail);
|
||||
request->send(200, "application/json", data.c_str());
|
||||
} else if (match.method == "press") {
|
||||
} else if (match.method_equals("press")) {
|
||||
this->schedule_([obj]() { obj->press(); });
|
||||
request->send(200);
|
||||
return;
|
||||
@ -553,9 +596,9 @@ void WebServer::on_binary_sensor_update(binary_sensor::BinarySensor *obj) {
|
||||
}
|
||||
void WebServer::handle_binary_sensor_request(AsyncWebServerRequest *request, const UrlMatch &match) {
|
||||
for (binary_sensor::BinarySensor *obj : App.get_binary_sensors()) {
|
||||
if (obj->get_object_id() != match.id)
|
||||
if (!match.id_equals(obj->get_object_id()))
|
||||
continue;
|
||||
if (request->method() == HTTP_GET && match.method.empty()) {
|
||||
if (request->method() == HTTP_GET && match.method_empty()) {
|
||||
auto detail = get_request_detail(request);
|
||||
std::string data = this->binary_sensor_json(obj, obj->state, detail);
|
||||
request->send(200, "application/json", data.c_str());
|
||||
@ -591,18 +634,18 @@ void WebServer::on_fan_update(fan::Fan *obj) {
|
||||
}
|
||||
void WebServer::handle_fan_request(AsyncWebServerRequest *request, const UrlMatch &match) {
|
||||
for (fan::Fan *obj : App.get_fans()) {
|
||||
if (obj->get_object_id() != match.id)
|
||||
if (!match.id_equals(obj->get_object_id()))
|
||||
continue;
|
||||
|
||||
if (request->method() == HTTP_GET && match.method.empty()) {
|
||||
if (request->method() == HTTP_GET && match.method_empty()) {
|
||||
auto detail = get_request_detail(request);
|
||||
std::string data = this->fan_json(obj, detail);
|
||||
request->send(200, "application/json", data.c_str());
|
||||
} else if (match.method == "toggle") {
|
||||
} else if (match.method_equals("toggle")) {
|
||||
this->schedule_([obj]() { obj->toggle().perform(); });
|
||||
request->send(200);
|
||||
} else if (match.method == "turn_on" || match.method == "turn_off") {
|
||||
auto call = match.method == "turn_on" ? obj->turn_on() : obj->turn_off();
|
||||
} else if (match.method_equals("turn_on") || match.method_equals("turn_off")) {
|
||||
auto call = match.method_equals("turn_on") ? obj->turn_on() : obj->turn_off();
|
||||
|
||||
if (request->hasParam("speed_level")) {
|
||||
auto speed_level = request->getParam("speed_level")->value();
|
||||
@ -672,17 +715,17 @@ void WebServer::on_light_update(light::LightState *obj) {
|
||||
}
|
||||
void WebServer::handle_light_request(AsyncWebServerRequest *request, const UrlMatch &match) {
|
||||
for (light::LightState *obj : App.get_lights()) {
|
||||
if (obj->get_object_id() != match.id)
|
||||
if (!match.id_equals(obj->get_object_id()))
|
||||
continue;
|
||||
|
||||
if (request->method() == HTTP_GET && match.method.empty()) {
|
||||
if (request->method() == HTTP_GET && match.method_empty()) {
|
||||
auto detail = get_request_detail(request);
|
||||
std::string data = this->light_json(obj, detail);
|
||||
request->send(200, "application/json", data.c_str());
|
||||
} else if (match.method == "toggle") {
|
||||
} else if (match.method_equals("toggle")) {
|
||||
this->schedule_([obj]() { obj->toggle().perform(); });
|
||||
request->send(200);
|
||||
} else if (match.method == "turn_on") {
|
||||
} else if (match.method_equals("turn_on")) {
|
||||
auto call = obj->turn_on();
|
||||
if (request->hasParam("brightness")) {
|
||||
auto brightness = parse_number<float>(request->getParam("brightness")->value().c_str());
|
||||
@ -739,7 +782,7 @@ void WebServer::handle_light_request(AsyncWebServerRequest *request, const UrlMa
|
||||
|
||||
this->schedule_([call]() mutable { call.perform(); });
|
||||
request->send(200);
|
||||
} else if (match.method == "turn_off") {
|
||||
} else if (match.method_equals("turn_off")) {
|
||||
auto call = obj->turn_off();
|
||||
if (request->hasParam("transition")) {
|
||||
auto transition = parse_number<uint32_t>(request->getParam("transition")->value().c_str());
|
||||
@ -788,10 +831,10 @@ void WebServer::on_cover_update(cover::Cover *obj) {
|
||||
}
|
||||
void WebServer::handle_cover_request(AsyncWebServerRequest *request, const UrlMatch &match) {
|
||||
for (cover::Cover *obj : App.get_covers()) {
|
||||
if (obj->get_object_id() != match.id)
|
||||
if (!match.id_equals(obj->get_object_id()))
|
||||
continue;
|
||||
|
||||
if (request->method() == HTTP_GET && match.method.empty()) {
|
||||
if (request->method() == HTTP_GET && match.method_empty()) {
|
||||
auto detail = get_request_detail(request);
|
||||
std::string data = this->cover_json(obj, detail);
|
||||
request->send(200, "application/json", data.c_str());
|
||||
@ -799,15 +842,15 @@ void WebServer::handle_cover_request(AsyncWebServerRequest *request, const UrlMa
|
||||
}
|
||||
|
||||
auto call = obj->make_call();
|
||||
if (match.method == "open") {
|
||||
if (match.method_equals("open")) {
|
||||
call.set_command_open();
|
||||
} else if (match.method == "close") {
|
||||
} else if (match.method_equals("close")) {
|
||||
call.set_command_close();
|
||||
} else if (match.method == "stop") {
|
||||
} else if (match.method_equals("stop")) {
|
||||
call.set_command_stop();
|
||||
} else if (match.method == "toggle") {
|
||||
} else if (match.method_equals("toggle")) {
|
||||
call.set_command_toggle();
|
||||
} else if (match.method != "set") {
|
||||
} else if (!match.method_equals("set")) {
|
||||
request->send(404);
|
||||
return;
|
||||
}
|
||||
@ -869,16 +912,16 @@ void WebServer::on_number_update(number::Number *obj, float state) {
|
||||
}
|
||||
void WebServer::handle_number_request(AsyncWebServerRequest *request, const UrlMatch &match) {
|
||||
for (auto *obj : App.get_numbers()) {
|
||||
if (obj->get_object_id() != match.id)
|
||||
if (!match.id_equals(obj->get_object_id()))
|
||||
continue;
|
||||
|
||||
if (request->method() == HTTP_GET && match.method.empty()) {
|
||||
if (request->method() == HTTP_GET && match.method_empty()) {
|
||||
auto detail = get_request_detail(request);
|
||||
std::string data = this->number_json(obj, obj->state, detail);
|
||||
request->send(200, "application/json", data.c_str());
|
||||
return;
|
||||
}
|
||||
if (match.method != "set") {
|
||||
if (!match.method_equals("set")) {
|
||||
request->send(404);
|
||||
return;
|
||||
}
|
||||
@ -940,15 +983,15 @@ void WebServer::on_date_update(datetime::DateEntity *obj) {
|
||||
}
|
||||
void WebServer::handle_date_request(AsyncWebServerRequest *request, const UrlMatch &match) {
|
||||
for (auto *obj : App.get_dates()) {
|
||||
if (obj->get_object_id() != match.id)
|
||||
if (!match.id_equals(obj->get_object_id()))
|
||||
continue;
|
||||
if (request->method() == HTTP_GET && match.method.empty()) {
|
||||
if (request->method() == HTTP_GET && match.method_empty()) {
|
||||
auto detail = get_request_detail(request);
|
||||
std::string data = this->date_json(obj, detail);
|
||||
request->send(200, "application/json", data.c_str());
|
||||
return;
|
||||
}
|
||||
if (match.method != "set") {
|
||||
if (!match.method_equals("set")) {
|
||||
request->send(404);
|
||||
return;
|
||||
}
|
||||
@ -999,15 +1042,15 @@ void WebServer::on_time_update(datetime::TimeEntity *obj) {
|
||||
}
|
||||
void WebServer::handle_time_request(AsyncWebServerRequest *request, const UrlMatch &match) {
|
||||
for (auto *obj : App.get_times()) {
|
||||
if (obj->get_object_id() != match.id)
|
||||
if (!match.id_equals(obj->get_object_id()))
|
||||
continue;
|
||||
if (request->method() == HTTP_GET && match.method.empty()) {
|
||||
if (request->method() == HTTP_GET && match.method_empty()) {
|
||||
auto detail = get_request_detail(request);
|
||||
std::string data = this->time_json(obj, detail);
|
||||
request->send(200, "application/json", data.c_str());
|
||||
return;
|
||||
}
|
||||
if (match.method != "set") {
|
||||
if (!match.method_equals("set")) {
|
||||
request->send(404);
|
||||
return;
|
||||
}
|
||||
@ -1057,15 +1100,15 @@ void WebServer::on_datetime_update(datetime::DateTimeEntity *obj) {
|
||||
}
|
||||
void WebServer::handle_datetime_request(AsyncWebServerRequest *request, const UrlMatch &match) {
|
||||
for (auto *obj : App.get_datetimes()) {
|
||||
if (obj->get_object_id() != match.id)
|
||||
if (!match.id_equals(obj->get_object_id()))
|
||||
continue;
|
||||
if (request->method() == HTTP_GET && match.method.empty()) {
|
||||
if (request->method() == HTTP_GET && match.method_empty()) {
|
||||
auto detail = get_request_detail(request);
|
||||
std::string data = this->datetime_json(obj, detail);
|
||||
request->send(200, "application/json", data.c_str());
|
||||
return;
|
||||
}
|
||||
if (match.method != "set") {
|
||||
if (!match.method_equals("set")) {
|
||||
request->send(404);
|
||||
return;
|
||||
}
|
||||
@ -1116,16 +1159,16 @@ void WebServer::on_text_update(text::Text *obj, const std::string &state) {
|
||||
}
|
||||
void WebServer::handle_text_request(AsyncWebServerRequest *request, const UrlMatch &match) {
|
||||
for (auto *obj : App.get_texts()) {
|
||||
if (obj->get_object_id() != match.id)
|
||||
if (!match.id_equals(obj->get_object_id()))
|
||||
continue;
|
||||
|
||||
if (request->method() == HTTP_GET && match.method.empty()) {
|
||||
if (request->method() == HTTP_GET && match.method_empty()) {
|
||||
auto detail = get_request_detail(request);
|
||||
std::string data = this->text_json(obj, obj->state, detail);
|
||||
request->send(200, "application/json", data.c_str());
|
||||
return;
|
||||
}
|
||||
if (match.method != "set") {
|
||||
if (!match.method_equals("set")) {
|
||||
request->send(404);
|
||||
return;
|
||||
}
|
||||
@ -1177,17 +1220,17 @@ void WebServer::on_select_update(select::Select *obj, const std::string &state,
|
||||
}
|
||||
void WebServer::handle_select_request(AsyncWebServerRequest *request, const UrlMatch &match) {
|
||||
for (auto *obj : App.get_selects()) {
|
||||
if (obj->get_object_id() != match.id)
|
||||
if (!match.id_equals(obj->get_object_id()))
|
||||
continue;
|
||||
|
||||
if (request->method() == HTTP_GET && match.method.empty()) {
|
||||
if (request->method() == HTTP_GET && match.method_empty()) {
|
||||
auto detail = get_request_detail(request);
|
||||
std::string data = this->select_json(obj, obj->state, detail);
|
||||
request->send(200, "application/json", data.c_str());
|
||||
return;
|
||||
}
|
||||
|
||||
if (match.method != "set") {
|
||||
if (!match.method_equals("set")) {
|
||||
request->send(404);
|
||||
return;
|
||||
}
|
||||
@ -1236,17 +1279,17 @@ void WebServer::on_climate_update(climate::Climate *obj) {
|
||||
}
|
||||
void WebServer::handle_climate_request(AsyncWebServerRequest *request, const UrlMatch &match) {
|
||||
for (auto *obj : App.get_climates()) {
|
||||
if (obj->get_object_id() != match.id)
|
||||
if (!match.id_equals(obj->get_object_id()))
|
||||
continue;
|
||||
|
||||
if (request->method() == HTTP_GET && match.method.empty()) {
|
||||
if (request->method() == HTTP_GET && match.method_empty()) {
|
||||
auto detail = get_request_detail(request);
|
||||
std::string data = this->climate_json(obj, detail);
|
||||
request->send(200, "application/json", data.c_str());
|
||||
return;
|
||||
}
|
||||
|
||||
if (match.method != "set") {
|
||||
if (!match.method_equals("set")) {
|
||||
request->send(404);
|
||||
return;
|
||||
}
|
||||
@ -1395,20 +1438,20 @@ void WebServer::on_lock_update(lock::Lock *obj) {
|
||||
}
|
||||
void WebServer::handle_lock_request(AsyncWebServerRequest *request, const UrlMatch &match) {
|
||||
for (lock::Lock *obj : App.get_locks()) {
|
||||
if (obj->get_object_id() != match.id)
|
||||
if (!match.id_equals(obj->get_object_id()))
|
||||
continue;
|
||||
|
||||
if (request->method() == HTTP_GET && match.method.empty()) {
|
||||
if (request->method() == HTTP_GET && match.method_empty()) {
|
||||
auto detail = get_request_detail(request);
|
||||
std::string data = this->lock_json(obj, obj->state, detail);
|
||||
request->send(200, "application/json", data.c_str());
|
||||
} else if (match.method == "lock") {
|
||||
} else if (match.method_equals("lock")) {
|
||||
this->schedule_([obj]() { obj->lock(); });
|
||||
request->send(200);
|
||||
} else if (match.method == "unlock") {
|
||||
} else if (match.method_equals("unlock")) {
|
||||
this->schedule_([obj]() { obj->unlock(); });
|
||||
request->send(200);
|
||||
} else if (match.method == "open") {
|
||||
} else if (match.method_equals("open")) {
|
||||
this->schedule_([obj]() { obj->open(); });
|
||||
request->send(200);
|
||||
} else {
|
||||
@ -1443,10 +1486,10 @@ void WebServer::on_valve_update(valve::Valve *obj) {
|
||||
}
|
||||
void WebServer::handle_valve_request(AsyncWebServerRequest *request, const UrlMatch &match) {
|
||||
for (valve::Valve *obj : App.get_valves()) {
|
||||
if (obj->get_object_id() != match.id)
|
||||
if (!match.id_equals(obj->get_object_id()))
|
||||
continue;
|
||||
|
||||
if (request->method() == HTTP_GET && match.method.empty()) {
|
||||
if (request->method() == HTTP_GET && match.method_empty()) {
|
||||
auto detail = get_request_detail(request);
|
||||
std::string data = this->valve_json(obj, detail);
|
||||
request->send(200, "application/json", data.c_str());
|
||||
@ -1454,15 +1497,15 @@ void WebServer::handle_valve_request(AsyncWebServerRequest *request, const UrlMa
|
||||
}
|
||||
|
||||
auto call = obj->make_call();
|
||||
if (match.method == "open") {
|
||||
if (match.method_equals("open")) {
|
||||
call.set_command_open();
|
||||
} else if (match.method == "close") {
|
||||
} else if (match.method_equals("close")) {
|
||||
call.set_command_close();
|
||||
} else if (match.method == "stop") {
|
||||
} else if (match.method_equals("stop")) {
|
||||
call.set_command_stop();
|
||||
} else if (match.method == "toggle") {
|
||||
} else if (match.method_equals("toggle")) {
|
||||
call.set_command_toggle();
|
||||
} else if (match.method != "set") {
|
||||
} else if (!match.method_equals("set")) {
|
||||
request->send(404);
|
||||
return;
|
||||
}
|
||||
@ -1515,10 +1558,10 @@ void WebServer::on_alarm_control_panel_update(alarm_control_panel::AlarmControlP
|
||||
}
|
||||
void WebServer::handle_alarm_control_panel_request(AsyncWebServerRequest *request, const UrlMatch &match) {
|
||||
for (alarm_control_panel::AlarmControlPanel *obj : App.get_alarm_control_panels()) {
|
||||
if (obj->get_object_id() != match.id)
|
||||
if (!match.id_equals(obj->get_object_id()))
|
||||
continue;
|
||||
|
||||
if (request->method() == HTTP_GET && match.method.empty()) {
|
||||
if (request->method() == HTTP_GET && match.method_empty()) {
|
||||
auto detail = get_request_detail(request);
|
||||
std::string data = this->alarm_control_panel_json(obj, obj->get_state(), detail);
|
||||
request->send(200, "application/json", data.c_str());
|
||||
@ -1530,15 +1573,15 @@ void WebServer::handle_alarm_control_panel_request(AsyncWebServerRequest *reques
|
||||
call.set_code(request->getParam("code")->value().c_str()); // NOLINT
|
||||
}
|
||||
|
||||
if (match.method == "disarm") {
|
||||
if (match.method_equals("disarm")) {
|
||||
call.disarm();
|
||||
} else if (match.method == "arm_away") {
|
||||
} else if (match.method_equals("arm_away")) {
|
||||
call.arm_away();
|
||||
} else if (match.method == "arm_home") {
|
||||
} else if (match.method_equals("arm_home")) {
|
||||
call.arm_home();
|
||||
} else if (match.method == "arm_night") {
|
||||
} else if (match.method_equals("arm_night")) {
|
||||
call.arm_night();
|
||||
} else if (match.method == "arm_vacation") {
|
||||
} else if (match.method_equals("arm_vacation")) {
|
||||
call.arm_vacation();
|
||||
} else {
|
||||
request->send(404);
|
||||
@ -1582,10 +1625,10 @@ void WebServer::on_event(event::Event *obj, const std::string &event_type) {
|
||||
|
||||
void WebServer::handle_event_request(AsyncWebServerRequest *request, const UrlMatch &match) {
|
||||
for (event::Event *obj : App.get_events()) {
|
||||
if (obj->get_object_id() != match.id)
|
||||
if (!match.id_equals(obj->get_object_id()))
|
||||
continue;
|
||||
|
||||
if (request->method() == HTTP_GET && match.method.empty()) {
|
||||
if (request->method() == HTTP_GET && match.method_empty()) {
|
||||
auto detail = get_request_detail(request);
|
||||
std::string data = this->event_json(obj, "", detail);
|
||||
request->send(200, "application/json", data.c_str());
|
||||
@ -1631,17 +1674,17 @@ void WebServer::on_update(update::UpdateEntity *obj) {
|
||||
}
|
||||
void WebServer::handle_update_request(AsyncWebServerRequest *request, const UrlMatch &match) {
|
||||
for (update::UpdateEntity *obj : App.get_updates()) {
|
||||
if (obj->get_object_id() != match.id)
|
||||
if (!match.id_equals(obj->get_object_id()))
|
||||
continue;
|
||||
|
||||
if (request->method() == HTTP_GET && match.method.empty()) {
|
||||
if (request->method() == HTTP_GET && match.method_empty()) {
|
||||
auto detail = get_request_detail(request);
|
||||
std::string data = this->update_json(obj, detail);
|
||||
request->send(200, "application/json", data.c_str());
|
||||
return;
|
||||
}
|
||||
|
||||
if (match.method != "install") {
|
||||
if (!match.method_equals("install")) {
|
||||
request->send(404);
|
||||
return;
|
||||
}
|
||||
@ -1717,102 +1760,102 @@ bool WebServer::canHandle(AsyncWebServerRequest *request) const {
|
||||
if (!match.valid)
|
||||
return false;
|
||||
#ifdef USE_SENSOR
|
||||
if (request->method() == HTTP_GET && match.domain == "sensor")
|
||||
if (request->method() == HTTP_GET && match.domain_equals("sensor"))
|
||||
return true;
|
||||
#endif
|
||||
|
||||
#ifdef USE_SWITCH
|
||||
if ((request->method() == HTTP_POST || request->method() == HTTP_GET) && match.domain == "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 == "button")
|
||||
if ((request->method() == HTTP_POST || request->method() == HTTP_GET) && match.domain_equals("button"))
|
||||
return true;
|
||||
#endif
|
||||
|
||||
#ifdef USE_BINARY_SENSOR
|
||||
if (request->method() == HTTP_GET && match.domain == "binary_sensor")
|
||||
if (request->method() == HTTP_GET && match.domain_equals("binary_sensor"))
|
||||
return true;
|
||||
#endif
|
||||
|
||||
#ifdef USE_FAN
|
||||
if ((request->method() == HTTP_POST || request->method() == HTTP_GET) && match.domain == "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 == "light")
|
||||
if ((request->method() == HTTP_POST || request->method() == HTTP_GET) && match.domain_equals("light"))
|
||||
return true;
|
||||
#endif
|
||||
|
||||
#ifdef USE_TEXT_SENSOR
|
||||
if (request->method() == HTTP_GET && match.domain == "text_sensor")
|
||||
if (request->method() == HTTP_GET && match.domain_equals("text_sensor"))
|
||||
return true;
|
||||
#endif
|
||||
|
||||
#ifdef USE_COVER
|
||||
if ((request->method() == HTTP_POST || request->method() == HTTP_GET) && match.domain == "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 == "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 == "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 == "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 == "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 == "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 == "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 == "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 == "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 == "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 == "alarm_control_panel")
|
||||
if ((request->method() == HTTP_GET || request->method() == HTTP_POST) && match.domain_equals("alarm_control_panel"))
|
||||
return true;
|
||||
#endif
|
||||
|
||||
#ifdef USE_EVENT
|
||||
if (request->method() == HTTP_GET && match.domain == "event")
|
||||
if (request->method() == HTTP_GET && match.domain_equals("event"))
|
||||
return true;
|
||||
#endif
|
||||
|
||||
#ifdef USE_UPDATE
|
||||
if ((request->method() == HTTP_POST || request->method() == HTTP_GET) && match.domain == "update")
|
||||
if ((request->method() == HTTP_POST || request->method() == HTTP_GET) && match.domain_equals("update"))
|
||||
return true;
|
||||
#endif
|
||||
|
||||
@ -1854,112 +1897,112 @@ void WebServer::handleRequest(AsyncWebServerRequest *request) {
|
||||
|
||||
UrlMatch match = match_url(request->url().c_str()); // NOLINT
|
||||
#ifdef USE_SENSOR
|
||||
if (match.domain == "sensor") {
|
||||
if (match.domain_equals("sensor")) {
|
||||
this->handle_sensor_request(request, match);
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef USE_SWITCH
|
||||
if (match.domain == "switch") {
|
||||
if (match.domain_equals("switch")) {
|
||||
this->handle_switch_request(request, match);
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef USE_BUTTON
|
||||
if (match.domain == "button") {
|
||||
if (match.domain_equals("button")) {
|
||||
this->handle_button_request(request, match);
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef USE_BINARY_SENSOR
|
||||
if (match.domain == "binary_sensor") {
|
||||
if (match.domain_equals("binary_sensor")) {
|
||||
this->handle_binary_sensor_request(request, match);
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef USE_FAN
|
||||
if (match.domain == "fan") {
|
||||
if (match.domain_equals("fan")) {
|
||||
this->handle_fan_request(request, match);
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef USE_LIGHT
|
||||
if (match.domain == "light") {
|
||||
if (match.domain_equals("light")) {
|
||||
this->handle_light_request(request, match);
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef USE_TEXT_SENSOR
|
||||
if (match.domain == "text_sensor") {
|
||||
if (match.domain_equals("text_sensor")) {
|
||||
this->handle_text_sensor_request(request, match);
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef USE_COVER
|
||||
if (match.domain == "cover") {
|
||||
if (match.domain_equals("cover")) {
|
||||
this->handle_cover_request(request, match);
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef USE_NUMBER
|
||||
if (match.domain == "number") {
|
||||
if (match.domain_equals("number")) {
|
||||
this->handle_number_request(request, match);
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef USE_DATETIME_DATE
|
||||
if (match.domain == "date") {
|
||||
if (match.domain_equals("date")) {
|
||||
this->handle_date_request(request, match);
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef USE_DATETIME_TIME
|
||||
if (match.domain == "time") {
|
||||
if (match.domain_equals("time")) {
|
||||
this->handle_time_request(request, match);
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef USE_DATETIME_DATETIME
|
||||
if (match.domain == "datetime") {
|
||||
if (match.domain_equals("datetime")) {
|
||||
this->handle_datetime_request(request, match);
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef USE_TEXT
|
||||
if (match.domain == "text") {
|
||||
if (match.domain_equals("text")) {
|
||||
this->handle_text_request(request, match);
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef USE_SELECT
|
||||
if (match.domain == "select") {
|
||||
if (match.domain_equals("select")) {
|
||||
this->handle_select_request(request, match);
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef USE_CLIMATE
|
||||
if (match.domain == "climate") {
|
||||
if (match.domain_equals("climate")) {
|
||||
this->handle_climate_request(request, match);
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef USE_LOCK
|
||||
if (match.domain == "lock") {
|
||||
if (match.domain_equals("lock")) {
|
||||
this->handle_lock_request(request, match);
|
||||
|
||||
return;
|
||||
@ -1967,14 +2010,14 @@ void WebServer::handleRequest(AsyncWebServerRequest *request) {
|
||||
#endif
|
||||
|
||||
#ifdef USE_VALVE
|
||||
if (match.domain == "valve") {
|
||||
if (match.domain_equals("valve")) {
|
||||
this->handle_valve_request(request, match);
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef USE_ALARM_CONTROL_PANEL
|
||||
if (match.domain == "alarm_control_panel") {
|
||||
if (match.domain_equals("alarm_control_panel")) {
|
||||
this->handle_alarm_control_panel_request(request, match);
|
||||
|
||||
return;
|
||||
@ -1982,7 +2025,7 @@ void WebServer::handleRequest(AsyncWebServerRequest *request) {
|
||||
#endif
|
||||
|
||||
#ifdef USE_UPDATE
|
||||
if (match.domain == "update") {
|
||||
if (match.domain_equals("update")) {
|
||||
this->handle_update_request(request, match);
|
||||
return;
|
||||
}
|
||||
|
@ -40,10 +40,28 @@ namespace web_server {
|
||||
|
||||
/// Internal helper struct that is used to parse incoming URLs
|
||||
struct UrlMatch {
|
||||
std::string domain; ///< The domain of the component, for example "sensor"
|
||||
std::string id; ///< The id of the device that's being accessed, for example "living_room_fan"
|
||||
std::string method; ///< The method that's being called, for example "turn_on"
|
||||
const char *domain; ///< Pointer to domain within URL, for example "sensor"
|
||||
const char *id; ///< Pointer to id within URL, for example "living_room_fan"
|
||||
const char *method; ///< Pointer to method within URL, for example "turn_on"
|
||||
uint8_t domain_len; ///< Length of domain string
|
||||
uint8_t id_len; ///< Length of id string
|
||||
uint8_t method_len; ///< Length of method string
|
||||
bool valid; ///< Whether this match is valid
|
||||
|
||||
// Helper methods for string comparisons
|
||||
bool domain_equals(const char *str) const {
|
||||
return domain && domain_len == strlen(str) && memcmp(domain, str, domain_len) == 0;
|
||||
}
|
||||
|
||||
bool id_equals(const std::string &str) const {
|
||||
return id && id_len == str.length() && memcmp(id, str.c_str(), id_len) == 0;
|
||||
}
|
||||
|
||||
bool method_equals(const char *str) const {
|
||||
return method && method_len == strlen(str) && memcmp(method, str, method_len) == 0;
|
||||
}
|
||||
|
||||
bool method_empty() const { return method_len == 0; }
|
||||
};
|
||||
|
||||
#ifdef USE_WEBSERVER_SORTING
|
||||
|
Loading…
x
Reference in New Issue
Block a user