forked from me-no-dev/ESPAsyncWebServer
Support route parameters with regex patterns (#560)
* Fix compile warnings * first test * Add regex path * Add simple example * add support for esp8266 * Update AsyncJson.h
This commit is contained in:
65
examples/regex_patterns/regex_patterns.ino
Normal file
65
examples/regex_patterns/regex_patterns.ino
Normal file
@ -0,0 +1,65 @@
|
||||
//
|
||||
// A simple server implementation with regex routes:
|
||||
// * serve static messages
|
||||
// * read GET and POST parameters
|
||||
// * handle missing pages / 404s
|
||||
//
|
||||
|
||||
#include <Arduino.h>
|
||||
#ifdef ESP32
|
||||
#include <WiFi.h>
|
||||
#include <AsyncTCP.h>
|
||||
#elif defined(ESP8266)
|
||||
#include <ESP8266WiFi.h>
|
||||
#include <ESPAsyncTCP.h>
|
||||
#endif
|
||||
#include <ESPAsyncWebServer.h>
|
||||
|
||||
AsyncWebServer server(80);
|
||||
|
||||
const char* ssid = "YOUR_SSID";
|
||||
const char* password = "YOUR_PASSWORD";
|
||||
|
||||
const char* PARAM_MESSAGE = "message";
|
||||
|
||||
void notFound(AsyncWebServerRequest *request) {
|
||||
request->send(404, "text/plain", "Not found");
|
||||
}
|
||||
|
||||
void setup() {
|
||||
|
||||
Serial.begin(115200);
|
||||
WiFi.mode(WIFI_STA);
|
||||
WiFi.begin(ssid, password);
|
||||
if (WiFi.waitForConnectResult() != WL_CONNECTED) {
|
||||
Serial.printf("WiFi Failed!\n");
|
||||
return;
|
||||
}
|
||||
|
||||
Serial.print("IP Address: ");
|
||||
Serial.println(WiFi.localIP());
|
||||
|
||||
server.on("/", HTTP_GET, [](AsyncWebServerRequest *request){
|
||||
request->send(200, "text/plain", "Hello, world");
|
||||
});
|
||||
|
||||
// Send a GET request to <IP>/sensor/<number>
|
||||
server.on("^\\/sensor\\/([0-9]+)$", HTTP_GET, [] (AsyncWebServerRequest *request) {
|
||||
String sensorNumber = request->pathArg(0);
|
||||
request->send(200, "text/plain", "Hello, sensor: " + sensorNumber);
|
||||
});
|
||||
|
||||
// Send a GET request to <IP>/sensor/<number>/action/<action>
|
||||
server.on("^\\/sensor\\/([0-9]+)\\/action\//([a-zA-Z0-9]+)$", HTTP_GET, [] (AsyncWebServerRequest *request) {
|
||||
String sensorNumber = request->pathArg(0);
|
||||
String action = request->pathArg(1);
|
||||
request->send(200, "text/plain", "Hello, sensor: " + sensorNumber + ", with action: " + action);
|
||||
});
|
||||
|
||||
server.onNotFound(notFound);
|
||||
|
||||
server.begin();
|
||||
}
|
||||
|
||||
void loop() {
|
||||
}
|
@ -129,6 +129,7 @@ class AsyncWebServerRequest {
|
||||
using File = fs::File;
|
||||
using FS = fs::FS;
|
||||
friend class AsyncWebServer;
|
||||
friend class AsyncCallbackWebHandler;
|
||||
private:
|
||||
AsyncClient* _client;
|
||||
AsyncWebServer* _server;
|
||||
@ -158,6 +159,7 @@ class AsyncWebServerRequest {
|
||||
|
||||
LinkedList<AsyncWebHeader *> _headers;
|
||||
LinkedList<AsyncWebParameter *> _params;
|
||||
LinkedList<String *> _pathParams;
|
||||
|
||||
uint8_t _multiParseState;
|
||||
uint8_t _boundaryPosition;
|
||||
@ -179,6 +181,7 @@ class AsyncWebServerRequest {
|
||||
void _onData(void *buf, size_t len);
|
||||
|
||||
void _addParam(AsyncWebParameter*);
|
||||
void _addPathParam(const char *param);
|
||||
|
||||
bool _parseReqHead();
|
||||
bool _parseReqHeader();
|
||||
@ -268,6 +271,8 @@ class AsyncWebServerRequest {
|
||||
bool hasArg(const char* name) const; // check if argument exists
|
||||
bool hasArg(const __FlashStringHelper * data) const; // check if F(argument) exists
|
||||
|
||||
const String& pathArg(size_t i) const;
|
||||
|
||||
const String& header(const char* name) const;// get request header value by name
|
||||
const String& header(const __FlashStringHelper * data) const;// get request header value by F(name)
|
||||
const String& header(size_t i) const; // get request header value by number
|
||||
|
@ -21,6 +21,8 @@
|
||||
#ifndef ASYNCWEBSERVERHANDLERIMPL_H_
|
||||
#define ASYNCWEBSERVERHANDLERIMPL_H_
|
||||
|
||||
#include <string>
|
||||
#include <regex>
|
||||
|
||||
#include "stddef.h"
|
||||
#include <time.h>
|
||||
@ -67,9 +69,13 @@ class AsyncCallbackWebHandler: public AsyncWebHandler {
|
||||
ArRequestHandlerFunction _onRequest;
|
||||
ArUploadHandlerFunction _onUpload;
|
||||
ArBodyHandlerFunction _onBody;
|
||||
bool _isRegex;
|
||||
public:
|
||||
AsyncCallbackWebHandler() : _uri(), _method(HTTP_ANY), _onRequest(NULL), _onUpload(NULL), _onBody(NULL){}
|
||||
void setUri(const String& uri){ _uri = uri; }
|
||||
AsyncCallbackWebHandler() : _uri(), _method(HTTP_ANY), _onRequest(NULL), _onUpload(NULL), _onBody(NULL), _isRegex(false){}
|
||||
void setUri(const String& uri){
|
||||
_uri = uri;
|
||||
_isRegex = uri.startsWith("^") && uri.endsWith("$");
|
||||
}
|
||||
void setMethod(WebRequestMethodComposite method){ _method = method; }
|
||||
void onRequest(ArRequestHandlerFunction fn){ _onRequest = fn; }
|
||||
void onUpload(ArUploadHandlerFunction fn){ _onUpload = fn; }
|
||||
@ -83,7 +89,18 @@ class AsyncCallbackWebHandler: public AsyncWebHandler {
|
||||
if(!(_method & request->method()))
|
||||
return false;
|
||||
|
||||
if (_uri.length() && _uri.endsWith("*")) {
|
||||
if (_isRegex) {
|
||||
std::regex rgx(_uri.c_str());
|
||||
std::smatch matches;
|
||||
std::string s(request->url().c_str());
|
||||
if(std::regex_search(s, matches, rgx)) {
|
||||
for (size_t i = 1; i < matches.size(); ++i) { // start from 1
|
||||
request->_addPathParam(matches[i].str().c_str());
|
||||
}
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
} else if (_uri.length() && _uri.endsWith("*")) {
|
||||
String uriTemplate = String(_uri);
|
||||
uriTemplate = uriTemplate.substring(0, uriTemplate.length() - 1);
|
||||
if (!request->url().startsWith(uriTemplate))
|
||||
|
@ -55,6 +55,7 @@ AsyncWebServerRequest::AsyncWebServerRequest(AsyncWebServer* s, AsyncClient* c)
|
||||
, _parsedLength(0)
|
||||
, _headers(LinkedList<AsyncWebHeader *>([](AsyncWebHeader *h){ delete h; }))
|
||||
, _params(LinkedList<AsyncWebParameter *>([](AsyncWebParameter *p){ delete p; }))
|
||||
, _pathParams(LinkedList<String *>([](String *p){ delete p; }))
|
||||
, _multiParseState(0)
|
||||
, _boundaryPosition(0)
|
||||
, _itemStartIndex(0)
|
||||
@ -80,6 +81,7 @@ AsyncWebServerRequest::~AsyncWebServerRequest(){
|
||||
_headers.free();
|
||||
|
||||
_params.free();
|
||||
_pathParams.free();
|
||||
|
||||
_interestingHeaders.free();
|
||||
|
||||
@ -230,6 +232,10 @@ void AsyncWebServerRequest::_addParam(AsyncWebParameter *p){
|
||||
_params.add(p);
|
||||
}
|
||||
|
||||
void AsyncWebServerRequest::_addPathParam(const char *p){
|
||||
_pathParams.add(new String(p));
|
||||
}
|
||||
|
||||
void AsyncWebServerRequest::_addGetParams(const String& params){
|
||||
size_t start = 0;
|
||||
while (start < params.length()){
|
||||
@ -912,6 +918,11 @@ const String& AsyncWebServerRequest::argName(size_t i) const {
|
||||
return getParam(i)->name();
|
||||
}
|
||||
|
||||
const String& AsyncWebServerRequest::pathArg(size_t i) const {
|
||||
auto param = _pathParams.nth(i);
|
||||
return param ? **param : SharedEmptyString;
|
||||
}
|
||||
|
||||
const String& AsyncWebServerRequest::header(const char* name) const {
|
||||
AsyncWebHeader* h = getHeader(String(name));
|
||||
return h ? h->value() : SharedEmptyString;
|
||||
|
Reference in New Issue
Block a user