mirror of
https://github.com/me-no-dev/ESPAsyncWebServer.git
synced 2025-10-01 00:30:54 +02:00
(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:
@@ -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;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -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;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -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;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -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;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -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;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -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;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -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;
|
||||||
|
@@ -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;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -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) {
|
||||||
|
@@ -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);
|
||||||
|
@@ -155,7 +155,6 @@ void AsyncWebServer::_attachHandler(AsyncWebServerRequest* request) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
request->addInterestingHeader(T_ANY);
|
|
||||||
request->setHandler(_catchAllHandler);
|
request->setHandler(_catchAllHandler);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Reference in New Issue
Block a user