From 21323aa46fca70b284759ef8de45af56db8fe3ef Mon Sep 17 00:00:00 2001 From: Mathieu Carbou Date: Thu, 9 Jan 2025 15:31:27 +0100 Subject: [PATCH] Breaking: Renamed Middleware classes to not conflict with Arduino Core 3.1.1 which now has Middleware support --- README.md | 26 ++++++++++++------------ docs/index.md | 26 ++++++++++++------------ examples/SimpleServer/SimpleServer.ino | 20 +++++++++--------- src/AsyncEventSource.cpp | 2 +- src/ESPAsyncWebServer.h | 28 +++++++++++++------------- src/Middleware.cpp | 26 ++++++++++++------------ src/WebHandlers.cpp | 2 +- 7 files changed, 65 insertions(+), 65 deletions(-) diff --git a/README.md b/README.md index 5fd384b..971bd00 100644 --- a/README.md +++ b/README.md @@ -22,7 +22,7 @@ This fork is based on [yubox-node-org/ESPAsyncWebServer](https://github.com/yubo - [`AsyncWebSocketMessageBuffer` and `makeBuffer()`](#asyncwebsocketmessagebuffer-and-makebuffer) - [How to replace a response](#how-to-replace-a-response) - [How to use Middleware](#how-to-use-middleware) -- [How to use authentication with AuthenticationMiddleware](#how-to-use-authentication-with-authenticationmiddleware) +- [How to use authentication with AsyncAuthenticationMiddleware](#how-to-use-authentication-with-authenticationmiddleware) - [Migration to Middleware to improve performance and memory usage](#migration-to-middleware-to-improve-performance-and-memory-usage) - [Original Documentation](#original-documentation) @@ -270,24 +270,24 @@ AsyncMiddlewareFunction complexAuth([](AsyncWebServerRequest* request, ArMiddlew **Here are the list of available middlewares:** - `AsyncMiddlewareFunction`: can convert a lambda function (`ArMiddlewareCallback`) to a middleware -- `AuthenticationMiddleware`: to handle basic/digest authentication globally or per handler -- `AuthorizationMiddleware`: to handle authorization globally or per handler -- `CorsMiddleware`: to handle CORS preflight request globally or per handler -- `HeaderFilterMiddleware`: to filter out headers from the request -- `HeaderFreeMiddleware`: to only keep some headers from the request, and remove the others +- `AsyncAuthenticationMiddleware`: to handle basic/digest authentication globally or per handler +- `AsyncAuthorizationMiddleware`: to handle authorization globally or per handler +- `AsyncCorsMiddleware`: to handle CORS preflight request globally or per handler +- `AsyncHeaderFilterMiddleware`: to filter out headers from the request +- `AsyncHeaderFreeMiddleware`: to only keep some headers from the request, and remove the others - `LoggerMiddleware`: to log requests globally or per handler with the same pattern as curl. Will also record request processing time -- `RateLimitMiddleware`: to limit the number of requests on a windows of time globally or per handler +- `AsyncRateLimitMiddleware`: to limit the number of requests on a windows of time globally or per handler -## How to use authentication with AuthenticationMiddleware +## How to use authentication with AsyncAuthenticationMiddleware Do not use the `setUsername()` and `setPassword()` methods on the hanlders anymore. They are deprecated. These methods were causing a copy of the username and password for each handler, which is not efficient. -Now, you can use the `AuthenticationMiddleware` to handle authentication globally or per handler. +Now, you can use the `AsyncAuthenticationMiddleware` to handle authentication globally or per handler. ```c++ -AuthenticationMiddleware authMiddleware; +AsyncAuthenticationMiddleware authMiddleware; // [...] @@ -309,10 +309,10 @@ myHandler.addMiddleware(&authMiddleware); // add authentication to a specific ha ## Migration to Middleware to improve performance and memory usage -- `AsyncEventSource.authorizeConnect(...)` => do not use this method anymore: add a common `AuthorizationMiddleware` to the handler or server, and make sure to add it AFTER the `AuthenticationMiddleware` if you use authentication. -- `AsyncWebHandler.setAuthentication(...)` => do not use this method anymore: add a common `AuthenticationMiddleware` to the handler or server +- `AsyncEventSource.authorizeConnect(...)` => do not use this method anymore: add a common `AsyncAuthorizationMiddleware` to the handler or server, and make sure to add it AFTER the `AsyncAuthenticationMiddleware` if you use authentication. +- `AsyncWebHandler.setAuthentication(...)` => do not use this method anymore: add a common `AsyncAuthenticationMiddleware` to the handler or server - `ArUploadHandlerFunction` and `ArBodyHandlerFunction` => these callbacks receiving body data and upload and not calling anymore the authentication code for performance reasons. - These callbacks can be called multiple times during request parsing, so this is up to the user to now call the `AuthenticationMiddleware.allowed(request)` if needed and ideally when the method is called for the first time. + These callbacks can be called multiple times during request parsing, so this is up to the user to now call the `AsyncAuthenticationMiddleware.allowed(request)` if needed and ideally when the method is called for the first time. These callbacks are also not triggering the whole middleware chain since they are not part of the request processing workflow (they are not the final handler). diff --git a/docs/index.md b/docs/index.md index 5fd384b..971bd00 100644 --- a/docs/index.md +++ b/docs/index.md @@ -22,7 +22,7 @@ This fork is based on [yubox-node-org/ESPAsyncWebServer](https://github.com/yubo - [`AsyncWebSocketMessageBuffer` and `makeBuffer()`](#asyncwebsocketmessagebuffer-and-makebuffer) - [How to replace a response](#how-to-replace-a-response) - [How to use Middleware](#how-to-use-middleware) -- [How to use authentication with AuthenticationMiddleware](#how-to-use-authentication-with-authenticationmiddleware) +- [How to use authentication with AsyncAuthenticationMiddleware](#how-to-use-authentication-with-authenticationmiddleware) - [Migration to Middleware to improve performance and memory usage](#migration-to-middleware-to-improve-performance-and-memory-usage) - [Original Documentation](#original-documentation) @@ -270,24 +270,24 @@ AsyncMiddlewareFunction complexAuth([](AsyncWebServerRequest* request, ArMiddlew **Here are the list of available middlewares:** - `AsyncMiddlewareFunction`: can convert a lambda function (`ArMiddlewareCallback`) to a middleware -- `AuthenticationMiddleware`: to handle basic/digest authentication globally or per handler -- `AuthorizationMiddleware`: to handle authorization globally or per handler -- `CorsMiddleware`: to handle CORS preflight request globally or per handler -- `HeaderFilterMiddleware`: to filter out headers from the request -- `HeaderFreeMiddleware`: to only keep some headers from the request, and remove the others +- `AsyncAuthenticationMiddleware`: to handle basic/digest authentication globally or per handler +- `AsyncAuthorizationMiddleware`: to handle authorization globally or per handler +- `AsyncCorsMiddleware`: to handle CORS preflight request globally or per handler +- `AsyncHeaderFilterMiddleware`: to filter out headers from the request +- `AsyncHeaderFreeMiddleware`: to only keep some headers from the request, and remove the others - `LoggerMiddleware`: to log requests globally or per handler with the same pattern as curl. Will also record request processing time -- `RateLimitMiddleware`: to limit the number of requests on a windows of time globally or per handler +- `AsyncRateLimitMiddleware`: to limit the number of requests on a windows of time globally or per handler -## How to use authentication with AuthenticationMiddleware +## How to use authentication with AsyncAuthenticationMiddleware Do not use the `setUsername()` and `setPassword()` methods on the hanlders anymore. They are deprecated. These methods were causing a copy of the username and password for each handler, which is not efficient. -Now, you can use the `AuthenticationMiddleware` to handle authentication globally or per handler. +Now, you can use the `AsyncAuthenticationMiddleware` to handle authentication globally or per handler. ```c++ -AuthenticationMiddleware authMiddleware; +AsyncAuthenticationMiddleware authMiddleware; // [...] @@ -309,10 +309,10 @@ myHandler.addMiddleware(&authMiddleware); // add authentication to a specific ha ## Migration to Middleware to improve performance and memory usage -- `AsyncEventSource.authorizeConnect(...)` => do not use this method anymore: add a common `AuthorizationMiddleware` to the handler or server, and make sure to add it AFTER the `AuthenticationMiddleware` if you use authentication. -- `AsyncWebHandler.setAuthentication(...)` => do not use this method anymore: add a common `AuthenticationMiddleware` to the handler or server +- `AsyncEventSource.authorizeConnect(...)` => do not use this method anymore: add a common `AsyncAuthorizationMiddleware` to the handler or server, and make sure to add it AFTER the `AsyncAuthenticationMiddleware` if you use authentication. +- `AsyncWebHandler.setAuthentication(...)` => do not use this method anymore: add a common `AsyncAuthenticationMiddleware` to the handler or server - `ArUploadHandlerFunction` and `ArBodyHandlerFunction` => these callbacks receiving body data and upload and not calling anymore the authentication code for performance reasons. - These callbacks can be called multiple times during request parsing, so this is up to the user to now call the `AuthenticationMiddleware.allowed(request)` if needed and ideally when the method is called for the first time. + These callbacks can be called multiple times during request parsing, so this is up to the user to now call the `AsyncAuthenticationMiddleware.allowed(request)` if needed and ideally when the method is called for the first time. These callbacks are also not triggering the whole middleware chain since they are not part of the request processing workflow (they are not the final handler). diff --git a/examples/SimpleServer/SimpleServer.ino b/examples/SimpleServer/SimpleServer.ino index c8d74a5..8a2ccfe 100644 --- a/examples/SimpleServer/SimpleServer.ino +++ b/examples/SimpleServer/SimpleServer.ino @@ -110,27 +110,27 @@ AsyncWebSocket ws("/ws"); ///////////////////////////////////////////////////////////////////////////////////////////////////// // log incoming requests -LoggingMiddleware requestLogger; +AsyncLoggingMiddleware requestLogger; // CORS -CorsMiddleware cors; +AsyncCorsMiddleware cors; // maximum 5 requests per 10 seconds -RateLimitMiddleware rateLimit; +AsyncRateLimitMiddleware rateLimit; // filter out specific headers from the incoming request -HeaderFilterMiddleware headerFilter; +AsyncHeaderFilterMiddleware headerFilter; // remove all headers from the incoming request except the ones provided in the constructor -HeaderFreeMiddleware headerFree; +AsyncHeaderFreeMiddleware headerFree; // basicAuth -AuthenticationMiddleware basicAuth; -AuthenticationMiddleware basicAuthHash; +AsyncAuthenticationMiddleware basicAuth; +AsyncAuthenticationMiddleware basicAuthHash; // simple digest authentication -AuthenticationMiddleware digestAuth; -AuthenticationMiddleware digestAuthHash; +AsyncAuthenticationMiddleware digestAuth; +AsyncAuthenticationMiddleware digestAuthHash; // complex authentication which adds request attributes for the next middlewares and handler AsyncMiddlewareFunction complexAuth([](AsyncWebServerRequest* request, ArMiddlewareNext next) { @@ -145,7 +145,7 @@ AsyncMiddlewareFunction complexAuth([](AsyncWebServerRequest* request, ArMiddlew request->getResponse()->addHeader("X-Rate-Limit", "200"); }); -AuthorizationMiddleware authz([](AsyncWebServerRequest* request) { return request->getAttribute("role") == "staff"; }); +AsyncAuthorizationMiddleware authz([](AsyncWebServerRequest* request) { return request->getAttribute("role") == "staff"; }); int wsClients = 0; diff --git a/src/AsyncEventSource.cpp b/src/AsyncEventSource.cpp index c06cb8f..874faa0 100644 --- a/src/AsyncEventSource.cpp +++ b/src/AsyncEventSource.cpp @@ -332,7 +332,7 @@ void AsyncEventSourceClient::set_max_inflight_bytes(size_t value) { /* AsyncEventSource */ void AsyncEventSource::authorizeConnect(ArAuthorizeConnectHandler cb) { - AuthorizationMiddleware* m = new AuthorizationMiddleware(401, cb); + AsyncAuthorizationMiddleware* m = new AsyncAuthorizationMiddleware(401, cb); m->_freeOnRemoval = true; addMiddleware(m); } diff --git a/src/ESPAsyncWebServer.h b/src/ESPAsyncWebServer.h index 214f631..2fbff6b 100644 --- a/src/ESPAsyncWebServer.h +++ b/src/ESPAsyncWebServer.h @@ -285,12 +285,12 @@ class AsyncWebServerRequest { void setHandler(AsyncWebHandler* handler) { _handler = handler; } #ifndef ESP8266 - [[deprecated("All headers are now collected. Use removeHeader(name) or HeaderFreeMiddleware if you really need to free some headers.")]] + [[deprecated("All headers are now collected. Use removeHeader(name) or AsyncHeaderFreeMiddleware if you really need to free some headers.")]] #endif void addInterestingHeader(__unused const char* name) { } #ifndef ESP8266 - [[deprecated("All headers are now collected. Use removeHeader(name) or HeaderFreeMiddleware if you really need to free some headers.")]] + [[deprecated("All headers are now collected. Use removeHeader(name) or AsyncHeaderFreeMiddleware if you really need to free some headers.")]] #endif void addInterestingHeader(__unused const String& name) { } @@ -557,8 +557,8 @@ class AsyncMiddlewareChain { std::list _middlewares; }; -// AuthenticationMiddleware is a middleware that checks if the request is authenticated -class AuthenticationMiddleware : public AsyncMiddleware { +// AsyncAuthenticationMiddleware is a middleware that checks if the request is authenticated +class AsyncAuthenticationMiddleware : public AsyncMiddleware { public: void setUsername(const char* username); void setPassword(const char* password); @@ -601,11 +601,11 @@ class AuthenticationMiddleware : public AsyncMiddleware { }; using ArAuthorizeFunction = std::function; -// AuthorizationMiddleware is a middleware that checks if the request is authorized -class AuthorizationMiddleware : public AsyncMiddleware { +// AsyncAuthorizationMiddleware is a middleware that checks if the request is authorized +class AsyncAuthorizationMiddleware : public AsyncMiddleware { public: - AuthorizationMiddleware(ArAuthorizeFunction authorizeConnectHandler) : _code(403), _authz(authorizeConnectHandler) {} - AuthorizationMiddleware(int code, ArAuthorizeFunction authorizeConnectHandler) : _code(code), _authz(authorizeConnectHandler) {} + AsyncAuthorizationMiddleware(ArAuthorizeFunction authorizeConnectHandler) : _code(403), _authz(authorizeConnectHandler) {} + AsyncAuthorizationMiddleware(int code, ArAuthorizeFunction authorizeConnectHandler) : _code(code), _authz(authorizeConnectHandler) {} void run(AsyncWebServerRequest* request, ArMiddlewareNext next) { return _authz && !_authz(request) ? request->send(_code) : next(); } @@ -615,7 +615,7 @@ class AuthorizationMiddleware : public AsyncMiddleware { }; // remove all headers from the incoming request except the ones provided in the constructor -class HeaderFreeMiddleware : public AsyncMiddleware { +class AsyncHeaderFreeMiddleware : public AsyncMiddleware { public: void keep(const char* name) { _toKeep.push_back(name); } void unKeep(const char* name) { _toKeep.erase(std::remove(_toKeep.begin(), _toKeep.end(), name), _toKeep.end()); } @@ -627,7 +627,7 @@ class HeaderFreeMiddleware : public AsyncMiddleware { }; // filter out specific headers from the incoming request -class HeaderFilterMiddleware : public AsyncMiddleware { +class AsyncHeaderFilterMiddleware : public AsyncMiddleware { public: void filter(const char* name) { _toRemove.push_back(name); } void unFilter(const char* name) { _toRemove.erase(std::remove(_toRemove.begin(), _toRemove.end(), name), _toRemove.end()); } @@ -639,7 +639,7 @@ class HeaderFilterMiddleware : public AsyncMiddleware { }; // curl-like logging of incoming requests -class LoggingMiddleware : public AsyncMiddleware { +class AsyncLoggingMiddleware : public AsyncMiddleware { public: void setOutput(Print& output) { _out = &output; } void setEnabled(bool enabled) { _enabled = enabled; } @@ -653,7 +653,7 @@ class LoggingMiddleware : public AsyncMiddleware { }; // CORS Middleware -class CorsMiddleware : public AsyncMiddleware { +class AsyncCorsMiddleware : public AsyncMiddleware { public: void setOrigin(const char* origin) { _origin = origin; } void setMethods(const char* methods) { _methods = methods; } @@ -674,7 +674,7 @@ class CorsMiddleware : public AsyncMiddleware { }; // Rate limit Middleware -class RateLimitMiddleware : public AsyncMiddleware { +class AsyncRateLimitMiddleware : public AsyncMiddleware { public: void setMaxRequests(size_t maxRequests) { _maxRequests = maxRequests; } void setWindowSize(uint32_t seconds) { _windowSizeMillis = seconds * 1000; } @@ -727,7 +727,7 @@ class AsyncWebRewrite { class AsyncWebHandler : public AsyncMiddlewareChain { protected: ArRequestFilterFunction _filter = nullptr; - AuthenticationMiddleware* _authMiddleware = nullptr; + AsyncAuthenticationMiddleware* _authMiddleware = nullptr; public: AsyncWebHandler() {} diff --git a/src/Middleware.cpp b/src/Middleware.cpp index 78cdfc8..1eb8e50 100644 --- a/src/Middleware.cpp +++ b/src/Middleware.cpp @@ -53,24 +53,24 @@ void AsyncMiddlewareChain::_runChain(AsyncWebServerRequest* request, ArMiddlewar return next(); } -void AuthenticationMiddleware::setUsername(const char* username) { +void AsyncAuthenticationMiddleware::setUsername(const char* username) { _username = username; _hasCreds = _username.length() && _credentials.length(); } -void AuthenticationMiddleware::setPassword(const char* password) { +void AsyncAuthenticationMiddleware::setPassword(const char* password) { _credentials = password; _hash = false; _hasCreds = _username.length() && _credentials.length(); } -void AuthenticationMiddleware::setPasswordHash(const char* hash) { +void AsyncAuthenticationMiddleware::setPasswordHash(const char* hash) { _credentials = hash; _hash = _credentials.length(); _hasCreds = _username.length() && _credentials.length(); } -bool AuthenticationMiddleware::generateHash() { +bool AsyncAuthenticationMiddleware::generateHash() { // ensure we have all the necessary data if (!_hasCreds) return false; @@ -95,7 +95,7 @@ bool AuthenticationMiddleware::generateHash() { } } -bool AuthenticationMiddleware::allowed(AsyncWebServerRequest* request) const { +bool AsyncAuthenticationMiddleware::allowed(AsyncWebServerRequest* request) const { if (_authMethod == AsyncAuthType::AUTH_NONE) return true; @@ -108,11 +108,11 @@ bool AuthenticationMiddleware::allowed(AsyncWebServerRequest* request) const { return request->authenticate(_username.c_str(), _credentials.c_str(), _realm.c_str(), _hash); } -void AuthenticationMiddleware::run(AsyncWebServerRequest* request, ArMiddlewareNext next) { +void AsyncAuthenticationMiddleware::run(AsyncWebServerRequest* request, ArMiddlewareNext next) { return allowed(request) ? next() : request->requestAuthentication(_authMethod, _realm.c_str(), _authFailMsg.c_str()); } -void HeaderFreeMiddleware::run(AsyncWebServerRequest* request, ArMiddlewareNext next) { +void AsyncHeaderFreeMiddleware::run(AsyncWebServerRequest* request, ArMiddlewareNext next) { std::vector reqHeaders; request->getHeaderNames(reqHeaders); for (const char* h : reqHeaders) { @@ -130,13 +130,13 @@ void HeaderFreeMiddleware::run(AsyncWebServerRequest* request, ArMiddlewareNext next(); } -void HeaderFilterMiddleware::run(AsyncWebServerRequest* request, ArMiddlewareNext next) { +void AsyncHeaderFilterMiddleware::run(AsyncWebServerRequest* request, ArMiddlewareNext next) { for (auto it = _toRemove.begin(); it != _toRemove.end(); ++it) request->removeHeader(*it); next(); } -void LoggingMiddleware::run(AsyncWebServerRequest* request, ArMiddlewareNext next) { +void AsyncLoggingMiddleware::run(AsyncWebServerRequest* request, ArMiddlewareNext next) { if (!isEnabled()) { next(); return; @@ -194,7 +194,7 @@ void LoggingMiddleware::run(AsyncWebServerRequest* request, ArMiddlewareNext nex } } -void CorsMiddleware::addCORSHeaders(AsyncWebServerResponse* response) { +void AsyncCorsMiddleware::addCORSHeaders(AsyncWebServerResponse* response) { response->addHeader(asyncsrv::T_CORS_ACAO, _origin.c_str()); response->addHeader(asyncsrv::T_CORS_ACAM, _methods.c_str()); response->addHeader(asyncsrv::T_CORS_ACAH, _headers.c_str()); @@ -202,7 +202,7 @@ void CorsMiddleware::addCORSHeaders(AsyncWebServerResponse* response) { response->addHeader(asyncsrv::T_CORS_ACMA, String(_maxAge).c_str()); } -void CorsMiddleware::run(AsyncWebServerRequest* request, ArMiddlewareNext next) { +void AsyncCorsMiddleware::run(AsyncWebServerRequest* request, ArMiddlewareNext next) { // Origin header ? => CORS handling if (request->hasHeader(asyncsrv::T_CORS_O)) { // check if this is a preflight request => handle it and return @@ -226,7 +226,7 @@ void CorsMiddleware::run(AsyncWebServerRequest* request, ArMiddlewareNext next) } } -bool RateLimitMiddleware::isRequestAllowed(uint32_t& retryAfterSeconds) { +bool AsyncRateLimitMiddleware::isRequestAllowed(uint32_t& retryAfterSeconds) { uint32_t now = millis(); while (!_requestTimes.empty() && _requestTimes.front() <= now - _windowSizeMillis) @@ -244,7 +244,7 @@ bool RateLimitMiddleware::isRequestAllowed(uint32_t& retryAfterSeconds) { return true; } -void RateLimitMiddleware::run(AsyncWebServerRequest* request, ArMiddlewareNext next) { +void AsyncRateLimitMiddleware::run(AsyncWebServerRequest* request, ArMiddlewareNext next) { uint32_t retryAfterSeconds; if (isRequestAllowed(retryAfterSeconds)) { next(); diff --git a/src/WebHandlers.cpp b/src/WebHandlers.cpp index 67fcac8..44a4601 100644 --- a/src/WebHandlers.cpp +++ b/src/WebHandlers.cpp @@ -29,7 +29,7 @@ AsyncWebHandler& AsyncWebHandler::setFilter(ArRequestFilterFunction fn) { } AsyncWebHandler& AsyncWebHandler::setAuthentication(const char* username, const char* password, AsyncAuthType authMethod) { if (!_authMiddleware) { - _authMiddleware = new AuthenticationMiddleware(); + _authMiddleware = new AsyncAuthenticationMiddleware(); _authMiddleware->_freeOnRemoval = true; addMiddleware(_authMiddleware); }