Skip to content

Commit

Permalink
feat: add a path handler using wildcards
Browse files Browse the repository at this point in the history
```
srv->add_path_handler(srv, "^/cgi-bin/", cgi_handler);
srv->add_path_handler(srv, "^/cgi-bin/test$", cgi_test_handler);
srv->add_path_handler(srv, "test", test_handler);
```

Signed-off-by: Jianhui Zhao <zhaojh329@gmail.com>
  • Loading branch information
zhaojh329 committed Aug 20, 2021
1 parent 5d7660e commit c8bcc63
Show file tree
Hide file tree
Showing 3 changed files with 104 additions and 10 deletions.
63 changes: 55 additions & 8 deletions src/connection.c
Expand Up @@ -453,27 +453,74 @@ static int on_header_value_cb(struct http_parser *parser, const char *at, size_t
return 0;
}

static bool set_path_handler(struct uh_connection_internal *conn, struct uh_path_handler *h,
struct uh_str *path, bool wildcard)
{
while (h) {
if (wildcard) {
int match = 0;

if (!(h->flags & UH_PATH_WILDCARD))
goto next;

if (path->len < h->len)
goto next;

if (h->flags & UH_PATH_MATCH_START) {
if (strncmp(path->p, h->path, h->len))
goto next;
match++;
}

if (h->flags & UH_PATH_MATCH_END) {
if (strncmp(path->p + (path->len - h->len), h->path, h->len))
goto next;
match++;
}

if (!match && !memmem(path->p, path->len, h->path, h->len))
goto next;

conn->handler = h->handler;
return true;
} else {
if (h->flags & UH_PATH_WILDCARD)
goto next;

if (h->len == path->len && !strncmp(path->p, h->path, path->len)) {
conn->handler = h->handler;
return true;
}
}

next:
h = h->next;
}

return false;
}

static int on_headers_complete(struct http_parser *parser)
{
struct uh_connection_internal *conn = (struct uh_connection_internal *)parser->data;
struct uh_server_internal *srv = conn->srv;
struct uh_request *req = &conn->req;
struct uh_path_handler *h = srv->handlers;
struct uh_plugin *p = srv->plugins;
struct uh_str path;

http_parser_parse_url(O2D(conn, req->url.offset), req->url.length, false, &conn->url_parser);

path = conn->com.get_path(&conn->com);

while (h) {
if (strlen(h->path) == path.len && !strncmp(path.p, h->path, path.len)) {
conn->handler = h->handler;
goto done;
}
h = h->next;
}
/* match non wildcard path handler */
if (set_path_handler(conn, srv->handlers, &path, false))
goto done;

/* match wildcard path handler */
if (set_path_handler(conn, srv->handlers, &path, true))
goto done;

/* match plugin */
while (p) {
if (strlen(p->h->path) == path.len && !strncmp(path.p, p->h->path, path.len)) {
conn->handler = p->h->handler;
Expand Down
35 changes: 33 additions & 2 deletions src/uhttpd.c
Expand Up @@ -235,10 +235,27 @@ static int uh_load_plugin(struct uh_server *srv, const char *path)
#endif
}

static int uh_add_path_handler(struct uh_server *srv, const char *path, uh_path_handler_prototype handler)
static int __uh_add_path_handler(struct uh_server *srv, const char *path, uh_path_handler_prototype handler, bool wildcard)
{
struct uh_server_internal *srvi = (struct uh_server_internal *)srv;
int path_len = strlen(path);
struct uh_path_handler *h;
uint8_t flags = 0;

if (wildcard) {
flags |= UH_PATH_WILDCARD;

if (path[0] == '^') {
flags |= UH_PATH_MATCH_START;
path_len--;
path++;
}

if (path[path_len - 1] == '$') {
flags |= UH_PATH_MATCH_END;
path_len--;
}
}

h = calloc(1, sizeof(struct uh_path_handler) + strlen(path) + 1);
if (!h) {
Expand All @@ -247,7 +264,10 @@ static int uh_add_path_handler(struct uh_server *srv, const char *path, uh_path_
}

h->handler = handler;
strcpy(h->path, path);
h->flags = flags;
h->len = path_len;

strncpy(h->path, path, path_len);

if (!srvi->handlers) {
srvi->handlers = h;
Expand All @@ -260,6 +280,16 @@ static int uh_add_path_handler(struct uh_server *srv, const char *path, uh_path_
return 0;
}

static int uh_add_path_handler(struct uh_server *srv, const char *path, uh_path_handler_prototype handler)
{
return __uh_add_path_handler(srv, path, handler, false);
}

static int uh_add_path_handler_wildcard(struct uh_server *srv, const char *path, uh_path_handler_prototype handler)
{
return __uh_add_path_handler(srv, path, handler, true);
}

static void uh_set_conn_abort_cb(struct uh_server *srv, uh_con_closed_cb_prototype cb)
{
struct uh_server_internal *srvi = (struct uh_server_internal *)srv;
Expand Down Expand Up @@ -471,6 +501,7 @@ void uh_server_init(struct uh_server *srv, struct ev_loop *loop)
srv->set_conn_closed_cb = uh_set_conn_abort_cb;
srv->set_default_handler = uh_set_default_handler;
srv->add_path_handler = uh_add_path_handler;
srv->add_path_handler_w = uh_add_path_handler_wildcard;

srv->set_docroot = uh_set_docroot;
srv->set_index_page = uh_set_index_page;
Expand Down
16 changes: 16 additions & 0 deletions src/uhttpd.h
Expand Up @@ -108,6 +108,14 @@ struct uh_server {
void (*set_conn_closed_cb)(struct uh_server *srv, uh_con_closed_cb_prototype cb);
void (*set_default_handler)(struct uh_server *srv, uh_path_handler_prototype handler);
int (*add_path_handler)(struct uh_server *srv, const char *path, uh_path_handler_prototype handler);
/*
** Similar with 'add_path_handler', but treats 'path' as wildcard
**
** ^/cgi-bin/ matches the starting position within the path
** ^/cgi-bin/test$ matches the starting position and the ending position within the path
** test matches any position within the path
*/
int (*add_path_handler_w)(struct uh_server *srv, const char *path, uh_path_handler_prototype handler);
int (*set_docroot)(struct uh_server *srv, const char *path);
int (*set_index_page)(struct uh_server *srv, const char *name);
};
Expand All @@ -123,9 +131,17 @@ struct uh_plugin {
struct uh_plugin *next;
};

enum {
UH_PATH_WILDCARD = (1 << 0),
UH_PATH_MATCH_START = (1 << 1),
UH_PATH_MATCH_END = (1 << 2)
};

struct uh_path_handler {
uh_path_handler_prototype handler;
struct uh_path_handler *next;
uint8_t flags;
uint8_t len;
char path[0];
};

Expand Down

0 comments on commit c8bcc63

Please sign in to comment.