Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: Implemented support for filters and removable routes in WebServer #2225

Merged
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
100 changes: 100 additions & 0 deletions libraries/WebServer/examples/Filters/Filters.ino
Original file line number Diff line number Diff line change
@@ -0,0 +1,100 @@
#include <WiFi.h>
#include <WiFiClient.h>
#include <WebServer.h>
#include <LEAmDNS.h>

// Your STA WiFi Credentials
// ( This is the AP your RP2040 will connect to )
const char *ssid = "........";
const char *password = "........";

// Your AP WiFi Credentials
// ( This is the AP your RP2040 will broadcast )
const char *ap_ssid = "RP2040_Demo";
const char *ap_password = "";

WebServer server(80);

const int led = LED_BUILTIN;

// ON_STA_FILTER - Only accept requests coming from STA interface
bool ON_STA_FILTER(HTTPServer &server) {
return WiFi.localIP() == server.client().localIP();
}

// ON_AP_FILTER - Only accept requests coming from AP interface
bool ON_AP_FILTER(HTTPServer &server) {
return WiFi.softAPIP() == 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("picow")) {
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();
MDNS.update();
}
81 changes: 75 additions & 6 deletions libraries/WebServer/src/HTTPServer.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -207,22 +207,65 @@ void HTTPServer::requestAuthentication(HTTPAuthMethod mode, const char* realm, c
send(401, String(FPSTR(mimeTable[html].mimeType)), authFailMsg);
}

