(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.
This commit is contained in:
Mathieu Carbou
2024-09-09 17:03:27 +02:00
parent 958f764c48
commit b4460a2a70
11 changed files with 59 additions and 59 deletions

View File

@@ -20,7 +20,6 @@ class CaptiveRequestHandler : public AsyncWebHandler {
virtual ~CaptiveRequestHandler() {} virtual ~CaptiveRequestHandler() {}
bool canHandle(__unused AsyncWebServerRequest* request) { bool canHandle(__unused AsyncWebServerRequest* request) {
// request->addInterestingHeader("ANY");
return true; return true;
} }

View File

@@ -22,7 +22,6 @@ class CaptiveRequestHandler : public AsyncWebHandler {
virtual ~CaptiveRequestHandler() {} virtual ~CaptiveRequestHandler() {}
bool canHandle(__unused AsyncWebServerRequest* request) { bool canHandle(__unused AsyncWebServerRequest* request) {
// request->addInterestingHeader("ANY");
return true; return true;
} }

View File

@@ -374,8 +374,6 @@ bool AsyncEventSource::canHandle(AsyncWebServerRequest* request) {
if (request->method() != HTTP_GET || !request->url().equals(_url)) { if (request->method() != HTTP_GET || !request->url().equals(_url)) {
return false; return false;
} }
request->addInterestingHeader(T_Last_Event_ID);
request->addInterestingHeader(T_Cookie);
return true; return true;
} }

View File

@@ -198,7 +198,6 @@ class AsyncCallbackJsonWebHandler : public AsyncWebHandler {
if (request_method != HTTP_GET && !request->contentType().equalsIgnoreCase(JSON_MIMETYPE)) if (request_method != HTTP_GET && !request->contentType().equalsIgnoreCase(JSON_MIMETYPE))
return false; return false;
request->addInterestingHeader("ANY");
return true; return true;
} }

View File

@@ -97,7 +97,6 @@ class AsyncCallbackMessagePackWebHandler : public AsyncWebHandler {
if (request_method != HTTP_GET && !request->contentType().equalsIgnoreCase(asyncsrv::T_application_msgpack)) if (request_method != HTTP_GET && !request->contentType().equalsIgnoreCase(asyncsrv::T_application_msgpack))
return false; return false;
request->addInterestingHeader("ANY");
return true; return true;
} }

View File

@@ -1078,13 +1078,6 @@ bool AsyncWebSocket::canHandle(AsyncWebServerRequest* request) {
if (request->method() != HTTP_GET || !request->url().equals(_url) || !request->isExpectedRequestedConnType(RCT_WS)) if (request->method() != HTTP_GET || !request->url().equals(_url) || !request->isExpectedRequestedConnType(RCT_WS))
return false; 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; return true;
} }

View File

