feat: added support for filters in WebServer library (#9842)
* feat: added support for filters in webserver * feat: add setFilter function in StaticRequestHandler * fix: ON_STA_FILTER & ON_AP_FILTER * fix: make request handlers backward compatible * fix: ON_STA_FILTER & ON_AP_FILTER * fix: more filters to their own example * chore: grammar * fix: remove filters from header file * fix: use same root route for both interfaces * ci(pre-commit): Apply automatic fixes --------- Co-authored-by: pre-commit-ci-lite[bot] <117423508+pre-commit-ci-lite[bot]@users.noreply.github.com>
This commit is contained in:
parent
1d895e58e7
commit
3428eb6a9e
7 changed files with 226 additions and 23 deletions
110
libraries/WebServer/examples/Filters/Filters.ino
Normal file
110
libraries/WebServer/examples/Filters/Filters.ino
Normal file
|
|
@ -0,0 +1,110 @@
|
|||
#include <WiFi.h>
|
||||
#include <NetworkClient.h>
|
||||
#include <WebServer.h>
|
||||
#include <ESPmDNS.h>
|
||||
|
||||
// Your STA WiFi Credentials
|
||||
// ( This is the AP your ESP will connect to )
|
||||
const char *ssid = "........";
|
||||
const char *password = "........";
|
||||
|
||||
// Your AP WiFi Credentials
|
||||
// ( This is the AP your ESP will broadcast )
|
||||
const char *ap_ssid = "ESP32_Demo";
|
||||
const char *ap_password = "";
|
||||
|
||||
WebServer server(80);
|
||||
|
||||
const int led = 13;
|
||||
|
||||
// ON_STA_FILTER - Only accept requests coming from STA interface
|
||||
bool ON_STA_FILTER(WebServer &server) {
|
||||
return WiFi.STA.hasIP() && WiFi.STA.localIP() == server.client().localIP();
|
||||
}
|
||||
|
||||
// ON_AP_FILTER - Only accept requests coming from AP interface
|
||||
bool ON_AP_FILTER(WebServer &server) {
|
||||
return WiFi.AP.hasIP() && WiFi.AP.localIP() == server.client().localIP();
|
||||
}
|
||||
|
||||
void handleNotFound() {
|
||||
digitalWrite(led, 1);
|
||||
String message = "File Not Found\n\n";
|
||||
message += "URI: ";
|
||||
message += server.uri();
|
||||
message += "\nMethod: ";
|
||||
message += (server.method() == HTTP_GET) ? "GET" : "POST";
|
||||
message += "\nArguments: ";
|
||||
message += server.args();
|
||||
message += "\n";
|
||||
for (uint8_t i = 0; i < server.args(); i++) {
|
||||
message += " " + server.argName(i) + ": " + server.arg(i) + "\n";
|
||||
}
|
||||
server.send(404, "text/plain", message);
|
||||
digitalWrite(led, 0);
|
||||
}
|
||||
|
||||
void setup(void) {
|
||||
pinMode(led, OUTPUT);
|
||||
digitalWrite(led, 0);
|
||||
Serial.begin(115200);
|
||||
WiFi.mode(WIFI_AP_STA);
|
||||
// Connect to STA
|
||||
WiFi.begin(ssid, password);
|
||||
// Start AP
|
||||
WiFi.softAP(ap_ssid, ap_password);
|
||||
Serial.println("");
|
||||
|
||||
// Wait for connection
|
||||
while (WiFi.status() != WL_CONNECTED) {
|
||||
delay(500);
|
||||
Serial.print(".");
|
||||
}
|
||||
Serial.println("");
|
||||
Serial.print("Connected to ");
|
||||
Serial.println(ssid);
|
||||
Serial.print("IP address: ");
|
||||
Serial.println(WiFi.localIP());
|
||||
|
||||
if (MDNS.begin("esp32")) {
|
||||
Serial.println("MDNS responder started");
|
||||
}
|
||||
|
||||
// This route will be accessible by STA clients only
|
||||
server
|
||||
.on(
|
||||
"/",
|
||||
[&]() {
|
||||
digitalWrite(led, 1);
|
||||
server.send(200, "text/plain", "Hi!, This route is accessible for STA clients only");
|
||||
digitalWrite(led, 0);
|
||||
}
|
||||
)
|
||||
.setFilter(ON_STA_FILTER);
|
||||
|
||||
// This route will be accessible by AP clients only
|
||||
server
|
||||
.on(
|
||||
"/",
|
||||
[&]() {
|
||||
digitalWrite(led, 1);
|
||||
server.send(200, "text/plain", "Hi!, This route is accessible for AP clients only");
|
||||
digitalWrite(led, 0);
|
||||
}
|
||||
)
|
||||
.setFilter(ON_AP_FILTER);
|
||||
|
||||
server.on("/inline", []() {
|
||||
server.send(200, "text/plain", "this works as well");
|
||||
});
|
||||
|
||||
server.onNotFound(handleNotFound);
|
||||
|
||||
server.begin();
|
||||
Serial.println("HTTP server started");
|
||||
}
|
||||
|
||||
void loop(void) {
|
||||
server.handleClient();
|
||||
delay(2); //allow the cpu to switch to other tasks
|
||||
}
|
||||
5
libraries/WebServer/examples/Filters/ci.json
Normal file
5
libraries/WebServer/examples/Filters/ci.json
Normal file
|
|
@ -0,0 +1,5 @@
|
|||
{
|
||||
"targets": {
|
||||
"esp32h2": false
|
||||
}
|
||||
}
|
||||
|
|
@ -124,7 +124,7 @@ bool WebServer::_parseRequest(NetworkClient &client) {
|
|||
//attach handler
|
||||
RequestHandler *handler;
|
||||
for (handler = _firstHandler; handler; handler = handler->next()) {
|
||||
if (handler->canHandle(_currentMethod, _currentUri)) {
|
||||
if (handler->canHandle(*this, _currentMethod, _currentUri)) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
|
@ -176,7 +176,7 @@ bool WebServer::_parseRequest(NetworkClient &client) {
|
|||
}
|
||||
}
|
||||
|
||||
if (!isForm && _currentHandler && _currentHandler->canRaw(_currentUri)) {
|
||||
if (!isForm && _currentHandler && _currentHandler->canRaw(*this, _currentUri)) {
|
||||
log_v("Parse raw");
|
||||
_currentRaw.reset(new HTTPRaw());
|
||||
_currentRaw->status = RAW_START;
|
||||
|
|
@ -334,7 +334,7 @@ void WebServer::_parseArguments(String data) {
|
|||
|
||||
void WebServer::_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;
|
||||
|
|
@ -449,7 +449,7 @@ bool WebServer::_parseForm(NetworkClient &client, String boundary, uint32_t len)
|
|||
_currentUpload->totalSize = 0;
|
||||
_currentUpload->currentSize = 0;
|
||||
log_v("Start File: %s Type: %s", _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;
|
||||
|
|
@ -488,12 +488,12 @@ bool WebServer::_parseForm(NetworkClient &client, String boundary, uint32_t len)
|
|||
}
|
||||
}
|
||||
// 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);
|
||||
}
|
||||
log_v("End File: %s Type: %s Size: %d", _currentUpload->filename.c_str(), _currentUpload->type.c_str(), (int)_currentUpload->totalSize);
|
||||
|
|
@ -567,7 +567,7 @@ String WebServer::urlDecode(const String &text) {
|
|||
|
||||
bool WebServer::_parseFormUploadAborted() {
|
||||
_currentUpload->status = UPLOAD_FILE_ABORTED;
|
||||
if (_currentHandler && _currentHandler->canUpload(_currentUri)) {
|
||||
if (_currentHandler && _currentHandler->canUpload(*this, _currentUri)) {
|
||||
_currentHandler->upload(*this, _currentUri, *_currentUpload);
|
||||
}
|
||||
return false;
|
||||
|
|
|
|||
|
|
@ -306,16 +306,18 @@ void WebServer::requestAuthentication(HTTPAuthMethod mode, const char *realm, co
|
|||
send(401, String(FPSTR(mimeTable[html].mimeType)), authFailMsg);
|
||||
}
|
||||
|
||||
void WebServer::on(const Uri &uri, WebServer::THandlerFunction handler) {
|
||||
on(uri, HTTP_ANY, handler);
|
||||
RequestHandler &WebServer::on(const Uri &uri, WebServer::THandlerFunction handler) {
|
||||
return on(uri, HTTP_ANY, handler);
|
||||
}
|
||||
|
||||
void WebServer::on(const Uri &uri, HTTPMethod method, WebServer::THandlerFunction fn) {
|
||||
on(uri, method, fn, _fileUploadHandler);
|
||||
RequestHandler &WebServer::on(const Uri &uri, HTTPMethod method, WebServer::THandlerFunction fn) {
|
||||
return on(uri, method, fn, _fileUploadHandler);
|
||||
}
|
||||
|
||||
void WebServer::on(const Uri &uri, HTTPMethod method, WebServer::THandlerFunction fn, WebServer::THandlerFunction ufn) {
|
||||
_addRequestHandler(new FunctionRequestHandler(fn, ufn, uri, method));
|
||||
RequestHandler &WebServer::on(const Uri &uri, HTTPMethod method, WebServer::THandlerFunction fn, WebServer::THandlerFunction ufn) {
|
||||
FunctionRequestHandler *handler = new FunctionRequestHandler(fn, ufn, uri, method);
|
||||
_addRequestHandler(handler);
|
||||
return *handler;
|
||||
}
|
||||
|
||||
bool WebServer::removeRoute(const char *uri) {
|
||||
|
|
|
|||
|
|
@ -144,9 +144,10 @@ public:
|
|||
void requestAuthentication(HTTPAuthMethod mode = BASIC_AUTH, const char *realm = NULL, const String &authFailMsg = String(""));
|
||||
|
||||
typedef std::function<void(void)> THandlerFunction;
|
||||
void on(const Uri &uri, THandlerFunction fn);
|
||||
void on(const Uri &uri, HTTPMethod method, THandlerFunction fn);
|
||||
void on(const Uri &uri, HTTPMethod method, THandlerFunction fn, THandlerFunction ufn); //ufn handles file uploads
|
||||
typedef std::function<bool(WebServer &server)> FilterFunction;
|
||||
RequestHandler &on(const Uri &uri, THandlerFunction fn);
|
||||
RequestHandler &on(const Uri &uri, HTTPMethod method, THandlerFunction fn);
|
||||
RequestHandler &on(const Uri &uri, HTTPMethod method, THandlerFunction fn, THandlerFunction ufn); //ufn handles file uploads
|
||||
bool removeRoute(const char *uri);
|
||||
bool removeRoute(const char *uri, HTTPMethod method);
|
||||
bool removeRoute(const String &uri);
|
||||
|
|
|
|||
|
|
@ -7,6 +7,11 @@
|
|||
class RequestHandler {
|
||||
public:
|
||||
virtual ~RequestHandler() {}
|
||||
|
||||
/*
|
||||
note: old handler API for backward compatibility
|
||||
*/
|
||||
|
||||
virtual bool canHandle(HTTPMethod method, String uri) {
|
||||
(void)method;
|
||||
(void)uri;
|
||||
|
|
@ -20,6 +25,27 @@ public:
|
|||
(void)uri;
|
||||
return false;
|
||||
}
|
||||
|
||||
/*
|
||||
note: new handler API with support for filters etc.
|
||||
*/
|
||||
|
||||
virtual bool canHandle(WebServer &server, HTTPMethod method, String uri) {
|
||||
(void)server;
|
||||
(void)method;
|
||||
(void)uri;
|
||||
return false;
|
||||
}
|
||||
virtual bool canUpload(WebServer &server, String uri) {
|
||||
(void)server;
|
||||
(void)uri;
|
||||
return false;
|
||||
}
|
||||
virtual bool canRaw(WebServer &server, String uri) {
|
||||
(void)server;
|
||||
(void)uri;
|
||||
return false;
|
||||
}
|
||||
virtual bool handle(WebServer &server, HTTPMethod requestMethod, String requestUri) {
|
||||
(void)server;
|
||||
(void)requestMethod;
|
||||
|
|
@ -37,6 +63,11 @@ public:
|
|||
(void)raw;
|
||||
}
|
||||
|
||||
virtual RequestHandler &setFilter(std::function<bool(WebServer &)> filter) {
|
||||
(void)filter;
|
||||
return *this;
|
||||
}
|
||||
|
||||
RequestHandler *next() {
|
||||
return _next;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -36,6 +36,7 @@ public:
|
|||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool canRaw(String requestUri) override {
|
||||
if (!_ufn || _method == HTTP_GET) {
|
||||
return false;
|
||||
|
|
@ -44,9 +45,32 @@ public:
|
|||
return true;
|
||||
}
|
||||
|
||||
bool canHandle(WebServer &server, HTTPMethod requestMethod, String requestUri) override {
|
||||
if (_method != HTTP_ANY && _method != requestMethod) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return _uri->canHandle(requestUri, pathArgs) && (_filter != NULL ? _filter(server) : true);
|
||||
}
|
||||
|
||||
bool canUpload(WebServer &server, String requestUri) override {
|
||||
if (!_ufn || !canHandle(server, HTTP_POST, requestUri)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool canRaw(WebServer &server, String requestUri) override {
|
||||
if (!_ufn || _method == HTTP_GET || (_filter != NULL ? _filter(server) == false : false)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool handle(WebServer &server, HTTPMethod requestMethod, String requestUri) override {
|
||||
(void)server;
|
||||
if (!canHandle(requestMethod, requestUri)) {
|
||||
if (!canHandle(server, requestMethod, requestUri)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
|
|
@ -55,24 +79,30 @@ public:
|
|||
}
|
||||
|
||||
void upload(WebServer &server, String requestUri, HTTPUpload &upload) override {
|
||||
(void)server;
|
||||
(void)upload;
|
||||
if (canUpload(requestUri)) {
|
||||
if (canUpload(server, requestUri)) {
|
||||
_ufn();
|
||||
}
|
||||
}
|
||||
|
||||
void raw(WebServer &server, String requestUri, HTTPRaw &raw) override {
|
||||
(void)server;
|
||||
(void)raw;
|
||||
if (canRaw(requestUri)) {
|
||||
if (canRaw(server, requestUri)) {
|
||||
_ufn();
|
||||
}
|
||||
}
|
||||
|
||||
FunctionRequestHandler &setFilter(WebServer::FilterFunction filter) {
|
||||
_filter = filter;
|
||||
return *this;
|
||||
}
|
||||
|
||||
protected:
|
||||
WebServer::THandlerFunction _fn;
|
||||
WebServer::THandlerFunction _ufn;
|
||||
// _filter should return 'true' when the request should be handled
|
||||
// and 'false' when the request should be ignored
|
||||
WebServer::FilterFunction _filter;
|
||||
Uri *_uri;
|
||||
HTTPMethod _method;
|
||||
};
|
||||
|
|
@ -100,8 +130,24 @@ public:
|
|||
return true;
|
||||
}
|
||||
|
||||
bool canHandle(WebServer &server, HTTPMethod requestMethod, String requestUri) override {
|
||||
if (requestMethod != HTTP_GET) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if ((_isFile && requestUri != _uri) || !requestUri.startsWith(_uri)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (_filter != NULL ? _filter(server) == false : false) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool handle(WebServer &server, HTTPMethod requestMethod, String requestUri) override {
|
||||
if (!canHandle(requestMethod, requestUri)) {
|
||||
if (!canHandle(server, requestMethod, requestUri)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
|
|
@ -197,7 +243,15 @@ public:
|
|||
return (result);
|
||||
} // calcETag
|
||||
|
||||
StaticRequestHandler &setFilter(WebServer::FilterFunction filter) {
|
||||
_filter = filter;
|
||||
return *this;
|
||||
}
|
||||
|
||||
protected:
|
||||
// _filter should return 'true' when the request should be handled
|
||||
// and 'false' when the request should be ignored
|
||||
WebServer::FilterFunction _filter;
|
||||
FS _fs;
|
||||
String _uri;
|
||||
String _path;
|
||||
|
|
|
|||
Loading…
Reference in a new issue