diff --git a/libraries/ESP8266WebServer/examples/PathArgServer/PathArgServer.ino b/libraries/ESP8266WebServer/examples/PathArgServer/PathArgServer.ino
new file mode 100644
index 0000000000..c2c7f56884
--- /dev/null
+++ b/libraries/ESP8266WebServer/examples/PathArgServer/PathArgServer.ino
@@ -0,0 +1,61 @@
+#include <ESP8266WiFi.h>
+#include <WiFiClient.h>
+#include <ESP8266WebServer.h>
+#include <ESP8266mDNS.h>
+
+#include <uri/UriBraces.h>
+#include <uri/UriRegex.h>
+
+#ifndef STASSID
+#define STASSID "your-ssid"
+#define STAPSK  "your-password"
+#endif
+
+const char *ssid = STASSID;
+const char *password = STAPSK;
+
+ESP8266WebServer server(80);
+
+void setup(void) {
+  Serial.begin(115200);
+  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(UriBraces("/users/{}"), []() {
+    String user = server.pathArg(0);
+    server.send(200, "text/plain", "User: '" + user + "'");
+  });
+
+  server.on(UriRegex("^\\/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 440d9d9bbd..f085a8afe6 100644
--- a/libraries/ESP8266WebServer/src/ESP8266WebServer-impl.h
+++ b/libraries/ESP8266WebServer/src/ESP8266WebServer-impl.h
@@ -263,17 +263,17 @@ void ESP8266WebServerTemplate<ServerType>::requestAuthentication(HTTPAuthMethod
 }
 
 template <typename ServerType>
-void ESP8266WebServerTemplate<ServerType>::on(const String &uri, ESP8266WebServerTemplate<ServerType>::THandlerFunction handler) {
+void ESP8266WebServerTemplate<ServerType>::on(const Uri &uri, ESP8266WebServerTemplate<ServerType>::THandlerFunction handler) {
   on(uri, HTTP_ANY, handler);
 }
 
 template <typename ServerType>
-void ESP8266WebServerTemplate<ServerType>::on(const String &uri, HTTPMethod method, ESP8266WebServerTemplate<ServerType>::THandlerFunction fn) {
+void ESP8266WebServerTemplate<ServerType>::on(const Uri &uri, HTTPMethod method, ESP8266WebServerTemplate<ServerType>::THandlerFunction fn) {
   on(uri, method, fn, _fileUploadHandler);
 }
 
 template <typename ServerType>
-void ESP8266WebServerTemplate<ServerType>::on(const String &uri, HTTPMethod method, ESP8266WebServerTemplate<ServerType>::THandlerFunction fn, ESP8266WebServerTemplate<ServerType>::THandlerFunction ufn) {
+void ESP8266WebServerTemplate<ServerType>::on(const Uri &uri, HTTPMethod method, ESP8266WebServerTemplate<ServerType>::THandlerFunction fn, ESP8266WebServerTemplate<ServerType>::THandlerFunction ufn) {
   _addRequestHandler(new FunctionRequestHandler<ServerType>(fn, ufn, uri, method));
 }
 
@@ -544,6 +544,12 @@ void ESP8266WebServerTemplate<ServerType>::_streamFileCore(const size_t fileSize
   send(200, contentType, emptyString);
 }
 
+template <typename ServerType>
+const String& ESP8266WebServerTemplate<ServerType>::pathArg(unsigned int i) const { 
+  if (_currentHandler != nullptr)
+    return _currentHandler->pathArg(i);
+  return emptyString;
+}
 
 template <typename ServerType>
 const String& ESP8266WebServerTemplate<ServerType>::arg(const String& name) const {
diff --git a/libraries/ESP8266WebServer/src/ESP8266WebServer.h b/libraries/ESP8266WebServer/src/ESP8266WebServer.h
index 2366ea93af..eefcba2ba3 100644
--- a/libraries/ESP8266WebServer/src/ESP8266WebServer.h
+++ b/libraries/ESP8266WebServer/src/ESP8266WebServer.h
@@ -29,6 +29,7 @@
 #include <ESP8266WiFi.h>
 #include <FS.h>
 #include "detail/mimetable.h"
+#include "Uri.h"
 
 enum HTTPMethod { HTTP_ANY, HTTP_GET, HTTP_HEAD, HTTP_POST, HTTP_PUT, HTTP_PATCH, HTTP_DELETE, HTTP_OPTIONS };
 enum HTTPUploadStatus { UPLOAD_FILE_START, UPLOAD_FILE_WRITE, UPLOAD_FILE_END,
@@ -91,9 +92,9 @@ class ESP8266WebServerTemplate
   void requestAuthentication(HTTPAuthMethod mode = BASIC_AUTH, const char* realm = NULL, const String& authFailMsg = String("") );
 
   typedef std::function<void(void)> THandlerFunction;
-  void on(const String &uri, THandlerFunction handler);
-  void on(const String &uri, HTTPMethod method, THandlerFunction fn);
-  void on(const String &uri, HTTPMethod method, THandlerFunction fn, THandlerFunction ufn);
+  void on(const Uri &uri, THandlerFunction handler);
+  void on(const Uri &uri, HTTPMethod method, THandlerFunction fn);
+  void on(const Uri &uri, HTTPMethod method, THandlerFunction fn, THandlerFunction ufn);
   void addHandler(RequestHandlerType* handler);
   void serveStatic(const char* uri, fs::FS& fs, const char* path, const char* cache_header = NULL );
   void onNotFound(THandlerFunction fn);  //called when handler is not assigned
@@ -107,6 +108,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/Uri.h b/libraries/ESP8266WebServer/src/Uri.h
new file mode 100644
index 0000000000..cb9b68c051
--- /dev/null
+++ b/libraries/ESP8266WebServer/src/Uri.h
@@ -0,0 +1,26 @@
+#ifndef URI_H
+#define URI_H
+
+#include <Arduino.h>
+#include <vector>
+
+class Uri {
+
+    protected:
+        const String _uri;
+
+    public:
+        Uri(const char *uri) : _uri(uri) {}
+        Uri(const String &uri) : _uri(uri) {}
+        virtual ~Uri() {}
+
+        virtual Uri* clone() const {
+            return new Uri(_uri);
+        };
+
+        virtual bool canHandle(const String &requestUri, __attribute__((unused)) std::vector<String> &pathArgs) {
+            return _uri == requestUri;
+        }
+};
+
+#endif
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 <ESP8266WebServer.h>
+#include <vector>
+#include <assert.h>
 
 template<typename ServerType>
 class RequestHandler {
@@ -18,6 +20,15 @@ class RequestHandler {
 
 private:
     RequestHandler<ServerType>* _next = nullptr;
+	
+protected:
+    std::vector<String> 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 1c44f7833f..e196393174 100644
--- a/libraries/ESP8266WebServer/src/detail/RequestHandlersImpl.h
+++ b/libraries/ESP8266WebServer/src/detail/RequestHandlersImpl.h
@@ -5,6 +5,7 @@
 #include "RequestHandler.h"
 #include "mimetable.h"
 #include "WString.h"
+#include "Uri.h"
 
 using namespace mime;
 
@@ -12,22 +13,23 @@ template<typename ServerType>
 class FunctionRequestHandler : public RequestHandler<ServerType> {
     using WebServerType = ESP8266WebServerTemplate<ServerType>;
 public:
-    FunctionRequestHandler(typename WebServerType::THandlerFunction fn, typename WebServerType::THandlerFunction ufn, const String &uri, HTTPMethod method)
+    FunctionRequestHandler(typename WebServerType::THandlerFunction fn, typename WebServerType::THandlerFunction ufn, const Uri &uri, HTTPMethod method)
     : _fn(fn)
     , _ufn(ufn)
-    , _uri(uri)
+    , _uri(uri.clone())
     , _method(method)
     {
     }
 
+    ~FunctionRequestHandler() {
+        delete _uri;
+    }
+
     bool canHandle(HTTPMethod requestMethod, String requestUri) override  {
         if (_method != HTTP_ANY && _method != requestMethod)
             return false;
 
-        if (requestUri != _uri)
-            return false;
-
-        return true;
+        return _uri->canHandle(requestUri, RequestHandler<ServerType>::pathArgs);
     }
 
     bool canUpload(String requestUri) override  {
@@ -56,7 +58,7 @@ class FunctionRequestHandler : public RequestHandler<ServerType> {
 protected:
     typename WebServerType::THandlerFunction _fn;
     typename WebServerType::THandlerFunction _ufn;
-    String _uri;
+    Uri *_uri;
     HTTPMethod _method;
 };
 
diff --git a/libraries/ESP8266WebServer/src/uri/UriBraces.h b/libraries/ESP8266WebServer/src/uri/UriBraces.h
new file mode 100644
index 0000000000..29652efc7f
--- /dev/null
+++ b/libraries/ESP8266WebServer/src/uri/UriBraces.h
@@ -0,0 +1,54 @@
+#ifndef URI_BRACES_H
+#define URI_BRACES_H
+
+#include "Uri.h"
+
+class UriBraces : public Uri {
+
+    public:
+        explicit UriBraces(const char *uri) : Uri(uri) {};
+        explicit UriBraces(const String &uri) : Uri(uri) {};
+
+        Uri* clone() const override final {
+            return new UriBraces(_uri);
+        };
+
+        bool canHandle(const String &requestUri, std::vector<String> &pathArgs) override final {
+            if (Uri::canHandle(requestUri, pathArgs))
+                return true;
+
+            pathArgs.clear();
+
+            size_t uriLength = _uri.length();
+            unsigned int requestUriIndex = 0;
+            for (unsigned int i = 0; i < uriLength; i++, requestUriIndex++) {
+                char uriChar = _uri[i];
+                char requestUriChar = requestUri[requestUriIndex];
+
+                if (uriChar == requestUriChar)
+                    continue;
+                if (uriChar != '{')
+                    return false;
+
+                i += 2; // index of char after '}'
+                if (i >= uriLength) {
+                    // there is no char after '}'
+                    pathArgs.push_back(requestUri.substring(requestUriIndex));
+                    return pathArgs.back().indexOf("/") == -1; // path argument may not contain a '/'
+                }
+                else
+                {
+                    char charEnd = _uri[i];
+                    int uriIndex = requestUri.indexOf(charEnd, requestUriIndex);
+                    if (uriIndex < 0)
+                        return false;
+                    pathArgs.push_back(requestUri.substring(requestUriIndex, uriIndex));
+                    requestUriIndex = (unsigned int) uriIndex;
+                }
+            }
+
+            return requestUriIndex >= requestUri.length();
+        }
+};
+
+#endif
diff --git a/libraries/ESP8266WebServer/src/uri/UriGlob.h b/libraries/ESP8266WebServer/src/uri/UriGlob.h
new file mode 100644
index 0000000000..1e222cbabd
--- /dev/null
+++ b/libraries/ESP8266WebServer/src/uri/UriGlob.h
@@ -0,0 +1,22 @@
+#ifndef URI_GLOB_H
+#define URI_GLOB_H
+
+#include "Uri.h"
+#include <fnmatch.h>
+
+class UriGlob : public Uri {
+
+    public:
+        explicit UriGlob(const char *uri) : Uri(uri) {};
+        explicit UriGlob(const String &uri) : Uri(uri) {};
+
+        Uri* clone() const override final {
+            return new UriGlob(_uri);
+        };
+
+        bool canHandle(const String &requestUri, __attribute__((unused)) std::vector<String> &pathArgs) override final {
+            return fnmatch(_uri.c_str(), requestUri.c_str(), 0) == 0;
+        }
+};
+
+#endif
diff --git a/libraries/ESP8266WebServer/src/uri/UriRegex.h b/libraries/ESP8266WebServer/src/uri/UriRegex.h
new file mode 100644
index 0000000000..eef1b516d4
--- /dev/null
+++ b/libraries/ESP8266WebServer/src/uri/UriRegex.h
@@ -0,0 +1,54 @@
+#ifndef URI_REGEX_H
+#define URI_REGEX_H
+
+#include "Uri.h"
+#include <regex.h>
+#include <assert.h>
+
+#ifndef REGEX_MAX_GROUPS
+#define REGEX_MAX_GROUPS 10
+#endif
+
+class UriRegex : public Uri {
+
+    private:
+        regex_t _regexCompiled;
+
+    public:
+        explicit UriRegex(const char *uri) : Uri(uri) {
+            assert(regcomp(&_regexCompiled, uri, REG_EXTENDED) == 0);
+        };
+        explicit UriRegex(const String &uri) : UriRegex(uri.c_str()) {};
+
+        ~UriRegex() {
+            regfree(&_regexCompiled);
+        }
+
+        Uri* clone() const override final {
+            return new UriRegex(_uri);
+        };
+
+        bool canHandle(const String &requestUri, std::vector<String> &pathArgs) override final {
+            if (Uri::canHandle(requestUri, pathArgs))
+                return true;
+
+            regmatch_t groupArray[REGEX_MAX_GROUPS];
+            if (regexec(&_regexCompiled, requestUri.c_str(), REGEX_MAX_GROUPS, groupArray, 0) == 0) {
+                // matches
+                pathArgs.clear();
+
+                unsigned int g = 1; 
+                for (; g < REGEX_MAX_GROUPS; g++) {
+                    if (groupArray[g].rm_so == (long int)-1)
+                        break;  // No more groups
+
+                    pathArgs.push_back(requestUri.substring(groupArray[g].rm_so, groupArray[g].rm_eo));
+                }
+
+                return true;
+            }
+            return false;
+        }
+};
+
+#endif