@@ -192,7 +192,6 @@ class AsyncWebServerRequest {
AsyncWebServer* _server; AsyncWebServer* _server;
AsyncWebHandler* _handler; AsyncWebHandler* _handler;
AsyncWebServerResponse* _response; AsyncWebServerResponse* _response;
std::vector<String> _interestingHeaders;
ArDisconnectHandler _onDisconnectfn; ArDisconnectHandler _onDisconnectfn;
String _temp; String _temp;
@@ -206,7 +205,6 @@ class AsyncWebServerRequest {
String _boundary; String _boundary;
String _authorization; String _authorization;
RequestedConnectionType _reqconntype; RequestedConnectionType _reqconntype;
void _removeNotInterestingHeaders();
bool _isDigest; bool _isDigest;
bool _isMultipart; bool _isMultipart;
bool _isPlainPost; bool _isPlainPost;
@@ -289,13 +287,16 @@ class AsyncWebServerRequest {
void setHandler(AsyncWebHandler* handler) { _handler = handler; } void setHandler(AsyncWebHandler* handler) { _handler = handler; }
/** #ifndef ESP8266
* @brief add header to collect from a response [[deprecated("All headers are now collected. Use removeHeadersExcept(name) if you really need to free some headers.")]]
* #endif
* @param name void addInterestingHeader(__unused const char* name) {
*/ }
void addInterestingHeader(const char* name); #ifndef ESP8266
void addInterestingHeader(const String& name) { return addInterestingHeader(name.c_str()); }; [[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 * @brief issue 302 redirect response
@@ -411,6 +412,54 @@ class AsyncWebServerRequest {
const AsyncWebHeader* getHeader(const __FlashStringHelper* data) const; const AsyncWebHeader* getHeader(const __FlashStringHelper* data) const;
#endif #endif
const AsyncWebHeader* getHeader(size_t num) const; const AsyncWebHeader* getHeader(size_t num) const;
size_t getHeaderNames(std::vector<const char*>& 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<AsyncWebHeader>& 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<const char*>& 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<const char*>& 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<const char*> 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 size_t params() const; // get arguments count
bool hasParam(const char* name, bool post = false, bool file = false) const; bool hasParam(const char* name, bool post = false, bool file = false) const;

View File

@@ -125,7 +125,6 @@ class AsyncCallbackWebHandler : public AsyncWebHandler {
} else if (_uri.length() && (_uri != request->url() && !request->url().startsWith(_uri + "/"))) } else if (_uri.length() && (_uri != request->url() && !request->url().startsWith(_uri + "/")))
return false; return false;
request->addInterestingHeader("ANY");
return true; return true;
} }

View File

@@ -23,7 +23,6 @@
using namespace asyncsrv; using namespace asyncsrv;
AsyncStaticWebHandler::AsyncStaticWebHandler(const char* uri, FS& fs, const char* path, const char* cache_control) 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) { : _fs(fs), _uri(uri), _path(path), _default_file(F("index.htm")), _cache_control(cache_control), _last_modified(), _callback(nullptr) {
// Ensure leading '/' // 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)) { if (request->method() != HTTP_GET || !request->url().startsWith(_uri) || !request->isExpectedRequestedConnType(RCT_DEFAULT, RCT_HTTP)) {
return false; return false;
} }
if (_getFile(request)) { return _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;
} }
bool AsyncStaticWebHandler::_getFile(AsyncWebServerRequest* request) { bool AsyncStaticWebHandler::_getFile(AsyncWebServerRequest* request) {

View File

@@ -49,8 +49,6 @@ AsyncWebServerRequest::~AsyncWebServerRequest() {
_pathParams.clear(); _pathParams.clear();
_interestingHeaders.clear();
if (_response != NULL) { if (_response != NULL) {
delete _response; 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() { void AsyncWebServerRequest::_onPoll() {
// os_printf("p\n"); // os_printf("p\n");
if (_response != NULL && _client != NULL && _client->canSend()) { if (_response != NULL && _client != NULL && _client->canSend()) {
@@ -583,7 +567,6 @@ void AsyncWebServerRequest::_parseLine() {
// end of headers // end of headers
_server->_rewriteRequest(this); _server->_rewriteRequest(this);
_server->_attachHandler(this); _server->_attachHandler(this);
_removeNotInterestingHeaders();
if (_expectingContinue) { if (_expectingContinue) {
String response(T_HTTP_100_CONT); String response(T_HTTP_100_CONT);
_client->write(response.c_str(), response.length()); _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)); 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) { AsyncWebServerResponse* AsyncWebServerRequest::beginResponse(int code, const char* contentType, const char* content, AwsTemplateProcessor callback) {
if (callback) if (callback)
return new AsyncProgmemResponse(code, contentType, (const uint8_t*)content, strlen(content), callback); return new AsyncProgmemResponse(code, contentType, (const uint8_t*)content, strlen(content), callback);

View File

@@ -155,7 +155,6 @@ void AsyncWebServer::_attachHandler(AsyncWebServerRequest* request) {
} }
} }
request->addInterestingHeader(T_ANY);
request->setHandler(_catchAllHandler); request->setHandler(_catchAllHandler);
} }