(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() {}
bool canHandle(__unused AsyncWebServerRequest* request) {
// request->addInterestingHeader("ANY");
return true;
}

View File

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

View File

@@ -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;
}

View File

@@ -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;
}

View File

@@ -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;
}

View File

@@ -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;
}

View File

@@ -192,7 +192,6 @@ class AsyncWebServerRequest {
AsyncWebServer* _server;
AsyncWebHandler* _handler;
AsyncWebServerResponse* _response;
std::vector<String> _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<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
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 + "/")))
return false;
request->addInterestingHeader("ANY");
return true;
}

View File

@@ -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) {

View File

@@ -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);

View File

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