1
0
mirror of https://github.com/esp8266/Arduino.git synced 2025-06-28 05:01:28 +03:00

Implemented support for filters and removable routes in ESP8266WebServer (#9152)

* feat: added filters and removeable routes

* Update Filters.ino

* fix: clang-format

* chore: updated docs

* chore: updated doc

* fix: use new implementation

* fix: filters.ino example

* fix: filters.ino

* fix: formatting

* fix: formatting (2)
This commit is contained in:
Ayush Sharma
2024-06-15 23:50:13 +05:30
committed by GitHub
parent 685f2c97ff
commit 9afeaf5694
7 changed files with 317 additions and 30 deletions

View File

@ -230,18 +230,61 @@ void ESP8266WebServerTemplate<ServerType>::requestAuthentication(HTTPAuthMethod
}
template <typename ServerType>
void ESP8266WebServerTemplate<ServerType>::on(const Uri &uri, ESP8266WebServerTemplate<ServerType>::THandlerFunction handler) {
on(uri, HTTP_ANY, handler);
RequestHandler<ServerType>& ESP8266WebServerTemplate<ServerType>::on(const Uri &uri, ESP8266WebServerTemplate<ServerType>::THandlerFunction handler) {
return on(uri, HTTP_ANY, handler);
}
template <typename ServerType>
void ESP8266WebServerTemplate<ServerType>::on(const Uri &uri, HTTPMethod method, ESP8266WebServerTemplate<ServerType>::THandlerFunction fn) {
on(uri, method, fn, _fileUploadHandler);
RequestHandler<ServerType>& ESP8266WebServerTemplate<ServerType>::on(const Uri &uri, HTTPMethod method, ESP8266WebServerTemplate<ServerType>::THandlerFunction fn) {
return on(uri, method, fn, _fileUploadHandler);
}
template <typename ServerType>
void ESP8266WebServerTemplate<ServerType>::on(const Uri &uri, HTTPMethod method, ESP8266WebServerTemplate<ServerType>::THandlerFunction fn, ESP8266WebServerTemplate<ServerType>::THandlerFunction ufn) {
_addRequestHandler(new FunctionRequestHandler<ServerType>(fn, ufn, uri, method));
RequestHandler<ServerType>& ESP8266WebServerTemplate<ServerType>::on(const Uri &uri, HTTPMethod method, ESP8266WebServerTemplate<ServerType>::THandlerFunction fn, ESP8266WebServerTemplate<ServerType>::THandlerFunction ufn) {
RequestHandler<ServerType> *handler = new FunctionRequestHandler<ServerType>(fn, ufn, uri, method);
_addRequestHandler(handler);
return *handler;
}
template <typename ServerType>
bool ESP8266WebServerTemplate<ServerType>::removeRoute(const char *uri) {
return removeRoute(String(uri), HTTP_ANY);
}
template <typename ServerType>
bool ESP8266WebServerTemplate<ServerType>::removeRoute(const char *uri, HTTPMethod method) {
return removeRoute(String(uri), method);
}
template <typename ServerType>
bool ESP8266WebServerTemplate<ServerType>::removeRoute(const String &uri) {
return removeRoute(uri, HTTP_ANY);
}
template <typename ServerType>
bool ESP8266WebServerTemplate<ServerType>::removeRoute(const String &uri, HTTPMethod method) {
bool anyHandlerRemoved = false;
RequestHandlerType *handler = _firstHandler;
RequestHandlerType *previousHandler = nullptr;
while (handler) {
if (handler->canHandle(method, uri)) {
if (_removeRequestHandler(handler)) {
anyHandlerRemoved = true;
// Move to the next handler
if (previousHandler) {
handler = previousHandler->next();
} else {
handler = _firstHandler;
}
continue;
}
}
previousHandler = handler;
handler = handler->next();
}
return anyHandlerRemoved;
}
template <typename ServerType>
@ -249,6 +292,11 @@ void ESP8266WebServerTemplate<ServerType>::addHandler(RequestHandlerType* handle
_addRequestHandler(handler);
}
template <typename ServerType>
bool ESP8266WebServerTemplate<ServerType>::removeHandler(RequestHandlerType *handler) {
return _removeRequestHandler(handler);
}
template <typename ServerType>
void ESP8266WebServerTemplate<ServerType>::_addRequestHandler(RequestHandlerType* handler) {
if (!_lastHandler) {
@ -261,6 +309,33 @@ void ESP8266WebServerTemplate<ServerType>::_addRequestHandler(RequestHandlerType
}
}
template <typename ServerType>
bool ESP8266WebServerTemplate<ServerType>::_removeRequestHandler(RequestHandlerType *handler) {
RequestHandlerType *current = _firstHandler;
RequestHandlerType *previous = nullptr;
while (current != nullptr) {
if (current == handler) {
if (previous == nullptr) {
_firstHandler = current->next();
} else {
previous->next(current->next());
}
if (current == _lastHandler) {
_lastHandler = previous;
}
// Delete 'matching' handler
delete current;
return true;
}
previous = current;
current = current->next();
}
return false;
}
template <typename ServerType>
void ESP8266WebServerTemplate<ServerType>::serveStatic(const char* uri, FS& fs, const char* path, const char* cache_header) {
bool is_file = false;

View File

@ -116,11 +116,17 @@ public:
typedef std::function<void(void)> THandlerFunction;
typedef std::function<String(FS &fs, const String &fName)> ETagFunction;
typedef std::function<bool(ESP8266WebServerTemplate<ServerType> &server)> FilterFunction;
void on(const Uri &uri, THandlerFunction handler);
void on(const Uri &uri, HTTPMethod method, THandlerFunction fn);
void on(const Uri &uri, HTTPMethod method, THandlerFunction fn, THandlerFunction ufn);
RequestHandler<ServerType>& on(const Uri &uri, THandlerFunction handler);
RequestHandler<ServerType>& on(const Uri &uri, HTTPMethod method, THandlerFunction fn);
RequestHandler<ServerType>& on(const Uri &uri, HTTPMethod method, THandlerFunction fn, THandlerFunction ufn);
bool removeRoute(const char *uri);
bool removeRoute(const char *uri, HTTPMethod method);
bool removeRoute(const String &uri);
bool removeRoute(const String &uri, HTTPMethod method);
void addHandler(RequestHandlerType* handler);
bool removeHandler(RequestHandlerType* handler);
void serveStatic(const char* uri, fs::FS& fs, const char* path, const char* cache_header = NULL );
void onNotFound(THandlerFunction fn); //called when handler is not assigned
void onFileUpload(THandlerFunction fn); //handle file uploads
@ -306,6 +312,7 @@ public:
protected:
void _addRequestHandler(RequestHandlerType* handler);
bool _removeRequestHandler(RequestHandlerType *handler);
void _handleRequest();
void _finalizeResponse();
ClientFuture _parseRequest(ClientType& client);

View File

@ -106,7 +106,7 @@ typename ESP8266WebServerTemplate<ServerType>::ClientFuture ESP8266WebServerTemp
//attach handler
RequestHandlerType* handler;
for (handler = _firstHandler; handler; handler = handler->next()) {
if (handler->canHandle(_currentMethod, _currentUri))
if (handler->canHandle(*this, _currentMethod, _currentUri))
break;
}
_currentHandler = handler;
@ -324,7 +324,7 @@ int ESP8266WebServerTemplate<ServerType>::_parseArgumentsPrivate(const String& d
template <typename ServerType>
void ESP8266WebServerTemplate<ServerType>::_uploadWriteByte(uint8_t b){
if (_currentUpload->currentSize == HTTP_UPLOAD_BUFLEN){
if(_currentHandler && _currentHandler->canUpload(_currentUri))
if(_currentHandler && _currentHandler->canUpload(*this, _currentUri))
_currentHandler->upload(*this, _currentUri, *_currentUpload);
_currentUpload->totalSize += _currentUpload->currentSize;
_currentUpload->currentSize = 0;
@ -425,7 +425,7 @@ bool ESP8266WebServerTemplate<ServerType>::_parseForm(ClientType& client, const
_currentUpload->currentSize = 0;
_currentUpload->contentLength = len;
DBGWS("Start File: %s Type: %s\n", _currentUpload->filename.c_str(), _currentUpload->type.c_str());
if(_currentHandler && _currentHandler->canUpload(_currentUri))
if(_currentHandler && _currentHandler->canUpload(*this, _currentUri))
_currentHandler->upload(*this, _currentUri, *_currentUpload);
_currentUpload->status = UPLOAD_FILE_WRITE;
@ -463,11 +463,11 @@ bool ESP8266WebServerTemplate<ServerType>::_parseForm(ClientType& client, const
}
}
// Found the boundary string, finish processing this file upload
if (_currentHandler && _currentHandler->canUpload(_currentUri))
if (_currentHandler && _currentHandler->canUpload(*this, _currentUri))
_currentHandler->upload(*this, _currentUri, *_currentUpload);
_currentUpload->totalSize += _currentUpload->currentSize;
_currentUpload->status = UPLOAD_FILE_END;
if (_currentHandler && _currentHandler->canUpload(_currentUri))
if (_currentHandler && _currentHandler->canUpload(*this, _currentUri))
_currentHandler->upload(*this, _currentUri, *_currentUpload);
DBGWS("End File: %s Type: %s Size: %d\n",
_currentUpload->filename.c_str(),
@ -542,7 +542,7 @@ String ESP8266WebServerTemplate<ServerType>::urlDecode(const String& text)
template <typename ServerType>
bool ESP8266WebServerTemplate<ServerType>::_parseFormUploadAborted(){
_currentUpload->status = UPLOAD_FILE_ABORTED;
if(_currentHandler && _currentHandler->canUpload(_currentUri))
if(_currentHandler && _currentHandler->canUpload(*this, _currentUri))
_currentHandler->upload(*this, _currentUri, *_currentUpload);
return false;
}

View File

@ -12,13 +12,60 @@ class RequestHandler {
using WebServerType = ESP8266WebServerTemplate<ServerType>;
public:
virtual ~RequestHandler() { }
virtual bool canHandle(HTTPMethod method, const String& uri) { (void) method; (void) uri; return false; }
virtual bool canUpload(const String& uri) { (void) uri; return false; }
virtual bool handle(WebServerType& server, HTTPMethod requestMethod, const String& requestUri) { (void) server; (void) requestMethod; (void) requestUri; return false; }
virtual void upload(WebServerType& server, const String& requestUri, HTTPUpload& upload) { (void) server; (void) requestUri; (void) upload; }
RequestHandler<ServerType>* next() { return _next; }
void next(RequestHandler<ServerType>* r) { _next = r; }
/*
note: old handler API for backward compatibility
*/
virtual bool canHandle(HTTPMethod method, const String& uri) {
(void) method;
(void) uri;
return false;
}
virtual bool canUpload(const String& uri) {
(void) uri;
return false;
}
/*
note: new handler API with support for filters etc.
*/
virtual bool canHandle(WebServerType& server, HTTPMethod method, const String& uri) {
(void) server;
(void) method;
(void) uri;
return false;
}
virtual bool canUpload(WebServerType& server, const String& uri) {
(void) server;
(void) uri;
return false;
}
virtual bool handle(WebServerType& server, HTTPMethod requestMethod, const String& requestUri) {
(void) server;
(void) requestMethod;
(void) requestUri;
return false;
}
virtual void upload(WebServerType& server, const String& requestUri, HTTPUpload& upload) {
(void) server;
(void) requestUri;
(void) upload;
}
RequestHandler<ServerType>* next() {
return _next;
}
void next(RequestHandler<ServerType>* r) {
_next = r;
}
virtual RequestHandler<ServerType>& setFilter(std::function<bool(ESP8266WebServerTemplate<ServerType>&)> filter) {
(void)filter;
return *this;
}
private:
RequestHandler<ServerType>* _next = nullptr;

View File

@ -59,9 +59,22 @@ public:
return true;
}
bool canHandle(WebServerType& server, HTTPMethod requestMethod, const String& requestUri) override {
if (_method != HTTP_ANY && _method != requestMethod)
return false;
return _uri->canHandle(requestUri, RequestHandler<ServerType>::pathArgs) && (_filter != NULL ? _filter(server) : true);
}
bool canUpload(WebServerType& server, const String& requestUri) override {
if (!_ufn || !canHandle(server, HTTP_POST, requestUri))
return false;
return true;
}
bool handle(WebServerType& server, HTTPMethod requestMethod, const String& requestUri) override {
(void) server;
if (!canHandle(requestMethod, requestUri))
if (!canHandle(server, requestMethod, requestUri))
return false;
_fn();
@ -69,15 +82,22 @@ public:
}
void upload(WebServerType& server, const String& requestUri, HTTPUpload& upload) override {
(void) server;
(void) upload;
if (canUpload(requestUri))
if (canUpload(server, requestUri))
_ufn();
}
FunctionRequestHandler& setFilter(typename WebServerType::FilterFunction filter) {
_filter = filter;
return *this;
}
protected:
typename WebServerType::THandlerFunction _fn;
typename WebServerType::THandlerFunction _ufn;
// _filter should return 'true' when the request should be handled
// and 'false' when the request should be ignored
typename WebServerType::FilterFunction _filter;
Uri *_uri;
HTTPMethod _method;
};
@ -115,7 +135,6 @@ protected:
// serve all files within a given directory
template<typename ServerType>
class StaticDirectoryRequestHandler : public StaticRequestHandler<ServerType> {
using SRH = StaticRequestHandler<ServerType>;
using WebServerType = ESP8266WebServerTemplate<ServerType>;
@ -130,9 +149,12 @@ public:
return SRH::validMethod(requestMethod) && requestUri.startsWith(SRH::_uri);
}
bool handle(WebServerType& server, HTTPMethod requestMethod, const String& requestUri) override {
bool canHandle(WebServerType& server, HTTPMethod requestMethod, const String& requestUri) override {
return SRH::validMethod(requestMethod) && requestUri.startsWith(SRH::_uri) && (_filter != NULL ? _filter(server) : true);
}
if (!canHandle(requestMethod, requestUri))
bool handle(WebServerType& server, HTTPMethod requestMethod, const String& requestUri) override {
if (!canHandle(server, requestMethod, requestUri))
return false;
DEBUGV("DirectoryRequestHandler::handle: request=%s _uri=%s\r\n", requestUri.c_str(), SRH::_uri.c_str());
@ -203,8 +225,14 @@ public:
return true;
}
StaticDirectoryRequestHandler& setFilter(typename WebServerType::FilterFunction filter) {
_filter = filter;
return *this;
}
protected:
size_t _baseUriLength;
typename WebServerType::FilterFunction _filter;
};
@ -228,8 +256,12 @@ public:
return SRH::validMethod(requestMethod) && requestUri == SRH::_uri;
}
bool canHandle(WebServerType& server, HTTPMethod requestMethod, const String& requestUri) override {
return SRH::validMethod(requestMethod) && requestUri == SRH::_uri && (_filter != NULL ? _filter(server) : true);
}
bool handle(WebServerType& server, HTTPMethod requestMethod, const String & requestUri) override {
if (!canHandle(requestMethod, requestUri))
if (!canHandle(server, requestMethod, requestUri))
return false;
if (server._eTagEnabled) {
@ -266,8 +298,14 @@ public:
return true;
}
StaticFileRequestHandler& setFilter(typename WebServerType::FilterFunction filter) {
_filter = filter;
return *this;
}
protected:
String _eTagCode; // ETag code calculated for this file as used in http header include quotes.
typename WebServerType::FilterFunction _filter;
};
} // namespace