void HTTPServer::on(const Uri &uri, HTTPServer::THandlerFunction handler) {
on(uri, HTTP_ANY, handler);
RequestHandler& HTTPServer::on(const Uri &uri, HTTPServer::THandlerFunction handler) {
return on(uri, HTTP_ANY, handler);
}

void HTTPServer::on(const Uri &uri, HTTPMethod method, HTTPServer::THandlerFunction fn) {
on(uri, method, fn, _fileUploadHandler);
RequestHandler& HTTPServer::on(const Uri &uri, HTTPMethod method, HTTPServer::THandlerFunction fn) {
return on(uri, method, fn, _fileUploadHandler);
}

void HTTPServer::on(const Uri &uri, HTTPMethod method, HTTPServer::THandlerFunction fn, HTTPServer::THandlerFunction ufn) {
_addRequestHandler(new FunctionRequestHandler(fn, ufn, uri, method));
RequestHandler& HTTPServer::on(const Uri &uri, HTTPMethod method, HTTPServer::THandlerFunction fn, HTTPServer::THandlerFunction ufn) {
FunctionRequestHandler *handler = new FunctionRequestHandler(fn, ufn, uri, method);
_addRequestHandler(handler);
return *handler;
}

bool HTTPServer::removeRoute(const char *uri) {
return removeRoute(String(uri), HTTP_ANY);
}

bool HTTPServer::removeRoute(const char *uri, HTTPMethod method) {
return removeRoute(String(uri), method);
}

bool HTTPServer::removeRoute(const String &uri) {
return removeRoute(uri, HTTP_ANY);
}

bool HTTPServer::removeRoute(const String &uri, HTTPMethod method) {
bool anyHandlerRemoved = false;
RequestHandler *handler = _firstHandler;
RequestHandler *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;
}

void HTTPServer::addHandler(RequestHandler* handler) {
_addRequestHandler(handler);
}

bool HTTPServer::removeHandler(RequestHandler *handler) {
return _removeRequestHandler(handler);
}

void HTTPServer::_addRequestHandler(RequestHandler* handler) {
if (!_lastHandler) {
_firstHandler = handler;
Expand All @@ -233,6 +276,32 @@ void HTTPServer::_addRequestHandler(RequestHandler* handler) {
}
}

bool HTTPServer::_removeRequestHandler(RequestHandler *handler) {
RequestHandler *current = _firstHandler;
RequestHandler *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;
}

void HTTPServer::serveStatic(const char* uri, FS& fs, const char* path, const char* cache_header) {
_addRequestHandler(new StaticRequestHandler(fs, path, uri, cache_header));
}
Expand Down
16 changes: 13 additions & 3 deletions libraries/WebServer/src/HTTPServer.h
Original file line number Diff line number Diff line change
Expand Up @@ -95,10 +95,16 @@ class HTTPServer {
void requestAuthentication(HTTPAuthMethod mode = BASIC_AUTH, const char* realm = nullptr, 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(HTTPServer &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);
bool removeRoute(const String &uri, HTTPMethod method);
void addHandler(RequestHandler* handler);
bool removeHandler(RequestHandler *handler);
void serveStatic(const char* uri, fs::FS& fs, const char* path, const char* cache_header = nullptr);
void onNotFound(THandlerFunction fn); //called when handler is not assigned
void onFileUpload(THandlerFunction ufn); //handle file uploads
Expand All @@ -109,6 +115,9 @@ class HTTPServer {
HTTPMethod method() {
return _currentMethod;
}
WiFiClient& client() {
return *_currentClient;
}
HTTPUpload& upload() {
return *_currentUpload;
}
Expand Down Expand Up @@ -230,6 +239,7 @@ class HTTPServer {
return _currentClient->write(b, l);
}
void _addRequestHandler(RequestHandler* handler);
bool _removeRequestHandler(RequestHandler *handler);
void _handleRequest();
void _finalizeResponse();
ClientFuture _parseRequest(WiFiClient* client);
Expand Down
14 changes: 7 additions & 7 deletions libraries/WebServer/src/Parsing.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -136,7 +136,7 @@ HTTPServer::ClientFuture HTTPServer::_parseRequest(WiFiClient* client) {
//attach handler
RequestHandler* handler;
for (handler = _firstHandler; handler; handler = handler->next()) {
if (handler->canHandle(_currentMethod, _currentUri)) {
if (handler->canHandle(*this, _currentMethod, _currentUri)) {
break;
}
}
Expand Down Expand Up @@ -188,7 +188,7 @@ HTTPServer::ClientFuture HTTPServer::_parseRequest(WiFiClient* 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;
Expand Down Expand Up @@ -347,7 +347,7 @@ void HTTPServer::_parseArguments(String data) {

void HTTPServer::_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;
Expand Down Expand Up @@ -462,7 +462,7 @@ bool HTTPServer::_parseForm(WiFiClient * 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;
Expand Down Expand Up @@ -501,12 +501,12 @@ bool HTTPServer::_parseForm(WiFiClient * 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);
Expand Down Expand Up @@ -580,7 +580,7 @@ String HTTPServer::urlDecode(const String & text) {

bool HTTPServer::_parseFormUploadAborted() {
_currentUpload->status = UPLOAD_FILE_ABORTED;
if (_currentHandler && _currentHandler->canUpload(_currentUri)) {
if (_currentHandler && _currentHandler->canUpload(*this, _currentUri)) {
_currentHandler->upload(*this, _currentUri, *_currentUpload);
}
return false;
Expand Down
39 changes: 35 additions & 4 deletions libraries/WebServer/src/detail/RequestHandler.h
Original file line number Diff line number Diff line change
Expand Up @@ -6,17 +6,43 @@
class RequestHandler {
public:
virtual ~RequestHandler() { }

/*
note: old handler API for backward compatibility
*/

virtual bool canHandle(HTTPMethod method, String uri) {
(void) method;
(void) uri;
(void)method;
(void)uri;
return false;
}
virtual bool canUpload(String uri) {
(void) uri;
(void)uri;
return false;
}
virtual bool canRaw(String uri) {
(void) uri;
(void)uri;
return false;
}

/*
note: new handler API with support for filters etc.
*/

virtual bool canHandle(HTTPServer &server, HTTPMethod method, String uri) {
(void)server;
(void)method;
(void)uri;
return false;
}
virtual bool canUpload(HTTPServer &server, String uri) {
(void)server;
(void)uri;
return false;
}
virtual bool canRaw(HTTPServer &server, String uri) {
(void)server;
(void)uri;
return false;
}
virtual bool handle(HTTPServer& server, HTTPMethod requestMethod, String requestUri) {
Expand All @@ -43,6 +69,11 @@ class RequestHandler {
_next = r;
}

virtual RequestHandler& setFilter(std::function<bool(HTTPServer&)> filter) {
(void)filter;
return *this;
}

private:
RequestHandler* _next = nullptr;

Expand Down
Loading