5050#define ASYNCWEBSERVER_FORK_ESP32Async
5151
5252#ifdef ASYNCWEBSERVER_REGEX
53- #define ASYNCWEBSERVER_REGEX_ATTRIBUTE
54- #else
55- #define ASYNCWEBSERVER_REGEX_ATTRIBUTE __attribute__ ((warning(" ASYNCWEBSERVER_REGEX not defined" )))
53+ #include < regex>
5654#endif
5755
5856// See https://github.com/ESP32Async/ESPAsyncWebServer/commit/3d3456e9e81502a477f6498c44d0691499dda8f9#diff-646b25b11691c11dce25529e3abce843f0ba4bd07ab75ec9eee7e72b06dbf13fR388-R392
@@ -72,6 +70,7 @@ class AsyncStaticWebHandler;
7270class AsyncCallbackWebHandler ;
7371class AsyncResponseStream ;
7472class AsyncMiddlewareChain ;
73+ class AsyncURIMatcher ;
7574
7675#if defined(TARGET_RP2040) || defined(TARGET_RP2350) || defined(PICO_RP2040) || defined(PICO_RP2350)
7776typedef enum http_method WebRequestMethod;
@@ -162,7 +161,7 @@ class AsyncWebHeader {
162161 [[deprecated("Use AsyncWebHeader::parse(data) instead")]]
163162#endif
164163 AsyncWebHeader (const String &data)
165- : AsyncWebHeader(parse(data)){};
164+ : AsyncWebHeader(parse(data)) {};
166165
167166 AsyncWebHeader &operator =(const AsyncWebHeader &) = default ;
168167 AsyncWebHeader &operator =(AsyncWebHeader &&other) = default ;
@@ -222,6 +221,7 @@ class AsyncWebServerRequest {
222221 friend class AsyncCallbackWebHandler ;
223222 friend class AsyncFileResponse ;
224223 friend class AsyncStaticWebHandler ;
224+ friend class AsyncURIMatcher ;
225225
226226private:
227227 AsyncClient *_client;
@@ -254,7 +254,9 @@ class AsyncWebServerRequest {
254254
255255 std::list<AsyncWebHeader> _headers;
256256 std::list<AsyncWebParameter> _params;
257+ #ifdef ASYNCWEBSERVER_REGEX
257258 std::list<String> _pathParams;
259+ #endif
258260
259261 std::unordered_map<const char *, String, std::hash<const char *>, std::equal_to<const char *>> _attributes;
260262
@@ -277,8 +279,6 @@ class AsyncWebServerRequest {
277279 void _onDisconnect ();
278280 void _onData (void *buf, size_t len);
279281
280- void _addPathParam (const char *param);
281-
282282 bool _parseReqHead ();
283283 bool _parseReqHeader ();
284284 void _parseLine ();
@@ -333,8 +333,9 @@ class AsyncWebServerRequest {
333333 RequestedConnectionType requestedConnType () const {
334334 return _reqconntype;
335335 }
336- bool isExpectedRequestedConnType (RequestedConnectionType erct1, RequestedConnectionType erct2 = RCT_NOT_USED , RequestedConnectionType erct3 = RCT_NOT_USED )
337- const ;
336+ bool isExpectedRequestedConnType (
337+ RequestedConnectionType erct1, RequestedConnectionType erct2 = RCT_NOT_USED , RequestedConnectionType erct3 = RCT_NOT_USED
338+ ) const ;
338339 bool isWebSocketUpgrade () const {
339340 return _method == HTTP_GET && isExpectedRequestedConnType (RCT_WS );
340341 }
@@ -527,7 +528,8 @@ class AsyncWebServerRequest {
527528 return beginResponse (code, contentType.c_str (), content, len, callback);
528529 }
529530#ifndef ESP8266
530- [[deprecated(" Replaced by beginResponse(int code, const String& contentType, const char* content = asyncsrv::empty, AwsTemplateProcessor callback = nullptr)"
531+ [[deprecated(
532+ " Replaced by beginResponse(int code, const String& contentType, const char* content = asyncsrv::empty, AwsTemplateProcessor callback = nullptr)"
531533 )]]
532534#endif
533535 AsyncWebServerResponse *beginResponse_P (int code, const String &contentType, PGM_P content, AwsTemplateProcessor callback = nullptr );
@@ -615,10 +617,19 @@ class AsyncWebServerRequest {
615617 bool hasArg (const __FlashStringHelper *data) const ; // check if F(argument) exists
616618#endif
617619
618- const String &ASYNCWEBSERVER_REGEX_ATTRIBUTE pathArg (size_t i) const ;
619- const String &ASYNCWEBSERVER_REGEX_ATTRIBUTE pathArg (int i) const {
620+ #ifdef ASYNCWEBSERVER_REGEX
621+ const String &pathArg (size_t i) const {
622+ if (i >= _pathParams.size ()) {
623+ return emptyString;
624+ }
625+ auto it = _pathParams.begin ();
626+ std::advance (it, i);
627+ return *it;
628+ }
629+ const String &pathArg (int i) const {
620630 return i < 0 ? emptyString : pathArg ((size_t )i);
621631 }
632+ #endif
622633
623634 // get request header value by name
624635 const String &header (const char *name) const ;
@@ -719,6 +730,86 @@ class AsyncWebServerRequest {
719730 String urlDecode (const String &text) const ;
720731};
721732
733+ class AsyncURIMatcher {
734+ public:
735+ AsyncURIMatcher () {}
736+ AsyncURIMatcher (const char *uri) : _value(uri) {
737+ #ifdef ASYNCWEBSERVER_REGEX
738+ if (isRegex ()) {
739+ pattern = std::regex (_value.c_str ());
740+ }
741+ #endif
742+ }
743+ AsyncURIMatcher (String uri) : _value(std::move(uri)) {
744+ #ifdef ASYNCWEBSERVER_REGEX
745+ if (isRegex ()) {
746+ pattern = std::regex (_value.c_str ());
747+ }
748+ #endif
749+ }
750+
751+ AsyncURIMatcher (const AsyncURIMatcher &) = default ;
752+ AsyncURIMatcher (AsyncURIMatcher &&) = default ;
753+ ~AsyncURIMatcher () = default ;
754+
755+ AsyncURIMatcher &operator =(const AsyncURIMatcher &) = default ;
756+ AsyncURIMatcher &operator =(AsyncURIMatcher &&) = default ;
757+
758+ const String &value () const {
759+ return _value;
760+ }
761+ size_t length () const {
762+ return _value.length ();
763+ }
764+
765+ #ifdef ASYNCWEBSERVER_REGEX
766+ bool isRegex () const {
767+ return _value.startsWith (" ^" ) && _value.endsWith (" $" );
768+ }
769+ #endif
770+
771+ bool matches (AsyncWebServerRequest *request) const {
772+ #ifdef ASYNCWEBSERVER_REGEX
773+ if (isRegex ()) {
774+ std::smatch matches;
775+ std::string s (request->url ().c_str ());
776+ if (std::regex_search (s, matches, pattern)) {
777+ for (size_t i = 1 ; i < matches.size (); ++i) {
778+ request->_pathParams .emplace_back (matches[i].str ().c_str ());
779+ }
780+ return true ;
781+ } else {
782+ return false ;
783+ }
784+ }
785+ #endif
786+
787+ if (!_value.length ()) {
788+ return true ;
789+ }
790+
791+ if (_value.startsWith (" /*." )) {
792+ if (!request->url ().endsWith (_value.substring (_value.lastIndexOf (" ." )))) {
793+ return false ;
794+ }
795+ } else if (_value.endsWith (" *" )) {
796+ if (!request->url ().startsWith (_value.substring (0 , _value.length () - 1 ))) {
797+ return false ;
798+ }
799+ } else if (_value != request->url () && !request->url ().startsWith (_value + " /" )) {
800+ return false ;
801+ }
802+
803+ return true ;
804+ }
805+
806+ private:
807+ String _value;
808+ #ifdef ASYNCWEBSERVER_REGEX
809+ std::regex pattern;
810+ #endif
811+ };
812+
722813/*
723814 * FILTER :: Callback to filter AsyncWebRewrite and AsyncWebHandler (done by the Server)
724815 * */
@@ -992,13 +1083,13 @@ class AsyncRateLimitMiddleware : public AsyncMiddleware {
9921083
9931084class AsyncWebRewrite {
9941085protected:
995- String _from;
1086+ AsyncURIMatcher _from;
9961087 String _toUrl;
9971088 String _params;
9981089 ArRequestFilterFunction _filter{nullptr };
9991090
10001091public:
1001- AsyncWebRewrite (const char * from, const char *to) : _from(from), _toUrl(to) {
1092+ AsyncWebRewrite (AsyncURIMatcher from, const char *to) : _from(std::move( from) ), _toUrl(to) {
10021093 int index = _toUrl.indexOf (' ?' );
10031094 if (index > 0 ) {
10041095 _params = _toUrl.substring (index + 1 );
@@ -1014,7 +1105,7 @@ class AsyncWebRewrite {
10141105 return _filter == NULL || _filter (request);
10151106 }
10161107 const String &from (void ) const {
1017- return _from;
1108+ return _from. value () ;
10181109 }
10191110 const String &toUrl (void ) const {
10201111 return _toUrl;
@@ -1023,7 +1114,7 @@ class AsyncWebRewrite {
10231114 return _params;
10241115 }
10251116 virtual bool match (AsyncWebServerRequest *request) {
1026- return from () == request-> url ( ) && filter (request);
1117+ return _from. matches ( request) && filter (request);
10271118 }
10281119};
10291120
@@ -1226,7 +1317,7 @@ class AsyncWebServer : public AsyncMiddlewareChain {
12261317 * @param to
12271318 * @return AsyncWebRewrite&
12281319 */
1229- AsyncWebRewrite &rewrite (const char * from, const char *to);
1320+ AsyncWebRewrite &rewrite (AsyncURIMatcher from, const char *to);
12301321
12311322 /* *
12321323 * @brief (compat) remove rewrite rule via referenced object
@@ -1246,24 +1337,24 @@ class AsyncWebServer : public AsyncMiddlewareChain {
12461337 * @return true
12471338 * @return false
12481339 */
1249- bool removeRewrite (const char * from, const char *to);
1340+ bool removeRewrite (AsyncURIMatcher from, const char *to);
12501341
12511342 AsyncWebHandler &addHandler (AsyncWebHandler *handler);
12521343 bool removeHandler (AsyncWebHandler *handler);
12531344
1254- AsyncCallbackWebHandler &on (const char * uri, ArRequestHandlerFunction onRequest) {
1255- return on (uri, HTTP_ANY , onRequest);
1345+ AsyncCallbackWebHandler &on (AsyncURIMatcher uri, ArRequestHandlerFunction onRequest) {
1346+ return on (std::move ( uri) , HTTP_ANY , onRequest);
12561347 }
12571348 AsyncCallbackWebHandler &on (
1258- const char * uri, WebRequestMethodComposite method, ArRequestHandlerFunction onRequest, ArUploadHandlerFunction onUpload = nullptr ,
1349+ AsyncURIMatcher uri, WebRequestMethodComposite method, ArRequestHandlerFunction onRequest, ArUploadHandlerFunction onUpload = nullptr ,
12591350 ArBodyHandlerFunction onBody = nullptr
12601351 );
12611352
12621353#if ASYNC_JSON_SUPPORT == 1
1263- AsyncCallbackJsonWebHandler &on (const char * uri, WebRequestMethodComposite method, ArJsonRequestHandlerFunction onBody);
1354+ AsyncCallbackJsonWebHandler &on (AsyncURIMatcher uri, WebRequestMethodComposite method, ArJsonRequestHandlerFunction onBody);
12641355#endif
12651356
1266- AsyncStaticWebHandler &serveStatic (const char * uri, fs::FS &fs, const char *path, const char *cache_control = NULL );
1357+ AsyncStaticWebHandler &serveStatic (AsyncURIMatcher uri, fs::FS &fs, const char *path, const char *cache_control = NULL );
12671358
12681359 void onNotFound (ArRequestHandlerFunction fn); // called when handler is not assigned
12691360 void onFileUpload (ArUploadHandlerFunction fn); // handle file uploads
0 commit comments