ESPHome 2025.9.0-dev
Loading...
Searching...
No Matches
web_server_idf.h
Go to the documentation of this file.
1#pragma once
2#ifdef USE_ESP_IDF
5#include <esp_http_server.h>
6
7#include <atomic>
8#include <functional>
9#include <list>
10#include <map>
11#include <set>
12#include <string>
13#include <utility>
14#include <vector>
15
16namespace esphome {
17#ifdef USE_WEBSERVER
18namespace web_server {
19class WebServer;
20class ListEntitiesIterator;
21}; // namespace web_server
22#endif
23namespace web_server_idf {
24
25#define F(string_literal) (string_literal)
26#define PGM_P const char *
27#define strncpy_P strncpy
28
29using String = std::string;
30
32 public:
33 AsyncWebParameter(std::string value) : value_(std::move(value)) {}
34 const std::string &value() const { return this->value_; }
35
36 protected:
37 std::string value_;
38};
39
41
43 public:
46
47 // NOLINTNEXTLINE(readability-identifier-naming)
48 void addHeader(const char *name, const char *value);
49
50 virtual const char *get_content_data() const = 0;
51 virtual size_t get_content_size() const = 0;
52
53 protected:
55};
56
58 public:
60
61 const char *get_content_data() const override { return nullptr; };
62 size_t get_content_size() const override { return 0; };
63};
64
66 public:
68 : AsyncWebServerResponse(req), content_(std::move(content)) {}
69
70 const char *get_content_data() const override { return this->content_.c_str(); };
71 size_t get_content_size() const override { return this->content_.size(); };
72
73 protected:
74 std::string content_;
75};
76
78 public:
80
81 const char *get_content_data() const override { return this->content_.c_str(); };
82 size_t get_content_size() const override { return this->content_.size(); };
83
84 void print(const char *str) { this->content_.append(str); }
85 void print(const std::string &str) { this->content_.append(str); }
86 void print(float value);
87 void printf(const char *fmt, ...) __attribute__((format(printf, 2, 3)));
88
89 protected:
90 std::string content_;
91};
92
94 public:
95 AsyncWebServerResponseProgmem(const AsyncWebServerRequest *req, const uint8_t *data, const size_t size)
96 : AsyncWebServerResponse(req), data_(data), size_(size) {}
97
98 const char *get_content_data() const override { return reinterpret_cast<const char *>(this->data_); };
99 size_t get_content_size() const override { return this->size_; };
100
101 protected:
102 const uint8_t *data_;
103 size_t size_;
104};
105
107 friend class AsyncWebServer;
108
109 public:
111
112 http_method method() const { return static_cast<http_method>(this->req_->method); }
113 std::string url() const;
114 std::string host() const;
115 // NOLINTNEXTLINE(readability-identifier-naming)
116 size_t contentLength() const { return this->req_->content_len; }
117
118#ifdef USE_WEBSERVER_AUTH
119 bool authenticate(const char *username, const char *password) const;
120 // NOLINTNEXTLINE(readability-identifier-naming)
121 void requestAuthentication(const char *realm = nullptr) const;
122#endif
123
124 void redirect(const std::string &url);
125
126 void send(AsyncWebServerResponse *response);
127 void send(int code, const char *content_type = nullptr, const char *content = nullptr);
128 // NOLINTNEXTLINE(readability-identifier-naming)
129 AsyncWebServerResponse *beginResponse(int code, const char *content_type) {
130 auto *res = new AsyncWebServerResponseEmpty(this); // NOLINT(cppcoreguidelines-owning-memory)
131 this->init_response_(res, code, content_type);
132 return res;
133 }
134 // NOLINTNEXTLINE(readability-identifier-naming)
135 AsyncWebServerResponse *beginResponse(int code, const char *content_type, const std::string &content) {
136 auto *res = new AsyncWebServerResponseContent(this, content); // NOLINT(cppcoreguidelines-owning-memory)
137 this->init_response_(res, code, content_type);
138 return res;
139 }
140 // NOLINTNEXTLINE(readability-identifier-naming)
141 AsyncWebServerResponse *beginResponse(int code, const char *content_type, const uint8_t *data,
142 const size_t data_size) {
143 auto *res = new AsyncWebServerResponseProgmem(this, data, data_size); // NOLINT(cppcoreguidelines-owning-memory)
144 this->init_response_(res, code, content_type);
145 return res;
146 }
147 // NOLINTNEXTLINE(readability-identifier-naming)
148 AsyncResponseStream *beginResponseStream(const char *content_type) {
149 auto *res = new AsyncResponseStream(this); // NOLINT(cppcoreguidelines-owning-memory)
150 this->init_response_(res, 200, content_type);
151 return res;
152 }
153
154 // NOLINTNEXTLINE(readability-identifier-naming)
155 bool hasParam(const std::string &name) { return this->getParam(name) != nullptr; }
156 // NOLINTNEXTLINE(readability-identifier-naming)
157 AsyncWebParameter *getParam(const std::string &name);
158
159 // NOLINTNEXTLINE(readability-identifier-naming)
160 bool hasArg(const char *name) { return this->hasParam(name); }
161 std::string arg(const std::string &name) {
162 auto *param = this->getParam(name);
163 if (param) {
164 return param->value();
165 }
166 return {};
167 }
168
169 operator httpd_req_t *() const { return this->req_; }
170 optional<std::string> get_header(const char *name) const;
171 // NOLINTNEXTLINE(readability-identifier-naming)
172 bool hasHeader(const char *name) const;
173
174 protected:
175 httpd_req_t *req_;
177 std::map<std::string, AsyncWebParameter *> params_;
178 std::string post_query_;
179 AsyncWebServerRequest(httpd_req_t *req) : req_(req) {}
180 AsyncWebServerRequest(httpd_req_t *req, std::string post_query) : req_(req), post_query_(std::move(post_query)) {}
181 void init_response_(AsyncWebServerResponse *rsp, int code, const char *content_type);
182};
183
184class AsyncWebHandler;
185
187 public:
188 AsyncWebServer(uint16_t port) : port_(port){};
189 ~AsyncWebServer() { this->end(); }
190
191 // NOLINTNEXTLINE(readability-identifier-naming)
192 void onNotFound(std::function<void(AsyncWebServerRequest *request)> fn) { on_not_found_ = std::move(fn); }
193
194 void begin();
195 void end();
196
197 // NOLINTNEXTLINE(readability-identifier-naming)
199 this->handlers_.push_back(handler);
200 return *handler;
201 }
202
203 protected:
204 uint16_t port_{};
205 httpd_handle_t server_{};
206 static esp_err_t request_handler(httpd_req_t *r);
207 static esp_err_t request_post_handler(httpd_req_t *r);
208 esp_err_t request_handler_(AsyncWebServerRequest *request) const;
209#ifdef USE_WEBSERVER_OTA
210 esp_err_t handle_multipart_upload_(httpd_req_t *r, const char *content_type);
211#endif
212 std::vector<AsyncWebHandler *> handlers_;
213 std::function<void(AsyncWebServerRequest *request)> on_not_found_{};
214};
215
217 public:
218 virtual ~AsyncWebHandler() {}
219 // NOLINTNEXTLINE(readability-identifier-naming)
220 virtual bool canHandle(AsyncWebServerRequest *request) const { return false; }
221 // NOLINTNEXTLINE(readability-identifier-naming)
222 virtual void handleRequest(AsyncWebServerRequest *request) {}
223 // NOLINTNEXTLINE(readability-identifier-naming)
224 virtual void handleUpload(AsyncWebServerRequest *request, const std::string &filename, size_t index, uint8_t *data,
225 size_t len, bool final) {}
226 // NOLINTNEXTLINE(readability-identifier-naming)
227 virtual void handleBody(AsyncWebServerRequest *request, uint8_t *data, size_t len, size_t index, size_t total) {}
228 // NOLINTNEXTLINE(readability-identifier-naming)
229 virtual bool isRequestHandlerTrivial() const { return true; }
230};
231
232#ifdef USE_WEBSERVER
233class AsyncEventSource;
235
237
238/*
239 This class holds a pointer to the source component that wants to publish a state event, and a pointer to a function
240 that will lazily generate that event. The two pointers allow dedup in the deferred queue if multiple publishes for
241 the same component are backed up, and take up only 8 bytes of memory. The entry in the deferred queue (a
242 std::vector) is the DeferredEvent instance itself (not a pointer to one elsewhere in heap) so still only 8 bytes per
243 entry (and no heap fragmentation). Even 100 backed up events (you'd have to have at least 100 sensors publishing
244 because of dedup) would take up only 0.8 kB.
245*/
248
249 protected:
250 void *source_;
252
253 public:
254 DeferredEvent(void *source, message_generator_t *message_generator)
255 : source_(source), message_generator_(message_generator) {}
256 bool operator==(const DeferredEvent &test) const {
257 return (source_ == test.source_ && message_generator_ == test.message_generator_);
258 }
259} __attribute__((packed));
260
262 friend class AsyncEventSource;
263
264 public:
265 bool try_send_nodefer(const char *message, const char *event = nullptr, uint32_t id = 0, uint32_t reconnect = 0);
266 void deferrable_send_state(void *source, const char *event_type, message_generator_t *message_generator);
267 void loop();
268
269 protected:
272
273 void deq_push_back_with_dedup_(void *source, message_generator_t *message_generator);
274 void process_deferred_queue_();
275 void process_buffer_();
276
277 static void destroy(void *p);
279 httpd_handle_t hd_{};
280 std::atomic<int> fd_{};
281 std::vector<DeferredEvent> deferred_queue_;
283 std::unique_ptr<esphome::web_server::ListEntitiesIterator> entities_iterator_;
284 std::string event_buffer_{""};
287
289
292 using connect_handler_t = std::function<void(AsyncEventSourceClient *)>;
293
294 public:
295 AsyncEventSource(std::string url, esphome::web_server::WebServer *ws) : url_(std::move(url)), web_server_(ws) {}
296 ~AsyncEventSource() override;
297
298 // NOLINTNEXTLINE(readability-identifier-naming)
299 bool canHandle(AsyncWebServerRequest *request) const override {
300 return request->method() == HTTP_GET && request->url() == this->url_;
301 }
302 // NOLINTNEXTLINE(readability-identifier-naming)
303 void handleRequest(AsyncWebServerRequest *request) override;
304 // NOLINTNEXTLINE(readability-identifier-naming)
305 void onConnect(connect_handler_t cb) { this->on_connect_ = std::move(cb); }
306
307 void try_send_nodefer(const char *message, const char *event = nullptr, uint32_t id = 0, uint32_t reconnect = 0);
308 void deferrable_send_state(void *source, const char *event_type, message_generator_t *message_generator);
309 void loop();
310 bool empty() { return this->count() == 0; }
311
312 size_t count() const { return this->sessions_.size(); }
313
314 protected:
315 std::string url_;
316 std::set<AsyncEventSourceResponse *> sessions_;
317 connect_handler_t on_connect_{};
319};
320#endif // USE_WEBSERVER
321
324#ifdef USE_WEBSERVER
326#endif
327
328 public:
329 // NOLINTNEXTLINE(readability-identifier-naming)
330 void addHeader(const char *name, const char *value) { this->headers_.emplace_back(name, value); }
331
332 // NOLINTNEXTLINE(readability-identifier-naming)
333 static DefaultHeaders &Instance();
334
335 protected:
336 std::vector<std::pair<std::string, std::string>> headers_;
337};
338
339} // namespace web_server_idf
340} // namespace esphome
341
342using namespace esphome::web_server_idf; // NOLINT(google-global-names-in-headers)
343
344#endif // !defined(USE_ESP_IDF)
This class allows users to create a web server with their ESP nodes.
Definition web_server.h:166
AsyncEventSource(std::string url, esphome::web_server::WebServer *ws)
std::set< AsyncEventSourceResponse * > sessions_
esphome::web_server::WebServer * web_server_
bool canHandle(AsyncWebServerRequest *request) const override
esphome::web_server::WebServer * web_server_
std::unique_ptr< esphome::web_server::ListEntitiesIterator > entities_iterator_
AsyncResponseStream(const AsyncWebServerRequest *req)
void printf(const char *fmt,...) __attribute__((format(printf
const char * get_content_data() const override
virtual bool canHandle(AsyncWebServerRequest *request) const
virtual void handleRequest(AsyncWebServerRequest *request)
virtual void handleUpload(AsyncWebServerRequest *request, const std::string &filename, size_t index, uint8_t *data, size_t len, bool final)
virtual void handleBody(AsyncWebServerRequest *request, uint8_t *data, size_t len, size_t index, size_t total)
std::vector< AsyncWebHandler * > handlers_
AsyncWebHandler & addHandler(AsyncWebHandler *handler)
void onNotFound(std::function< void(AsyncWebServerRequest *request)> fn)
AsyncWebServerResponse * beginResponse(int code, const char *content_type, const uint8_t *data, const size_t data_size)
std::map< std::string, AsyncWebParameter * > params_
AsyncWebServerResponse * beginResponse(int code, const char *content_type, const std::string &content)
std::string arg(const std::string &name)
AsyncWebServerResponse * beginResponse(int code, const char *content_type)
AsyncResponseStream * beginResponseStream(const char *content_type)
AsyncWebServerRequest(httpd_req_t *req, std::string post_query)
AsyncWebServerResponseContent(const AsyncWebServerRequest *req, std::string content)
AsyncWebServerResponseEmpty(const AsyncWebServerRequest *req)
virtual const char * get_content_data() const =0
AsyncWebServerResponse(const AsyncWebServerRequest *req)
void addHeader(const char *name, const char *value)
AsyncWebServerResponseProgmem(const AsyncWebServerRequest *req, const uint8_t *data, const size_t size)
std::vector< std::pair< std::string, std::string > > headers_
void addHeader(const char *name, const char *value)
void loop()
std::string(esphome::web_server::WebServer *, void *) message_generator_t
class esphome::web_server_idf::AsyncEventSourceResponse __attribute__
Providing packet encoding functions for exchanging data with a remote host.
Definition a01nyub.cpp:7
bool operator==(const DeferredEvent &test) const
DeferredEvent(void *source, message_generator_t *message_generator)
uint8_t end[39]
Definition sun_gtil2.cpp:17
uint32_t len
std::string print()
message_generator_t * message_generator_
Definition web_server.h:4
void * source_
Definition web_server.h:3
friend class AsyncEventSourceResponse