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