Skip to content

Commit 1775fed

Browse files
Webserver: Add support for filters and removable routes (#2225)
This PR implements filters and removable routes in RP2040 arduino core, making it API compatible with recent changes to ESP32 & ESP8266 WebServer API.
1 parent 4ab0ba6 commit 1775fed

File tree

6 files changed

+289
-26
lines changed

6 files changed

+289
-26
lines changed
Lines changed: 100 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,100 @@
1+
#include <WiFi.h>
2+
#include <WiFiClient.h>
3+
#include <WebServer.h>
4+
#include <LEAmDNS.h>
5+
6+
// Your STA WiFi Credentials
7+
// ( This is the AP your RP2040 will connect to )
8+
const char *ssid = "........";
9+
const char *password = "........";
10+
11+
// Your AP WiFi Credentials
12+
// ( This is the AP your RP2040 will broadcast )
13+
const char *ap_ssid = "RP2040_Demo";
14+
const char *ap_password = "";
15+
16+
WebServer server(80);
17+
18+
const int led = LED_BUILTIN;
19+
20+
// ON_STA_FILTER - Only accept requests coming from STA interface
21+
bool ON_STA_FILTER(HTTPServer &server) {
22+
return WiFi.localIP() == server.client().localIP();
23+
}
24+
25+
// ON_AP_FILTER - Only accept requests coming from AP interface
26+
bool ON_AP_FILTER(HTTPServer &server) {
27+
return WiFi.softAPIP() == server.client().localIP();
28+
}
29+
30+
void handleNotFound() {
31+
digitalWrite(led, 1);
32+
String message = "File Not Found\n\n";
33+
message += "URI: ";
34+
message += server.uri();
35+
message += "\nMethod: ";
36+
message += (server.method() == HTTP_GET) ? "GET" : "POST";
37+
message += "\nArguments: ";
38+
message += server.args();
39+
message += "\n";
40+
for (uint8_t i = 0; i < server.args(); i++) {
41+
message += " " + server.argName(i) + ": " + server.arg(i) + "\n";
42+
}
43+
server.send(404, "text/plain", message);
44+
digitalWrite(led, 0);
45+
}
46+
47+
void setup(void) {
48+
pinMode(led, OUTPUT);
49+
digitalWrite(led, 0);
50+
Serial.begin(115200);
51+
WiFi.mode(WIFI_AP_STA);
52+
// Connect to STA
53+
WiFi.begin(ssid, password);
54+
// Start AP
55+
WiFi.softAP(ap_ssid, ap_password);
56+
Serial.println("");
57+
58+
// Wait for connection
59+
while (WiFi.status() != WL_CONNECTED) {
60+
delay(500);
61+
Serial.print(".");
62+
}
63+
Serial.println("");
64+
Serial.print("Connected to ");
65+
Serial.println(ssid);
66+
Serial.print("IP address: ");
67+
Serial.println(WiFi.localIP());
68+
69+
if (MDNS.begin("picow")) {
70+
Serial.println("MDNS responder started");
71+
}
72+
73+
// This route will be accessible by STA clients only
74+
server.on("/", [&]() {
75+
digitalWrite(led, 1);
76+
server.send(200, "text/plain", "Hi!, This route is accessible for STA clients only");
77+
digitalWrite(led, 0);
78+
}).setFilter(ON_STA_FILTER);
79+
80+
// This route will be accessible by AP clients only
81+
server.on("/", [&]() {
82+
digitalWrite(led, 1);
83+
server.send(200, "text/plain", "Hi!, This route is accessible for AP clients only");
84+
digitalWrite(led, 0);
85+
}).setFilter(ON_AP_FILTER);
86+
87+
server.on("/inline", []() {
88+
server.send(200, "text/plain", "this works as well");
89+
});
90+
91+
server.onNotFound(handleNotFound);
92+
93+
server.begin();
94+
Serial.println("HTTP server started");
95+
}
96+
97+
void loop(void) {
98+
server.handleClient();
99+
MDNS.update();
100+
}

libraries/WebServer/src/HTTPServer.cpp

Lines changed: 75 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -207,22 +207,65 @@ void HTTPServer::requestAuthentication(HTTPAuthMethod mode, const char* realm, c
207207
send(401, String(FPSTR(mimeTable[html].mimeType)), authFailMsg);
208208
}
209209

210-
void HTTPServer::on(const Uri &uri, HTTPServer::THandlerFunction handler) {
211-
on(uri, HTTP_ANY, handler);
210+
RequestHandler& HTTPServer::on(const Uri &uri, HTTPServer::THandlerFunction handler) {
211+
return on(uri, HTTP_ANY, handler);
212212
}
213213

214-
void HTTPServer::on(const Uri &uri, HTTPMethod method, HTTPServer::THandlerFunction fn) {
215-
on(uri, method, fn, _fileUploadHandler);
214+
RequestHandler& HTTPServer::on(const Uri &uri, HTTPMethod method, HTTPServer::THandlerFunction fn) {
215+
return on(uri, method, fn, _fileUploadHandler);
216216
}
217217

218-
void HTTPServer::on(const Uri &uri, HTTPMethod method, HTTPServer::THandlerFunction fn, HTTPServer::THandlerFunction ufn) {
219-
_addRequestHandler(new FunctionRequestHandler(fn, ufn, uri, method));
218+
RequestHandler& HTTPServer::on(const Uri &uri, HTTPMethod method, HTTPServer::THandlerFunction fn, HTTPServer::THandlerFunction ufn) {
219+
FunctionRequestHandler *handler = new FunctionRequestHandler(fn, ufn, uri, method);
220+
_addRequestHandler(handler);
221+
return *handler;
222+
}
223+
224+
bool HTTPServer::removeRoute(const char *uri) {
225+
return removeRoute(String(uri), HTTP_ANY);
226+
}
227+
228+
bool HTTPServer::removeRoute(const char *uri, HTTPMethod method) {
229+
return removeRoute(String(uri), method);
230+
}
231+
232+
bool HTTPServer::removeRoute(const String &uri) {
233+
return removeRoute(uri, HTTP_ANY);
234+
}
235+
236+
bool HTTPServer::removeRoute(const String &uri, HTTPMethod method) {
237+
bool anyHandlerRemoved = false;
238+
RequestHandler *handler = _firstHandler;
239+
RequestHandler *previousHandler = nullptr;
240+
241+
while (handler) {
242+
if (handler->canHandle(method, uri)) {
243+
if (_removeRequestHandler(handler)) {
244+
anyHandlerRemoved = true;
245+
// Move to the next handler
246+
if (previousHandler) {
247+
handler = previousHandler->next();
248+
} else {
249+
handler = _firstHandler;
250+
}
251+
continue;
252+
}
253+
}
254+
previousHandler = handler;
255+
handler = handler->next();
256+
}
257+
258+
return anyHandlerRemoved;
220259
}
221260

222261
void HTTPServer::addHandler(RequestHandler* handler) {
223262
_addRequestHandler(handler);
224263
}
225264

265+
bool HTTPServer::removeHandler(RequestHandler *handler) {
266+
return _removeRequestHandler(handler);
267+
}
268+
226269
void HTTPServer::_addRequestHandler(RequestHandler* handler) {
227270
if (!_lastHandler) {
228271
_firstHandler = handler;
@@ -233,6 +276,32 @@ void HTTPServer::_addRequestHandler(RequestHandler* handler) {
233276
}
234277
}
235278

279+
bool HTTPServer::_removeRequestHandler(RequestHandler *handler) {
280+
RequestHandler *current = _firstHandler;
281+
RequestHandler *previous = nullptr;
282+
283+
while (current != nullptr) {
284+
if (current == handler) {
285+
if (previous == nullptr) {
286+
_firstHandler = current->next();
287+
} else {
288+
previous->next(current->next());
289+
}
290+
291+
if (current == _lastHandler) {
292+
_lastHandler = previous;
293+
}
294+
295+
// Delete 'matching' handler
296+
delete current;
297+
return true;
298+
}
299+
previous = current;
300+
current = current->next();
301+
}
302+
return false;
303+
}
304+
236305
void HTTPServer::serveStatic(const char* uri, FS& fs, const char* path, const char* cache_header) {
237306
_addRequestHandler(new StaticRequestHandler(fs, path, uri, cache_header));
238307
}

libraries/WebServer/src/HTTPServer.h

Lines changed: 13 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -95,10 +95,16 @@ class HTTPServer {
9595
void requestAuthentication(HTTPAuthMethod mode = BASIC_AUTH, const char* realm = nullptr, const String& authFailMsg = String(""));
9696

9797
typedef std::function<void(void)> THandlerFunction;
98-
void on(const Uri &uri, THandlerFunction fn);
99-
void on(const Uri &uri, HTTPMethod method, THandlerFunction fn);
100-
void on(const Uri &uri, HTTPMethod method, THandlerFunction fn, THandlerFunction ufn); //ufn handles file uploads
98+
typedef std::function<bool(HTTPServer &server)> FilterFunction;
99+
RequestHandler& on(const Uri &uri, THandlerFunction fn);
100+
RequestHandler& on(const Uri &uri, HTTPMethod method, THandlerFunction fn);
101+
RequestHandler& on(const Uri &uri, HTTPMethod method, THandlerFunction fn, THandlerFunction ufn); //ufn handles file uploads
102+
bool removeRoute(const char *uri);
103+
bool removeRoute(const char *uri, HTTPMethod method);
104+
bool removeRoute(const String &uri);
105+
bool removeRoute(const String &uri, HTTPMethod method);
101106
void addHandler(RequestHandler* handler);
107+
bool removeHandler(RequestHandler *handler);
102108
void serveStatic(const char* uri, fs::FS& fs, const char* path, const char* cache_header = nullptr);
103109
void onNotFound(THandlerFunction fn); //called when handler is not assigned
104110
void onFileUpload(THandlerFunction ufn); //handle file uploads
@@ -109,6 +115,9 @@ class HTTPServer {
109115
HTTPMethod method() {
110116
return _currentMethod;
111117
}
118+
WiFiClient& client() {
119+
return *_currentClient;
120+
}
112121
HTTPUpload& upload() {
113122
return *_currentUpload;
114123
}
@@ -230,6 +239,7 @@ class HTTPServer {
230239
return _currentClient->write(b, l);
231240
}
232241
void _addRequestHandler(RequestHandler* handler);
242+
bool _removeRequestHandler(RequestHandler *handler);
233243
void _handleRequest();
234244
void _finalizeResponse();
235245
ClientFuture _parseRequest(WiFiClient* client);

libraries/WebServer/src/Parsing.cpp

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -136,7 +136,7 @@ HTTPServer::ClientFuture HTTPServer::_parseRequest(WiFiClient* client) {
136136
//attach handler
137137
RequestHandler* handler;
138138
for (handler = _firstHandler; handler; handler = handler->next()) {
139-
if (handler->canHandle(_currentMethod, _currentUri)) {
139+
if (handler->canHandle(*this, _currentMethod, _currentUri)) {
140140
break;
141141
}
142142
}
@@ -188,7 +188,7 @@ HTTPServer::ClientFuture HTTPServer::_parseRequest(WiFiClient* client) {
188188
}
189189
}
190190

191-
if (!isForm && _currentHandler && _currentHandler->canRaw(_currentUri)) {
191+
if (!isForm && _currentHandler && _currentHandler->canRaw(*this, _currentUri)) {
192192
log_v("Parse raw");
193193
_currentRaw.reset(new HTTPRaw());
194194
_currentRaw->status = RAW_START;
@@ -347,7 +347,7 @@ void HTTPServer::_parseArguments(String data) {
347347

348348
void HTTPServer::_uploadWriteByte(uint8_t b) {
349349
if (_currentUpload->currentSize == HTTP_UPLOAD_BUFLEN) {
350-
if (_currentHandler && _currentHandler->canUpload(_currentUri)) {
350+
if (_currentHandler && _currentHandler->canUpload(*this, _currentUri)) {
351351
_currentHandler->upload(*this, _currentUri, *_currentUpload);
352352
}
353353
_currentUpload->totalSize += _currentUpload->currentSize;
@@ -462,7 +462,7 @@ bool HTTPServer::_parseForm(WiFiClient * client, String boundary, uint32_t len)
462462
_currentUpload->totalSize = 0;
463463
_currentUpload->currentSize = 0;
464464
log_v("Start File: %s Type: %s", _currentUpload->filename.c_str(), _currentUpload->type.c_str());
465-
if (_currentHandler && _currentHandler->canUpload(_currentUri)) {
465+
if (_currentHandler && _currentHandler->canUpload(*this, _currentUri)) {
466466
_currentHandler->upload(*this, _currentUri, *_currentUpload);
467467
}
468468
_currentUpload->status = UPLOAD_FILE_WRITE;
@@ -501,12 +501,12 @@ bool HTTPServer::_parseForm(WiFiClient * client, String boundary, uint32_t len)
501501
}
502502
}
503503
// Found the boundary string, finish processing this file upload
504-
if (_currentHandler && _currentHandler->canUpload(_currentUri)) {
504+
if (_currentHandler && _currentHandler->canUpload(*this, _currentUri)) {
505505
_currentHandler->upload(*this, _currentUri, *_currentUpload);
506506
}
507507
_currentUpload->totalSize += _currentUpload->currentSize;
508508
_currentUpload->status = UPLOAD_FILE_END;
509-
if (_currentHandler && _currentHandler->canUpload(_currentUri)) {
509+
if (_currentHandler && _currentHandler->canUpload(*this, _currentUri)) {
510510
_currentHandler->upload(*this, _currentUri, *_currentUpload);
511511
}
512512
log_v("End File: %s Type: %s Size: %d", _currentUpload->filename.c_str(), _currentUpload->type.c_str(), (int)_currentUpload->totalSize);
@@ -580,7 +580,7 @@ String HTTPServer::urlDecode(const String & text) {
580580

581581
bool HTTPServer::_parseFormUploadAborted() {
582582
_currentUpload->status = UPLOAD_FILE_ABORTED;
583-
if (_currentHandler && _currentHandler->canUpload(_currentUri)) {
583+
if (_currentHandler && _currentHandler->canUpload(*this, _currentUri)) {
584584
_currentHandler->upload(*this, _currentUri, *_currentUpload);
585585
}
586586
return false;

libraries/WebServer/src/detail/RequestHandler.h

Lines changed: 35 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -6,17 +6,43 @@
66
class RequestHandler {
77
public:
88
virtual ~RequestHandler() { }
9+
10+
/*
11+
note: old handler API for backward compatibility
12+
*/
13+
914
virtual bool canHandle(HTTPMethod method, String uri) {
10-
(void) method;
11-
(void) uri;
15+
(void)method;
16+
(void)uri;
1217
return false;
1318
}
1419
virtual bool canUpload(String uri) {
15-
(void) uri;
20+
(void)uri;
1621
return false;
1722
}
1823
virtual bool canRaw(String uri) {
19-
(void) uri;
24+
(void)uri;
25+
return false;
26+
}
27+
28+
/*
29+
note: new handler API with support for filters etc.
30+
*/
31+
32+
virtual bool canHandle(HTTPServer &server, HTTPMethod method, String uri) {
33+
(void)server;
34+
(void)method;
35+
(void)uri;
36+
return false;
37+
}
38+
virtual bool canUpload(HTTPServer &server, String uri) {
39+
(void)server;
40+
(void)uri;
41+
return false;
42+
}
43+
virtual bool canRaw(HTTPServer &server, String uri) {
44+
(void)server;
45+
(void)uri;
2046
return false;
2147
}
2248
virtual bool handle(HTTPServer& server, HTTPMethod requestMethod, String requestUri) {
@@ -43,6 +69,11 @@ class RequestHandler {
4369
_next = r;
4470
}
4571

72+
virtual RequestHandler& setFilter(std::function<bool(HTTPServer&)> filter) {
73+
(void)filter;
74+
return *this;
75+
}
76+
4677
private:
4778
RequestHandler* _next = nullptr;
4879

0 commit comments

Comments
 (0)