From b4460a2a706ec4ec2a5bacb872d5603c4fa5009a Mon Sep 17 00:00:00 2001 From: Mathieu Carbou Date: Mon, 9 Sep 2024 17:03:27 +0200 Subject: [PATCH] (perf) Remove interesting headers to fasten request processing All headers are already parsed: interesting headers allowed to cleanup parsed headers to only keep interesting ones during request processing. Removing "interesting headers" support will keep these parsed headers in heap memory during request processing before being freed at the end of the request. If you really need to cleanup some headers to get more heap space during request processing, use a middleware and removeHeadersExcept(names) to remove some. --- examples/CaptivePortal/CaptivePortal.ino | 1 - examples/Filters/Filters.ino | 1 - src/AsyncEventSource.cpp | 2 - src/AsyncJson.h | 1 - src/AsyncMessagePack.h | 1 - src/AsyncWebSocket.cpp | 7 --- src/ESPAsyncWebServer.h | 67 ++++++++++++++++++++---- src/WebHandlerImpl.h | 1 - src/WebHandlers.cpp | 14 +---- src/WebRequest.cpp | 22 -------- src/WebServer.cpp | 1 - 11 files changed, 59 insertions(+), 59 deletions(-) diff --git a/examples/CaptivePortal/CaptivePortal.ino b/examples/CaptivePortal/CaptivePortal.ino index 2cc5851..ed9dfff 100644 --- a/examples/CaptivePortal/CaptivePortal.ino +++ b/examples/CaptivePortal/CaptivePortal.ino @@ -20,7 +20,6 @@ class CaptiveRequestHandler : public AsyncWebHandler { virtual ~CaptiveRequestHandler() {} bool canHandle(__unused AsyncWebServerRequest* request) { - // request->addInterestingHeader("ANY"); return true; } diff --git a/examples/Filters/Filters.ino b/examples/Filters/Filters.ino index b7bbcff..de5129a 100644 --- a/examples/Filters/Filters.ino +++ b/examples/Filters/Filters.ino @@ -22,7 +22,6 @@ class CaptiveRequestHandler : public AsyncWebHandler { virtual ~CaptiveRequestHandler() {} bool canHandle(__unused AsyncWebServerRequest* request) { - // request->addInterestingHeader("ANY"); return true; } diff --git a/src/AsyncEventSource.cpp b/src/AsyncEventSource.cpp index 7e370ec..60c7429 100644 --- a/src/AsyncEventSource.cpp +++ b/src/AsyncEventSource.cpp @@ -374,8 +374,6 @@ bool AsyncEventSource::canHandle(AsyncWebServerRequest* request) { if (request->method() != HTTP_GET || !request->url().equals(_url)) { return false; } - request->addInterestingHeader(T_Last_Event_ID); - request->addInterestingHeader(T_Cookie); return true; } diff --git a/src/AsyncJson.h b/src/AsyncJson.h index bca3f24..42a2dc1 100644 --- a/src/AsyncJson.h +++ b/src/AsyncJson.h @@ -198,7 +198,6 @@ class AsyncCallbackJsonWebHandler : public AsyncWebHandler { if (request_method != HTTP_GET && !request->contentType().equalsIgnoreCase(JSON_MIMETYPE)) return false; - request->addInterestingHeader("ANY"); return true; } diff --git a/src/AsyncMessagePack.h b/src/AsyncMessagePack.h index 57a8824..7fe7278 100644 --- a/src/AsyncMessagePack.h +++ b/src/AsyncMessagePack.h @@ -97,7 +97,6 @@ class AsyncCallbackMessagePackWebHandler : public AsyncWebHandler { if (request_method != HTTP_GET && !request->contentType().equalsIgnoreCase(asyncsrv::T_application_msgpack)) return false; - request->addInterestingHeader("ANY"); return true; } diff --git a/src/AsyncWebSocket.cpp b/src/AsyncWebSocket.cpp index 0b87cef..9ef0b5f 100644 --- a/src/AsyncWebSocket.cpp +++ b/src/AsyncWebSocket.cpp @@ -1078,13 +1078,6 @@ bool AsyncWebSocket::canHandle(AsyncWebServerRequest* request) { if (request->method() != HTTP_GET || !request->url().equals(_url) || !request->isExpectedRequestedConnType(RCT_WS)) return false; - request->addInterestingHeader(WS_STR_CONNECTION); - request->addInterestingHeader(WS_STR_UPGRADE); - request->addInterestingHeader(WS_STR_ORIGIN); - request->addInterestingHeader(WS_STR_COOKIE); - request->addInterestingHeader(WS_STR_VERSION); - request->addInterestingHeader(WS_STR_KEY); - request->addInterestingHeader(WS_STR_PROTOCOL); return true; } diff --git a/src/ESPAsyncWebServer.h b/src/ESPAsyncWebServer.h index fe8e4c9..0fce863 100644 --- a/src/ESPAsyncWebServer.h +++ b/src/ESPAsyncWebServer.h @@ -192,7 +192,6 @@ class AsyncWebServerRequest { AsyncWebServer* _server; AsyncWebHandler* _handler; AsyncWebServerResponse* _response; - std::vector _interestingHeaders; ArDisconnectHandler _onDisconnectfn; String _temp; @@ -206,7 +205,6 @@ class AsyncWebServerRequest { String _boundary; String _authorization; RequestedConnectionType _reqconntype; - void _removeNotInterestingHeaders(); bool _isDigest; bool _isMultipart; bool _isPlainPost; @@ -289,13 +287,16 @@ class AsyncWebServerRequest { void setHandler(AsyncWebHandler* handler) { _handler = handler; } - /** - * @brief add header to collect from a response - * - * @param name - */ - void addInterestingHeader(const char* name); - void addInterestingHeader(const String& name) { return addInterestingHeader(name.c_str()); }; +#ifndef ESP8266 + [[deprecated("All headers are now collected. Use removeHeadersExcept(name) if you really need to free some headers.")]] +#endif + void addInterestingHeader(__unused const char* name) { + } +#ifndef ESP8266 + [[deprecated("All headers are now collected. Use removeHeadersExcept(name) if you really need to free some headers.")]] +#endif + void addInterestingHeader(__unused const String& name) { + } /** * @brief issue 302 redirect response @@ -411,6 +412,54 @@ class AsyncWebServerRequest { const AsyncWebHeader* getHeader(const __FlashStringHelper* data) const; #endif const AsyncWebHeader* getHeader(size_t num) const; + size_t getHeaderNames(std::vector& names) const { + names.clear(); + const size_t size = _headers.size(); + names.reserve(size); + for (const auto& h : _headers) { + names.push_back(h.name().c_str()); + } + return size; + } + const std::list& getHeaders() const { return _headers; } + // Remove a header from the request. + // It will free the memory and prevent the header to be seen during request processing. + bool removeHeader(const char* name) { + const size_t size = _headers.size(); + _headers.remove_if([&name](const AsyncWebHeader& header) { return header.name().equalsIgnoreCase(name); }); + return size != _headers.size(); + } + // Remove all request headers. + void removeHeaders() { _headers.clear(); } + // Remove all request headers with the given names. + void removeHeaders(std::vector& namesToRemove) { + for (const char* name : namesToRemove) + removeHeader(name); + } + void removeHeaders(const char* names...) { + va_list args; + va_start(args, names); + for (const char* name = names; name != NULL; name = va_arg(args, const char*)) + removeHeader(name); + va_end(args); + } + void removeHeadersExcept(std::vector& namesToKeep) { + _headers.remove_if([&namesToKeep](const AsyncWebHeader& header) { + for (const char* name : namesToKeep) + if (header.name().equalsIgnoreCase(name)) + return false; + return true; + }); + } + void removeHeadersExcept(const char* names...) { + va_list args; + va_start(args, names); + std::vector namesToKeep; + for (const char* name = names; name != NULL; name = va_arg(args, const char*)) + namesToKeep.push_back(name); + va_end(args); + removeHeadersExcept(namesToKeep); + } size_t params() const; // get arguments count bool hasParam(const char* name, bool post = false, bool file = false) const; diff --git a/src/WebHandlerImpl.h b/src/WebHandlerImpl.h index b07e013..8ee2a65 100644 --- a/src/WebHandlerImpl.h +++ b/src/WebHandlerImpl.h @@ -125,7 +125,6 @@ class AsyncCallbackWebHandler : public AsyncWebHandler { } else if (_uri.length() && (_uri != request->url() && !request->url().startsWith(_uri + "/"))) return false; - request->addInterestingHeader("ANY"); return true; } diff --git a/src/WebHandlers.cpp b/src/WebHandlers.cpp index d904a39..b87db7f 100644 --- a/src/WebHandlers.cpp +++ b/src/WebHandlers.cpp @@ -23,7 +23,6 @@ using namespace asyncsrv; - AsyncStaticWebHandler::AsyncStaticWebHandler(const char* uri, FS& fs, const char* path, const char* cache_control) : _fs(fs), _uri(uri), _path(path), _default_file(F("index.htm")), _cache_control(cache_control), _last_modified(), _callback(nullptr) { // Ensure leading '/' @@ -94,18 +93,7 @@ bool AsyncStaticWebHandler::canHandle(AsyncWebServerRequest* request) { if (request->method() != HTTP_GET || !request->url().startsWith(_uri) || !request->isExpectedRequestedConnType(RCT_DEFAULT, RCT_HTTP)) { return false; } - if (_getFile(request)) { - // We interested in "If-Modified-Since" header to check if file was modified - if (_last_modified.length()) - request->addInterestingHeader(F("If-Modified-Since")); - - if (_cache_control.length()) - request->addInterestingHeader(F("If-None-Match")); - - return true; - } - - return false; + return _getFile(request); } bool AsyncStaticWebHandler::_getFile(AsyncWebServerRequest* request) { diff --git a/src/WebRequest.cpp b/src/WebRequest.cpp index 022911e..da17d7a 100644 --- a/src/WebRequest.cpp +++ b/src/WebRequest.cpp @@ -49,8 +49,6 @@ AsyncWebServerRequest::~AsyncWebServerRequest() { _pathParams.clear(); - _interestingHeaders.clear(); - if (_response != NULL) { delete _response; } @@ -152,20 +150,6 @@ void AsyncWebServerRequest::_onData(void* buf, size_t len) { } } -void AsyncWebServerRequest::_removeNotInterestingHeaders() { - if (std::any_of(std::begin(_interestingHeaders), std::end(_interestingHeaders), [](const String& str) { return str.equalsIgnoreCase(T_ANY); })) - return; // nothing to do - - for (auto iter = std::begin(_headers); iter != std::end(_headers);) { - const auto name = iter->name(); - - if (std::none_of(std::begin(_interestingHeaders), std::end(_interestingHeaders), [&name](const String& str) { return str.equalsIgnoreCase(name); })) - iter = _headers.erase(iter); - else - iter++; - } -} - void AsyncWebServerRequest::_onPoll() { // os_printf("p\n"); if (_response != NULL && _client != NULL && _client->canSend()) { @@ -583,7 +567,6 @@ void AsyncWebServerRequest::_parseLine() { // end of headers _server->_rewriteRequest(this); _server->_attachHandler(this); - _removeNotInterestingHeaders(); if (_expectingContinue) { String response(T_HTTP_100_CONT); _client->write(response.c_str(), response.length()); @@ -683,11 +666,6 @@ const AsyncWebParameter* AsyncWebServerRequest::getParam(size_t num) const { return &(*std::next(_params.cbegin(), num)); } -void AsyncWebServerRequest::addInterestingHeader(const char* name) { - if (std::none_of(std::begin(_interestingHeaders), std::end(_interestingHeaders), [&name](const String& str) { return str.equalsIgnoreCase(name); })) - _interestingHeaders.emplace_back(name); -} - AsyncWebServerResponse* AsyncWebServerRequest::beginResponse(int code, const char* contentType, const char* content, AwsTemplateProcessor callback) { if (callback) return new AsyncProgmemResponse(code, contentType, (const uint8_t*)content, strlen(content), callback); diff --git a/src/WebServer.cpp b/src/WebServer.cpp index 58fdf60..06fad78 100644 --- a/src/WebServer.cpp +++ b/src/WebServer.cpp @@ -155,7 +155,6 @@ void AsyncWebServer::_attachHandler(AsyncWebServerRequest* request) { } } - request->addInterestingHeader(T_ANY); request->setHandler(_catchAllHandler); }