SensESP 3.3.0
Universal Signal K sensor toolkit ESP32
Loading...
Searching...
No Matches
base_command_handler.cpp
Go to the documentation of this file.
2
5#include "sensesp_app.h"
6
7namespace sensesp {
8
9namespace {
10
12bool check_origin(httpd_req_t* req) {
13 char origin[128] = {0};
14 if (httpd_req_get_hdr_value_str(req, "Origin", origin, sizeof(origin)) ==
15 ESP_OK) {
16 String origin_str(origin);
17 String hostname = SensESPBaseApp::get_hostname();
18 if (origin_str.indexOf(hostname) < 0) {
19 // Check the active provisioner's local IP — works for both WiFi
20 // and Ethernet without depending on the WiFi library directly.
21 auto provisioner = SensESPApp::get()->get_network_provisioner();
22 String ip =
23 provisioner ? provisioner->local_ip().toString() : String("");
24 if (ip.length() == 0 || origin_str.indexOf(ip) < 0) {
25 httpd_resp_send_err(req, HTTPD_403_FORBIDDEN,
26 "Cross-origin request rejected");
27 return false;
28 }
29 }
30 }
31 return true;
32}
33
34} // namespace
35
36void add_http_reset_handler(std::shared_ptr<HTTPServer>& server) {
37 auto reset_handler = std::make_shared<HTTPRequestHandler>(
38 1 << HTTP_POST, "/api/device/reset", [](httpd_req_t* req) {
39 if (!check_origin(req)) {
40 return ESP_FAIL;
41 }
42 httpd_resp_send(req,
43 "Resetting device back to factory defaults. "
44 "You may have to reconfigure the WiFi settings.",
45 0);
46 event_loop()->onDelay(500, []() { SensESPBaseApp::get()->reset(); });
47 return ESP_OK;
48 });
49 server->add_handler(reset_handler);
50}
51
52void add_http_restart_handler(std::shared_ptr<HTTPServer>& server) {
53 auto restart_handler = std::make_shared<HTTPRequestHandler>(
54 1 << HTTP_POST, "/api/device/restart", [](httpd_req_t* req) {
55 if (!check_origin(req)) {
56 return ESP_FAIL;
57 }
58 httpd_resp_send(req, "Restarting device", 0);
59 event_loop()->onDelay(500, []() { ESP.restart(); });
60 return ESP_OK;
61 });
62 server->add_handler(restart_handler);
63}
64
65void add_http_info_handler(std::shared_ptr<HTTPServer>& server) {
66 auto info_handler = std::make_shared<HTTPRequestHandler>(
67 1 << HTTP_GET, "/api/info", [](httpd_req_t* req) {
68 auto status_page_items = StatusPageItemBase::get_status_page_items();
69
70 JsonDocument json_doc;
71 JsonArray info_items = json_doc.to<JsonArray>();
72
73 for (auto info_item = status_page_items->begin();
74 info_item != status_page_items->end(); ++info_item) {
75 info_items.add(info_item->second->as_json());
76 }
77
78 String response;
79 serializeJson(json_doc, response);
80 httpd_resp_set_type(req, "application/json");
81 httpd_resp_sendstr(req, response.c_str());
82 return ESP_OK;
83 });
84 server->add_handler(info_handler);
85}
86
87void add_routes_handlers(std::shared_ptr<HTTPServer>& server) {
88 std::vector<RouteDefinition> routes;
89
90 routes.push_back(RouteDefinition("Status", "/status", "StatusPage"));
91 routes.push_back(RouteDefinition("System", "/system", "SystemPage"));
92 routes.push_back(RouteDefinition("WiFi", "/wifi", "WiFiConfigPage"));
93 routes.push_back(RouteDefinition("Signal K", "/signalk", "SignalKPage"));
94 routes.push_back(
95 RouteDefinition("Configuration", "/configuration", "ConfigurationPage"));
96
97 // Pre-render the response
98 JsonDocument json_doc;
99 JsonArray routes_json = json_doc.to<JsonArray>();
100
101 int sz = routes.size();
102
103 for (auto it = routes.begin(); it != routes.end(); ++it) {
104 routes_json.add(it->as_json());
105 }
106
107 String response;
108
109 serializeJson(routes_json, response);
110
111 auto routes_handler = std::make_shared<HTTPRequestHandler>(
112 1 << HTTP_GET, "/api/routes", [response](httpd_req_t* req) {
113 httpd_resp_set_type(req, "application/json");
114 httpd_resp_sendstr(req, response.c_str());
115 return ESP_OK;
116 });
117 server->add_handler(routes_handler);
118
119 // Find the root page
120
121 StaticFileData* root_page = nullptr;
122 for (int i = 0; i < sizeof(kFrontendFiles) / sizeof(StaticFileData); i++) {
123 if (strcmp(kFrontendFiles[i].url, "/") == 0) {
124 root_page = (StaticFileData*)&kFrontendFiles[i];
125 break;
126 }
127 }
128 if (root_page == nullptr) {
129 ESP_LOGE(__FILENAME__, "Root page not found in kWebUIFiles");
130 return;
131 }
132
133 // Add a handler for each route that returns the root page
134
135 for (auto it = routes.begin(); it != routes.end(); ++it) {
136 String path = it->get_path();
137 auto route_handler = std::make_shared<HTTPRequestHandler>(
138 1 << HTTP_GET, path.c_str(), [root_page](httpd_req_t* req) {
139 httpd_resp_set_type(req, root_page->content_type);
140 if (root_page->content_encoding != nullptr) {
141 httpd_resp_set_hdr(req, kContentEncoding,
142 root_page->content_encoding);
143 }
144 httpd_resp_send(req, root_page->content, root_page->content_length);
145 return ESP_OK;
146 });
147 server->add_handler(route_handler);
148 }
149}
150
151void add_base_app_http_command_handlers(std::shared_ptr<HTTPServer>& server) {
154 add_http_info_handler(server);
155 add_routes_handlers(server);
156}
157
158} // namespace sensesp
static std::shared_ptr< SensESPApp > get()
Get the singleton instance of the SensESPApp.
Definition sensesp_app.h:54
static String get_hostname()
Get the current hostname.
static const std::shared_ptr< SensESPBaseApp > & get()
Get the singleton instance of the SensESPBaseApp.
static const std::map< String, StatusPageItemBase * > * get_status_page_items()
std::shared_ptr< reactesp::EventLoop > event_loop()
Definition sensesp.cpp:9
void add_http_info_handler(std::shared_ptr< HTTPServer > &server)
const StaticFileData kFrontendFiles[]
void add_http_restart_handler(std::shared_ptr< HTTPServer > &server)
void add_http_reset_handler(std::shared_ptr< HTTPServer > &server)
void add_base_app_http_command_handlers(std::shared_ptr< HTTPServer > &server)
void add_routes_handlers(std::shared_ptr< HTTPServer > &server)
const unsigned int content_length