SensESP 3.3.0
Universal Signal K sensor toolkit ESP32
Loading...
Searching...
No Matches
http_server.h
Go to the documentation of this file.
1#ifndef SENSESP_NET_HTTP_SERVER_H_
2#define SENSESP_NET_HTTP_SERVER_H_
3
4#include "sensesp.h"
5
6#include <ESPmDNS.h>
7#include <IPAddress.h>
8#include <esp_http_server.h>
9#include <functional>
10#include <list>
11#include <memory>
12
15#include "sensesp_base_app.h"
16
17#ifndef HTTP_SERVER_STACK_SIZE
18#define HTTP_SERVER_STACK_SIZE 8192
19#endif
20
21namespace sensesp {
22
23#ifndef HTTP_DEFAULT_PORT
24#define HTTP_DEFAULT_PORT 80
25#endif
26
27#include <ctype.h>
28#include <stdlib.h>
29
30void urldecode2(char* dst, const char* src);
31String get_content_type(httpd_req_t* req);
32esp_err_t call_request_dispatcher(httpd_req_t* req);
33
34class HTTPServer;
35
41 public:
42 HTTPRequestHandler(uint32_t method_mask, String match_uri,
43 std::function<esp_err_t(httpd_req_t*)> handler_func)
44 : method_mask_(method_mask),
45 match_uri_(match_uri),
46 handler_func_(handler_func) {}
47
48 const uint32_t method_mask_;
49 const String match_uri_;
50
51 esp_err_t call(httpd_req_t* req) { return this->handler_func_(req); }
52
53 protected:
54 const std::function<esp_err_t(httpd_req_t*)> handler_func_;
55};
56
62 public:
64 const String& config_path = "/system/httpserver")
65 : FileSystemSaveable(config_path), config_(HTTPD_DEFAULT_CONFIG()) {
66 config_.server_port = port;
68 config_.max_uri_handlers = 20;
69 config_.uri_match_fn = httpd_uri_match_wildcard;
70 String auth_realm_ = "Login required for " + SensESPBaseApp::get_hostname();
71 load();
72 if (auth_required_) {
73 authenticator_ = std::unique_ptr<HTTPDigestAuthenticator>(
76 username_, ha1_, auth_realm_));
77 }
78 event_loop()->onDelay(0, [this]() {
79 esp_err_t error = httpd_start(&server_, &config_);
80 if (error != ESP_OK) {
81 ESP_LOGE(__FILENAME__, "Error starting HTTP server: %s",
82 esp_err_to_name(error));
83 } else {
84 ESP_LOGI(__FILENAME__, "HTTP server started");
85 }
86
87 // register the request dispatcher for all methods and all URIs
88 httpd_uri_t uri = {
89 .uri = "/*",
90 .method = HTTP_GET,
91 .handler = call_request_dispatcher,
92 .user_ctx = this,
93 };
94 httpd_register_uri_handler(server_, &uri);
95 uri.method = HTTP_HEAD;
96 httpd_register_uri_handler(server_, &uri);
97 uri.method = HTTP_POST;
98 httpd_register_uri_handler(server_, &uri);
99 uri.method = HTTP_PUT;
100 httpd_register_uri_handler(server_, &uri);
101 uri.method = HTTP_DELETE;
102 httpd_register_uri_handler(server_, &uri);
103
104 // announce the server over mDNS
105 MDNS.addService("http", "tcp", 80);
106 });
107 };
108
109 void stop() { httpd_stop(server_); }
110
111 void set_auth_credentials(const String& username, const String& password,
112 bool auth_required = true) {
113 username_ = username;
114 String realm = "Login required for " + SensESPBaseApp::get_hostname();
115 ha1_ = MD5(username + ":" + realm + ":" + password);
116 auth_required_ = auth_required;
117 }
118
127 void set_captive_portal(bool captive_portal,
128 IPAddress ap_ip = IPAddress()) {
129 captive_portal_ = captive_portal;
130 captive_portal_ap_ip_ = ap_ip;
131 }
132
133 virtual bool to_json(JsonObject& config) override {
134 config["auth_required"] = auth_required_;
135 config["username"] = username_;
136 config["ha1"] = ha1_;
137
138 return true;
139 }
140
141 virtual bool from_json(const JsonObject& config) override {
142 if (config["auth_required"].is<bool>()) {
143 auth_required_ = config["auth_required"];
144 }
145 if (config["username"].is<String>()) {
146 username_ = config["username"].as<String>();
147 }
148 if (config["ha1"].is<String>()) {
149 ha1_ = config["ha1"].as<String>();
150 } else if (config["password"].is<String>()) {
151 // Migrate from old plaintext password format
152 String password = config["password"].as<String>();
153 String realm = "Login required for " + SensESPBaseApp::get_hostname();
154 ha1_ = MD5(username_ + ":" + realm + ":" + password);
155 save();
156 }
157 return true;
158 }
159
160 void add_handler(std::shared_ptr<HTTPRequestHandler>& handler) {
161 handlers_.push_back(handler);
162 }
163
164 protected:
165 bool captive_portal_ = false;
167 httpd_handle_t server_ = nullptr;
168 httpd_config_t config_;
169 String username_;
170 String ha1_;
171 bool auth_required_ = false;
172 std::unique_ptr<HTTPAuthenticator> authenticator_;
173
175 std::function<esp_err_t(httpd_req_t*)> handler,
176 httpd_req_t* req);
177
185 esp_err_t dispatch_request(httpd_req_t* req);
186
194 bool handle_captive_portal(httpd_req_t* req);
195
196 std::list<std::shared_ptr<HTTPRequestHandler>> handlers_;
197
198 friend esp_err_t call_request_dispatcher(httpd_req_t* req);
199};
200
201inline const String ConfigSchema(const HTTPServer& obj) {
202 return "null";
203}
204
205inline bool ConfigRequiresRestart(const HTTPServer& obj) { return true; }
206
207} // namespace sensesp
208
209#endif // SENSESP_NET_HTTP_SERVER_H_
virtual bool load() override
Load and populate the object from a persistent storage.
Definition saveable.cpp:8
virtual bool save() override
Save the object to a persistent storage.
Definition saveable.cpp:40
FileSystemSaveable(const String &config_path)
Definition saveable.h:63
HTTP Authenticator base class.
HTTP Digest Authenticator class.
const uint32_t method_mask_
Definition http_server.h:48
HTTPRequestHandler(uint32_t method_mask, String match_uri, std::function< esp_err_t(httpd_req_t *)> handler_func)
Definition http_server.h:42
const std::function< esp_err_t(httpd_req_t *)> handler_func_
Definition http_server.h:54
esp_err_t call(httpd_req_t *req)
Definition http_server.h:51
HTTP server class wrapping the esp-idf http server.
Definition http_server.h:61
esp_err_t dispatch_request(httpd_req_t *req)
Dispatcher method that captures all requests and forwards them to the appropriate handlers.
String ha1_
Pre-computed MD5(username:realm:password).
virtual bool to_json(JsonObject &config) override
std::list< std::shared_ptr< HTTPRequestHandler > > handlers_
httpd_handle_t server_
void set_auth_credentials(const String &username, const String &password, bool auth_required=true)
IPAddress captive_portal_ap_ip_
bool authenticate_request(HTTPAuthenticator *auth, std::function< esp_err_t(httpd_req_t *)> handler, httpd_req_t *req)
void set_captive_portal(bool captive_portal, IPAddress ap_ip=IPAddress())
Enable or disable the captive-portal redirect path.
friend esp_err_t call_request_dispatcher(httpd_req_t *req)
httpd_config_t config_
virtual bool from_json(const JsonObject &config) override
void add_handler(std::shared_ptr< HTTPRequestHandler > &handler)
HTTPServer(int port=HTTP_DEFAULT_PORT, const String &config_path="/system/httpserver")
Definition http_server.h:63
std::unique_ptr< HTTPAuthenticator > authenticator_
bool handle_captive_portal(httpd_req_t *req)
Check if the request is for the captive portal and handle it if it.
static String get_hostname()
Get the current hostname.
#define HTTP_DEFAULT_PORT
Definition http_server.h:24
#define HTTP_SERVER_STACK_SIZE
Definition http_server.h:18
const String ConfigSchema(const SmartSwitchController &obj)
std::shared_ptr< reactesp::EventLoop > event_loop()
Definition sensesp.cpp:9
String MD5(const String &payload_str)
MD5 hash function.
Definition hash.cpp:45
esp_err_t call_request_dispatcher(httpd_req_t *req)
void urldecode2(char *dst, const char *src)
bool ConfigRequiresRestart(const HTTPServer &obj)
String get_content_type(httpd_req_t *req)
Construct with a pre-computed HA1 hash (avoids storing plaintext password).