[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