[LEDE-DEV] [RFC] uhttpd: [PATCH 2/2] handlers: Add more sophisticated prefix/path matching heuristic

lede at daniel.thecshore.com lede at daniel.thecshore.com
Wed May 18 03:50:01 PDT 2016


From: Daniel Dickinson <openwrt at daniel.thecshore.com>

We prefer either a path match (e.g. interpreter extension match)
then the longest matching prefix (e.g. /cgi-bin/luci handler is used
except if a prefix matches a virtual url before the path matching
logic is hit.
Note that we now allow a handler to have both check_url and check_path
to support this.
Also note that if a handler has both a path match and a prefix match
AND one of its prefixes is the most specific match for this url,
then before path_lookup this code will return NULL (no match)
to ensure that the path match has a chance to override the prefix.

Signed-off-by: Daniel Dickinson <lede at daniel.thecshore.com>
---
 NOTE: This is basically untested and is provided to solicit comments
 for something for which there may be no interest before spending
 more time on it.

 cgi.c    | 11 ++++++++++-
 file.c   | 60 +++++++++++++++++++++++++++++++++++++++++++++++++++---------
 lua.c    |  6 ++++--
 proxy.c  |  6 +++---
 ubus.c   |  6 ++++--
 uhttpd.h |  2 +-
 6 files changed, 73 insertions(+), 18 deletions(-)

diff --git a/cgi.c b/cgi.c
index dc302a9..b274e4c 100644
--- a/cgi.c
+++ b/cgi.c
@@ -84,6 +84,14 @@ static void cgi_handle_request(struct client *cl, char *url, struct path_info *p
 	return;
 }
 
+static const char *check_cgi_url(const char *url)
+{
+	if (uh_path_match(conf.cgi_docroot_path, url))
+		return conf.cgi_docroot_path;
+
+	return NULL;
+}
+
 static bool check_cgi_path(struct path_info *pi, const char *url)
 {
 	struct interpreter *ip;
@@ -104,11 +112,12 @@ static bool check_cgi_path(struct path_info *pi, const char *url)
 	}
 
 	pi->ip = NULL;
-	return uh_path_match(conf.cgi_docroot_path, pi->phys);
+	return false;
 }
 
 struct dispatch_handler cgi_dispatch = {
 	.script = true,
 	.check_path = check_cgi_path,
+	.check_url = check_cgi_url,
 	.handle_request = cgi_handle_request,
 };
diff --git a/file.c b/file.c
index 12aa130..6d7ff0c 100644
--- a/file.c
+++ b/file.c
@@ -38,6 +38,7 @@
 static LIST_HEAD(index_files);
 static LIST_HEAD(dispatch_handlers);
 static LIST_HEAD(pending_requests);
+static LIST_HEAD(matches);
 static int n_requests;
 
 struct deferred_request {
@@ -654,27 +655,68 @@ void uh_dispatch_add(struct dispatch_handler *d)
 }
 
 static struct dispatch_handler *
+dispatch_check_match(struct dispatch_handler *d, const char *url, size_t *max_len) {
+	const char *matching_path;
+	size_t len;
+
+	if (d->check_url)
+		if ((matching_path = d->check_url(url))) {
+			len = strlen(matching_path);
+			if (len > *max_len) {
+				*max_len = len;
+				return d;
+			}
+		}
+
+	return NULL;
+}
+
+/* We prefer either a path match (e.g. interpreter extension match)
+ * then the longest matching prefix (e.g. /cgi-bin/luci handler is used
+ * except if a prefix matches a virtual url before the path matching
+ * logic is hit.
+ * Note that we now allow a handler to have both check_url and check_path
+ * to support this.
+ * Also note that if a handler has both a path match and a prefix match
+ * AND one of its prefixes is the most specific match for this url,
+ * then before path_lookup this code will return NULL (no match)
+ * to ensure that the path match has a chance to override the prefix.
+ */
+static struct dispatch_handler *
 dispatch_find(const char *url, struct path_info *pi)
 {
 	struct dispatch_handler *d;
+	struct dispatch_handler *m = NULL;
+	size_t max_len = 0;
 
 	list_for_each_entry(d, &dispatch_handlers, list) {
 		if (pi) {
-			if (d->check_url)
-				continue;
-
+			/* Prefer a path (e.g. interpreter extension)
+		         * match to a prefix match
+                         */
 			if (d->check_path(pi, url))
 				return d;
-		} else {
-			if (d->check_path)
-				continue;
 
-			if (d->check_url(url))
-				return d;
+			if (dispatch_check_match(d, url, &max_len))
+				m = d;
+		} else {
+			/* for handlers with both prefixes and path matches we
+			 * want the path match to actually occur which means
+			 * that we can't check prefixes until after path_lookup
+			 * is done and we have the final path.
+			 */
+
+			if (dispatch_check_match(d, url, &max_len)) {
+				if (d->check_path) {
+					m = NULL;
+				} else {
+					m = d;
+				}
+			}
 		}
 	}
 
-	return NULL;
+	return m;
 }
 
 static void
diff --git a/lua.c b/lua.c
index 2134904..e708778 100644
--- a/lua.c
+++ b/lua.c
@@ -275,9 +275,11 @@ static void lua_handle_request(struct client *cl, char *url, struct path_info *p
 	}
 }
 
-static bool check_lua_url(const char *url)
+static const char *check_lua_url(const char *url)
 {
-	return ops->path_match(conf.lua_prefix, url);
+	if (ops->path_match(conf.lua_prefix, url))
+		return conf.lua_prefix;
+	return NULL;
 }
 
 static struct dispatch_handler lua_dispatch = {
diff --git a/proxy.c b/proxy.c
index 27c856b..da22136 100644
--- a/proxy.c
+++ b/proxy.c
@@ -389,14 +389,14 @@ static void proxy_handle_request(struct client *cl, char *url, struct path_info
 
 }
 
-static bool check_proxy_url(const char *url)
+static const char *check_proxy_url(const char *url)
 {
         struct proxy_uri *p;
 
         if (!list_empty(&conf.proxies)) list_for_each_entry(p, &conf.proxies, list)
 		if (uh_path_match(p->prefix, url))
-			return true;
-	return false;
+			return p->prefix;
+	return NULL;
 }
 
 struct dispatch_handler proxy_dispatch = {
diff --git a/ubus.c b/ubus.c
index f7d1f11..ed70c50 100644
--- a/ubus.c
+++ b/ubus.c
@@ -640,10 +640,12 @@ static void uh_ubus_handle_request(struct client *cl, char *url, struct path_inf
 	}
 }
 
-static bool
+static const char *
 uh_ubus_check_url(const char *url)
 {
-	return ops->path_match(conf.ubus_prefix, url);
+	if (ops->path_match(conf.ubus_prefix, url))
+		return conf.ubus_prefix;
+	return NULL;
 }
 
 static int
diff --git a/uhttpd.h b/uhttpd.h
index d47b7b4..6569251 100644
--- a/uhttpd.h
+++ b/uhttpd.h
@@ -214,7 +214,7 @@ struct dispatch_handler {
 	struct list_head list;
 	bool script;
 
-	bool (*check_url)(const char *url);
+	const char * (*check_url)(const char *url);
 	bool (*check_path)(struct path_info *pi, const char *url);
 	void (*handle_request)(struct client *cl, char *url, struct path_info *pi);
 };
-- 
1.9.1




More information about the Lede-dev mailing list