diff --git a/libraries/ESP8266WebServer/examples/PathArgServer/PathArgServer.ino b/libraries/ESP8266WebServer/examples/PathArgServer/PathArgServer.ino new file mode 100644 index 0000000000..db8bcfe039 --- /dev/null +++ b/libraries/ESP8266WebServer/examples/PathArgServer/PathArgServer.ino @@ -0,0 +1,53 @@ +#include +#include +#include +#include + +const char *ssid = "........"; +const char *password = "........"; + +ESP8266WebServer server(80); + +void setup(void) { + Serial.begin(9600); + WiFi.mode(WIFI_STA); + WiFi.begin(ssid, 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("esp8266")) { + Serial.println("MDNS responder started"); + } + + server.on("/", []() { + server.send(200, "text/plain", "hello from esp8266!"); + }); + + server.on("/users/{}", []() { + String user = server.pathArg(0); + server.send(200, "text/plain", "User: '" + user + "'"); + }); + + server.on("^\\/users\\/([0-9]+)\\/devices\\/([0-9]+)$", []() { + String user = server.pathArg(0); + String device = server.pathArg(1); + server.send(200, "text/plain", "User: '" + user + "' and Device: '" + device + "'"); + }); + + server.begin(); + Serial.println("HTTP server started"); +} + +void loop(void) { + server.handleClient(); +} diff --git a/libraries/ESP8266WebServer/src/ESP8266WebServer-impl.h b/libraries/ESP8266WebServer/src/ESP8266WebServer-impl.h index 1efcf92e5e..9de4f393dd 100644 --- a/libraries/ESP8266WebServer/src/ESP8266WebServer-impl.h +++ b/libraries/ESP8266WebServer/src/ESP8266WebServer-impl.h @@ -542,6 +542,12 @@ void ESP8266WebServerTemplate::_streamFileCore(const size_t fileSize send(200, contentType, emptyString); } +template +const String& ESP8266WebServerTemplate::pathArg(unsigned int i) const { + if (_currentHandler != nullptr) + return _currentHandler->pathArg(i); + return emptyString; +} template const String& ESP8266WebServerTemplate::arg(const String& name) const { diff --git a/libraries/ESP8266WebServer/src/ESP8266WebServer.h b/libraries/ESP8266WebServer/src/ESP8266WebServer.h index 4281ce8636..5797548eae 100644 --- a/libraries/ESP8266WebServer/src/ESP8266WebServer.h +++ b/libraries/ESP8266WebServer/src/ESP8266WebServer.h @@ -107,6 +107,7 @@ class ESP8266WebServerTemplate // Allows setting server options (i.e. SSL keys) by the instantiator ServerType &getServer() { return _server; } + const String& pathArg(unsigned int i) const; // get request path argument by number const String& arg(const String& name) const; // get request argument value by name const String& arg(int i) const; // get request argument value by number const String& argName(int i) const; // get request argument name by number diff --git a/libraries/ESP8266WebServer/src/detail/RequestHandler.h b/libraries/ESP8266WebServer/src/detail/RequestHandler.h index db840af2a1..9202f623b3 100644 --- a/libraries/ESP8266WebServer/src/detail/RequestHandler.h +++ b/libraries/ESP8266WebServer/src/detail/RequestHandler.h @@ -2,6 +2,8 @@ #define REQUESTHANDLER_H #include +#include +#include template class RequestHandler { @@ -18,6 +20,15 @@ class RequestHandler { private: RequestHandler* _next = nullptr; + +protected: + std::vector pathArgs; + +public: + const String& pathArg(unsigned int i) { + assert(i < pathArgs.size()); + return pathArgs[i]; + } }; #endif //REQUESTHANDLER_H diff --git a/libraries/ESP8266WebServer/src/detail/RequestHandlersImpl.h b/libraries/ESP8266WebServer/src/detail/RequestHandlersImpl.h index e9b8689c04..bc81dcc0c7 100644 --- a/libraries/ESP8266WebServer/src/detail/RequestHandlersImpl.h +++ b/libraries/ESP8266WebServer/src/detail/RequestHandlersImpl.h @@ -2,6 +2,8 @@ #define REQUESTHANDLERSIMPL_H #include +#include +#include #include "RequestHandler.h" #include "mimetable.h" #include "WString.h" @@ -17,17 +19,42 @@ class FunctionRequestHandler : public RequestHandler { , _ufn(ufn) , _uri(uri) , _method(method) + , _isRegex(false) { + _isRegex = uri.startsWith("^") && uri.endsWith("$"); + if (_isRegex) { + std::regex rgx((_uri + "|").c_str()); + std::smatch matches; + std::string s{""}; + std::regex_search(s, matches, rgx); + RequestHandler::pathArgs.resize(matches.size() - 1); + } else { + RequestHandler::pathArgs.resize(0); + } } bool canHandle(HTTPMethod requestMethod, String requestUri) override { if (_method != HTTP_ANY && _method != requestMethod) return false; - if (requestUri != _uri) - return false; + if (_uri == requestUri) + return true; + + if (_isRegex) { + unsigned int pathArgIndex = 0; + std::regex rgx(_uri.c_str()); + std::smatch matches; + std::string s(requestUri.c_str()); + if (std::regex_search(s, matches, rgx)) { + for (size_t i = 1; i < matches.size(); ++i) { // skip first + RequestHandler::pathArgs[pathArgIndex] = String(matches[i].str().c_str()); + pathArgIndex++; + } + return true; + } + } - return true; + return false; } bool canUpload(String requestUri) override { @@ -58,6 +85,7 @@ class FunctionRequestHandler : public RequestHandler { typename WebServerType::THandlerFunction _ufn; String _uri; HTTPMethod _method; + bool _isRegex; }; template