#pragma once #include "esphome/core/defines.h" #ifdef USE_NETWORK #include #include #include "esphome/core/progmem.h" #if USE_ESP32 #include "esphome/core/hal.h" #include "esphome/components/web_server_idf/web_server_idf.h" #else #include #endif #if USE_ESP32 using PlatformString = std::string; #elif USE_ARDUINO using PlatformString = String; #endif namespace esphome::web_server_base { class WebServerBase; extern WebServerBase *global_web_server_base; // NOLINT(cppcoreguidelines-avoid-non-const-global-variables) namespace internal { class MiddlewareHandler : public AsyncWebHandler { public: MiddlewareHandler(AsyncWebHandler *next) : next_(next) {} bool canHandle(AsyncWebServerRequest *request) const override { return next_->canHandle(request); } void handleRequest(AsyncWebServerRequest *request) override { next_->handleRequest(request); } void handleUpload(AsyncWebServerRequest *request, const PlatformString &filename, size_t index, uint8_t *data, size_t len, bool final) override { next_->handleUpload(request, filename, index, data, len, final); } void handleBody(AsyncWebServerRequest *request, uint8_t *data, size_t len, size_t index, size_t total) override { next_->handleBody(request, data, len, index, total); } bool isRequestHandlerTrivial() const override { return next_->isRequestHandlerTrivial(); } protected: AsyncWebHandler *next_; }; #ifdef USE_WEBSERVER_AUTH struct Credentials { std::string username; std::string password; }; class AuthMiddlewareHandler : public MiddlewareHandler { public: AuthMiddlewareHandler(AsyncWebHandler *next, Credentials *credentials) : MiddlewareHandler(next), credentials_(credentials) {} bool check_auth(AsyncWebServerRequest *request) { bool success = request->authenticate(credentials_->username.c_str(), credentials_->password.c_str()); if (!success) { request->requestAuthentication(); } return success; } void handleRequest(AsyncWebServerRequest *request) override { if (!check_auth(request)) return; MiddlewareHandler::handleRequest(request); } void handleUpload(AsyncWebServerRequest *request, const PlatformString &filename, size_t index, uint8_t *data, size_t len, bool final) override { if (!check_auth(request)) return; MiddlewareHandler::handleUpload(request, filename, index, data, len, final); } void handleBody(AsyncWebServerRequest *request, uint8_t *data, size_t len, size_t index, size_t total) override { if (!check_auth(request)) return; MiddlewareHandler::handleBody(request, data, len, index, total); } protected: Credentials *credentials_; }; #endif } // namespace internal class WebServerBase { public: void init() { if (this->initialized_) { this->initialized_++; return; } this->server_ = new AsyncWebServer(this->port_); // All content is controlled and created by user - so allowing all origins is fine here. // NOTE: Currently 1 header. If more are added, update in __init__.py: // cg.add_define("WEB_SERVER_DEFAULT_HEADERS_COUNT", 1) DefaultHeaders::Instance().addHeader(ESPHOME_F("Access-Control-Allow-Origin"), ESPHOME_F("*")); this->server_->begin(); for (auto *handler : this->handlers_) this->server_->addHandler(handler); this->initialized_++; } void deinit() { this->initialized_--; if (this->initialized_ == 0) { delete this->server_; this->server_ = nullptr; } } AsyncWebServer *get_server() const { return this->server_; } #ifdef USE_WEBSERVER_AUTH void set_auth_username(std::string auth_username) { credentials_.username = std::move(auth_username); } void set_auth_password(std::string auth_password) { credentials_.password = std::move(auth_password); } #endif void add_handler(AsyncWebHandler *handler); /** * WARNING: Registers a handler that bypasses the USE_WEBSERVER_AUTH middleware. * * This should only be used for endpoints that are intentionally unauthenticated * (for example, captive portal or very limited-status endpoints). For normal * endpoints that should respect web server authentication, use add_handler(). */ void add_handler_without_auth(AsyncWebHandler *handler); void set_port(uint16_t port) { port_ = port; } uint16_t get_port() const { return port_; } protected: uint8_t initialized_{0}; uint16_t port_{80}; AsyncWebServer *server_{nullptr}; std::vector handlers_; #ifdef USE_WEBSERVER_AUTH internal::Credentials credentials_; #endif }; } // namespace esphome::web_server_base #endif