ESPHome  2025.3.3
All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Modules Pages
web_server_idf.h
Go to the documentation of this file.
1 #pragma once
2 #ifdef USE_ESP_IDF
3 
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 
14 namespace esphome {
15 namespace web_server {
16 class WebServer;
17 class ListEntitiesIterator;
18 }; // namespace web_server
19 namespace web_server_idf {
20 
21 #define F(string_literal) (string_literal)
22 #define PGM_P const char *
23 #define strncpy_P strncpy
24 
25 using 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:
40  AsyncWebServerResponse(const AsyncWebServerRequest *req) : req_(req) {}
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:
63  AsyncWebServerResponseContent(const AsyncWebServerRequest *req, std::string content)
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 
178 class 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 
223 class 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_{""};
276 };
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 
312  friend class AsyncWebServerRequest;
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 
332 using namespace esphome::web_server_idf; // NOLINT(google-global-names-in-headers)
333 
334 #endif // !defined(USE_ESP_IDF)
const char * name
Definition: stm32flash.h:78
void loop()
virtual void handleRequest(AsyncWebServerRequest *request)
This class allows users to create a web server with their ESP nodes.
Definition: web_server.h:149
void addHeader(const char *name, const char *value)
AsyncResponseStream * beginResponseStream(const char *content_type)
AsyncWebHandler & addHandler(AsyncWebHandler *handler)
virtual void handleBody(AsyncWebServerRequest *request, uint8_t *data, size_t len, size_t index, size_t total)
std::unique_ptr< esphome::web_server::ListEntitiesIterator > entities_iterator_
STL namespace.
virtual bool canHandle(AsyncWebServerRequest *request)
const char * get_content_data() const override
std::string(esphome::web_server::WebServer *, void *) message_generator_t
static DefaultHeaders & Instance()
AsyncWebServerResponse(const AsyncWebServerRequest *req)
void onConnect(connect_handler_t cb)
AsyncWebServerResponseProgmem(const AsyncWebServerRequest *req, const uint8_t *data, const size_t size)
friend class AsyncEventSourceResponse
AsyncWebServerResponse * beginResponse(int code, const char *content_type)
message_generator_t * message_generator_
virtual void handleUpload(AsyncWebServerRequest *request, const std::string &filename, size_t index, uint8_t *data, size_t len, bool final)
void onNotFound(std::function< void(AsyncWebServerRequest *request)> fn)
std::vector< AsyncWebHandler * > handlers_
AsyncWebServerResponseContent(const AsyncWebServerRequest *req, std::string content)
esphome::web_server::WebServer * web_server_
AsyncWebServerResponseEmpty(const AsyncWebServerRequest *req)
std::string print()
std::vector< std::pair< std::string, std::string > > headers_
esphome::web_server::WebServer * web_server_
enum esphome::EntityCategory __attribute__
std::string size_t len
Definition: helpers.h:301
std::map< std::string, AsyncWebParameter * > params_
std::string arg(const std::string &name)
AsyncEventSource(std::string url, esphome::web_server::WebServer *ws)
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)
Implementation of SPI Controller mode.
Definition: a01nyub.cpp:7
num_t cb(num_t x)
Definition: sun.cpp:31
std::set< AsyncEventSourceResponse * > sessions_
uint8_t end[39]
Definition: sun_gtil2.cpp:31
bool operator==(const DeferredEvent &test) const
DeferredEvent(void *source, message_generator_t *message_generator)
AsyncWebServerResponse * beginResponse(int code, const char *content_type, const std::string &content)
bool canHandle(AsyncWebServerRequest *request) override
AsyncResponseStream(const AsyncWebServerRequest *req)