parent
17502e7e32
commit
2648076370
|
@ -12,6 +12,7 @@ add_executable(${PROJECT_NAME}
|
|||
main.c
|
||||
page.c
|
||||
server.c
|
||||
wildcard_cmp.c
|
||||
)
|
||||
target_compile_options(${PROJECT_NAME} PRIVATE -Wall)
|
||||
target_compile_definitions(${PROJECT_NAME} PRIVATE _FILE_OFFSET_BITS=64)
|
||||
|
|
3
Makefile
3
Makefile
|
@ -20,7 +20,8 @@ OBJECTS = \
|
|||
jwt.o \
|
||||
main.o \
|
||||
page.o \
|
||||
server.o
|
||||
server.o \
|
||||
wildcard_cmp.o \
|
||||
|
||||
all: $(PROJECT)
|
||||
|
||||
|
|
3
cftw.c
3
cftw.c
|
@ -29,12 +29,13 @@ int cftw(const char *const dirpath, int (*const fn)(const char *,
|
|||
if (!strcmp(path, ".") || !strcmp(path, ".."))
|
||||
continue;
|
||||
|
||||
const char *const sep = dirpath[strlen(dirpath) - 1] == '/' ? "" : "/";
|
||||
struct stat sb;
|
||||
struct dynstr d;
|
||||
|
||||
dynstr_init(&d);
|
||||
|
||||
if (dynstr_append(&d, "%s/%s", dirpath, path))
|
||||
if (dynstr_append(&d, "%s%s%s", dirpath, sep, path))
|
||||
{
|
||||
fprintf(stderr, "%s: dynstr_append failed\n", __func__);
|
||||
return -1;
|
||||
|
|
45
handler.c
45
handler.c
|
@ -3,6 +3,7 @@
|
|||
#include "handler.h"
|
||||
#include "http.h"
|
||||
#include "server.h"
|
||||
#include "wildcard_cmp.h"
|
||||
#include <errno.h>
|
||||
#include <stdbool.h>
|
||||
#include <stddef.h>
|
||||
|
@ -47,48 +48,6 @@ static int on_write(const void *const buf, const size_t n, void *const user)
|
|||
return server_write(buf, n, c->c);
|
||||
}
|
||||
|
||||
static int wildcard_cmp(const char *s, const char *p)
|
||||
{
|
||||
while (*p && *s)
|
||||
{
|
||||
const char *const wc = strchr(p, '*');
|
||||
|
||||
if (!wc)
|
||||
return strcmp(s, p);
|
||||
|
||||
const size_t n = wc - p;
|
||||
|
||||
if (n)
|
||||
{
|
||||
const int r = strncmp(s, p, n);
|
||||
|
||||
if (r)
|
||||
return r;
|
||||
|
||||
p += n;
|
||||
s += n;
|
||||
}
|
||||
else if (*(wc + 1) == *s)
|
||||
{
|
||||
p = wc + 1;
|
||||
s += n;
|
||||
}
|
||||
else if (*(wc + 1) == '*')
|
||||
p++;
|
||||
else
|
||||
{
|
||||
s++;
|
||||
p += n;
|
||||
}
|
||||
}
|
||||
|
||||
while (*p)
|
||||
if (*p++ != '*')
|
||||
return -1;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int on_payload(const struct http_payload *const p,
|
||||
struct http_response *const r, void *const user)
|
||||
{
|
||||
|
@ -99,7 +58,7 @@ static int on_payload(const struct http_payload *const p,
|
|||
{
|
||||
const struct elem *const e = &h->elem[i];
|
||||
|
||||
if (e->op == p->op && !wildcard_cmp(p->resource, e->url))
|
||||
if (e->op == p->op && !wildcard_cmp(p->resource, e->url, true))
|
||||
return e->f(p, r, e->user);
|
||||
}
|
||||
|
||||
|
|
242
main.c
242
main.c
|
@ -6,6 +6,7 @@
|
|||
#include "hex.h"
|
||||
#include "http.h"
|
||||
#include "page.h"
|
||||
#include "wildcard_cmp.h"
|
||||
#include <openssl/err.h>
|
||||
#include <openssl/rand.h>
|
||||
#include <dynstr.h>
|
||||
|
@ -464,19 +465,248 @@ end:
|
|||
return ret;
|
||||
}
|
||||
|
||||
static int check_search_input(const struct http_payload *const p,
|
||||
int (**const f)(struct http_response *), const struct auth *const a,
|
||||
char **const dir, struct dynstr *const res)
|
||||
{
|
||||
int ret = auth_cookie(a, &p->cookie);
|
||||
struct form *forms = NULL;
|
||||
size_t n = 0;
|
||||
|
||||
if (ret < 0)
|
||||
{
|
||||
fprintf(stderr, "%s: auth_cookie failed\n", __func__);
|
||||
goto end;
|
||||
}
|
||||
else if (ret)
|
||||
{
|
||||
*f = page_forbidden;
|
||||
goto end;
|
||||
}
|
||||
else if ((ret = get_forms(p, &forms, &n)))
|
||||
{
|
||||
if (ret < 0)
|
||||
fprintf(stderr, "%s: get_forms failed\n", __func__);
|
||||
else
|
||||
*f = page_bad_request;
|
||||
|
||||
goto end;
|
||||
}
|
||||
|
||||
const char *tdir = NULL, *tres = NULL;
|
||||
|
||||
for (size_t i = 0; i < n; i++)
|
||||
{
|
||||
const struct form *const f = &forms[i];
|
||||
|
||||
if (!strcmp(f->key, "dir"))
|
||||
tdir = f->value;
|
||||
else if (!strcmp(f->key, "name"))
|
||||
tres = f->value;
|
||||
}
|
||||
|
||||
if (!tdir)
|
||||
{
|
||||
fprintf(stderr, "%s: expected non-null directory\n", __func__);
|
||||
ret = 1;
|
||||
*f = page_bad_request;
|
||||
goto end;
|
||||
}
|
||||
else if (!tres)
|
||||
{
|
||||
fprintf(stderr, "%s: expected non-null resource\n", __func__);
|
||||
ret = 1;
|
||||
*f = page_bad_request;
|
||||
goto end;
|
||||
}
|
||||
else if (path_isrel(tdir) || *tdir != '/')
|
||||
{
|
||||
fprintf(stderr, "%s: invalid directory %s\n", __func__, tdir);
|
||||
ret = 1;
|
||||
*f = page_bad_request;
|
||||
goto end;
|
||||
}
|
||||
else if (strchr(tres, '/') || path_isrel(tres))
|
||||
{
|
||||
fprintf(stderr, "%s: invalid resource %s\n", __func__, tres);
|
||||
ret = 1;
|
||||
*f = page_bad_request;
|
||||
goto end;
|
||||
}
|
||||
else if (!(*dir = strdup(tdir)))
|
||||
{
|
||||
fprintf(stderr, "%s: strdup(3) dir: %s\n", __func__, strerror(errno));
|
||||
ret = -1;
|
||||
goto end;
|
||||
}
|
||||
else if (dynstr_append(res, "*%s*", tres))
|
||||
{
|
||||
fprintf(stderr, "%s: dynstr_append failed\n", __func__);
|
||||
ret = -1;
|
||||
goto end;
|
||||
}
|
||||
|
||||
end:
|
||||
forms_free(forms, n);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void search_result_free(struct page_search_result *const r)
|
||||
{
|
||||
if (r)
|
||||
free(r->name);
|
||||
}
|
||||
|
||||
static void search_results_free(struct page_search *const s)
|
||||
{
|
||||
if (s)
|
||||
{
|
||||
for (size_t i = 0; i < s->n; i++)
|
||||
search_result_free(&s->results[i]);
|
||||
|
||||
free(s->results);
|
||||
}
|
||||
}
|
||||
|
||||
struct search_args
|
||||
{
|
||||
const char *root, *res;
|
||||
struct page_search *s;
|
||||
};
|
||||
|
||||
static int search_fn(const char *const fpath, const struct stat *const sb,
|
||||
void *const user)
|
||||
{
|
||||
int ret = -1;
|
||||
const struct search_args *const sa = user;
|
||||
const char *const rel = fpath + strlen(sa->root) + 1;
|
||||
struct page_search *const res = sa->s;
|
||||
struct page_search_result *results = NULL, *r = NULL;
|
||||
|
||||
if (wildcard_cmp(rel, sa->res, false))
|
||||
{
|
||||
ret = 0;
|
||||
goto end;
|
||||
}
|
||||
else if (!(results = realloc(res->results,
|
||||
(res->n + 1) * sizeof *res->results)))
|
||||
{
|
||||
fprintf(stderr, "%s: realloc(3): %s\n", __func__, strerror(errno));
|
||||
goto end;
|
||||
}
|
||||
|
||||
r = &results[res->n];
|
||||
|
||||
/* Call strdup(3) again to ensure a pointer to the heap (remember
|
||||
* dirname(3) and basename(3) might return a pointer to static data). */
|
||||
*r = (const struct page_search_result)
|
||||
{
|
||||
.name = strdup(rel)
|
||||
};
|
||||
|
||||
if (!r->name)
|
||||
{
|
||||
fprintf(stderr, "%s: strdup(3) r->name: %s",
|
||||
__func__, strerror(errno));
|
||||
goto end;
|
||||
}
|
||||
|
||||
res->results = results;
|
||||
res->n++;
|
||||
ret = 0;
|
||||
|
||||
end:
|
||||
|
||||
if (ret)
|
||||
{
|
||||
free(results);
|
||||
search_result_free(r);
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int do_search(const char *const abs, const char *const root,
|
||||
const char *const res, struct page_search *const s)
|
||||
{
|
||||
struct search_args sa =
|
||||
{
|
||||
.root = root,
|
||||
.res = res,
|
||||
.s = s
|
||||
};
|
||||
|
||||
s->root = root;
|
||||
|
||||
if (cftw(abs, search_fn, &sa))
|
||||
{
|
||||
fprintf(stderr, "%s: cftw failed\n", __func__);
|
||||
return -1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int search(const struct http_payload *const p,
|
||||
struct http_response *const r, void *const user)
|
||||
{
|
||||
struct auth *const a = user;
|
||||
int ret = -1;
|
||||
const struct auth *const a = user;
|
||||
const char *const username = p->cookie.field, *const root = auth_dir(a);
|
||||
struct page_search s = {0};
|
||||
int (*f)(struct http_response *);
|
||||
char *dir = NULL;
|
||||
struct dynstr userd, d, res;
|
||||
|
||||
if (auth_cookie(a, &p->cookie))
|
||||
dynstr_init(&userd);
|
||||
dynstr_init(&d);
|
||||
dynstr_init(&res);
|
||||
|
||||
if (!root)
|
||||
{
|
||||
fprintf(stderr, "%s: auth_cookie failed\n", __func__);
|
||||
return page_forbidden(r);
|
||||
fprintf(stderr, "%s: auth_dir failed\n", __func__);
|
||||
goto end;
|
||||
}
|
||||
else if ((ret = check_search_input(p, &f, a, &dir, &res)))
|
||||
{
|
||||
if (ret < 0)
|
||||
fprintf(stderr, "%s: check_search_input failed\n", __func__);
|
||||
else if ((ret = f(r)))
|
||||
fprintf(stderr, "%s: check_search_input callback failed\n",
|
||||
__func__);
|
||||
|
||||
goto end;
|
||||
}
|
||||
else if (dynstr_append(&userd, "%s/user/%s", root, username))
|
||||
{
|
||||
fprintf(stderr, "%s: dynstr_append userd failed\n", __func__);
|
||||
goto end;
|
||||
}
|
||||
else if (dynstr_append(&d, "%s%s", userd.str, dir))
|
||||
{
|
||||
fprintf(stderr, "%s: dynstr_append d failed\n", __func__);
|
||||
goto end;
|
||||
}
|
||||
else if ((ret = do_search(d.str, userd.str, res.str, &s)))
|
||||
{
|
||||
if (ret < 0)
|
||||
fprintf(stderr, "%s: do_search failed\n", __func__);
|
||||
|
||||
goto end;
|
||||
}
|
||||
else if ((ret = page_search(r, &s)))
|
||||
{
|
||||
fprintf(stderr, "%s: page_search failed\n", __func__);
|
||||
goto end;
|
||||
}
|
||||
|
||||
fprintf(stderr, "%s: TODO\n", __func__);
|
||||
return -1;
|
||||
end:
|
||||
free(dir);
|
||||
dynstr_free(&userd);
|
||||
dynstr_free(&d);
|
||||
dynstr_free(&res);
|
||||
search_results_free(&s);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int share(const struct http_payload *const p,
|
||||
|
|
250
page.c
250
page.c
|
@ -283,6 +283,9 @@ end:
|
|||
return ret;
|
||||
}
|
||||
|
||||
/* dir: /user/test */
|
||||
/* res: /home/xavier/db/user/a/test/ */
|
||||
/* name: FB_IMG_1539173215088.jpg */
|
||||
static int add_element(struct html_node *const n, const char *const dir,
|
||||
const char *const res, const char *const name)
|
||||
{
|
||||
|
@ -354,6 +357,86 @@ end:
|
|||
return ret;
|
||||
}
|
||||
|
||||
static int prepare_search_form(struct html_node *const n, const char *const dir)
|
||||
{
|
||||
struct html_node *div, *form, *hidden, *submit, *input;
|
||||
|
||||
if (!(div = html_node_add_child(n, "div")))
|
||||
{
|
||||
fprintf(stderr, "%s: html_node_add_child div failed\n", __func__);
|
||||
return -1;
|
||||
}
|
||||
else if (!(form = html_node_add_child(div, "form")))
|
||||
{
|
||||
fprintf(stderr, "%s: html_node_add_child form failed\n", __func__);
|
||||
return -1;
|
||||
}
|
||||
else if (!(input = html_node_add_child(form, "input")))
|
||||
{
|
||||
fprintf(stderr, "%s: html_node_add_child input failed\n", __func__);
|
||||
return -1;
|
||||
}
|
||||
else if (!(hidden = html_node_add_child(form, "input")))
|
||||
{
|
||||
fprintf(stderr, "%s: html_node_add_child hidden failed\n", __func__);
|
||||
return -1;
|
||||
}
|
||||
else if (!(submit = html_node_add_child(form, "input")))
|
||||
{
|
||||
fprintf(stderr, "%s: html_node_add_child submit failed\n", __func__);
|
||||
return -1;
|
||||
}
|
||||
else if (html_node_add_attr(form, "method", "post"))
|
||||
{
|
||||
fprintf(stderr, "%s: html_node_add_attr method failed\n", __func__);
|
||||
return -1;
|
||||
}
|
||||
else if (html_node_add_attr(form, "action", "/search"))
|
||||
{
|
||||
fprintf(stderr, "%s: html_node_add_attr method failed\n", __func__);
|
||||
return -1;
|
||||
}
|
||||
else if (html_node_add_attr(hidden, "type", "hidden"))
|
||||
{
|
||||
fprintf(stderr, "%s: html_node_add_attr hidden failed\n", __func__);
|
||||
return -1;
|
||||
}
|
||||
else if (html_node_add_attr(hidden, "name", "dir"))
|
||||
{
|
||||
fprintf(stderr, "%s: html_node_add_attr dir failed\n", __func__);
|
||||
return -1;
|
||||
}
|
||||
else if (html_node_add_attr(hidden, "value", dir))
|
||||
{
|
||||
fprintf(stderr, "%s: html_node_add_attr hidden value failed\n",
|
||||
__func__);
|
||||
return -1;
|
||||
}
|
||||
else if (html_node_add_attr(submit, "type", "submit"))
|
||||
{
|
||||
fprintf(stderr, "%s: html_node_add_attr submit failed\n", __func__);
|
||||
return -1;
|
||||
}
|
||||
else if (html_node_add_attr(submit, "value", "Search"))
|
||||
{
|
||||
fprintf(stderr, "%s: html_node_add_attr submit value failed\n",
|
||||
__func__);
|
||||
return -1;
|
||||
}
|
||||
else if (html_node_add_attr(input, "type", "text"))
|
||||
{
|
||||
fprintf(stderr, "%s: html_node_add_attr text failed\n", __func__);
|
||||
return -1;
|
||||
}
|
||||
else if (html_node_add_attr(input, "name", "name"))
|
||||
{
|
||||
fprintf(stderr, "%s: html_node_add_attr name failed\n", __func__);
|
||||
return -1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int prepare_upload_form(struct html_node *const n, const char *const dir)
|
||||
{
|
||||
struct html_node *div, *hidden, *form, *submit, *input;
|
||||
|
@ -857,6 +940,11 @@ static struct html_node *resource_layout(const char *const dir,
|
|||
fprintf(stderr, "%s: common_head failed\n", __func__);
|
||||
goto end;
|
||||
}
|
||||
else if (prepare_search_form(body, fdir))
|
||||
{
|
||||
fprintf(stderr, "%s: prepare_search_form failed\n", __func__);
|
||||
goto end;
|
||||
}
|
||||
else if (prepare_upload_form(body, fdir))
|
||||
{
|
||||
fprintf(stderr, "%s: prepare_upload_form failed\n", __func__);
|
||||
|
@ -1103,7 +1191,7 @@ int page_resource(const struct page_resource *const pr)
|
|||
fprintf(stderr, "%s: stat(2) %s: %s\n",
|
||||
__func__, pr->res, strerror(errno));
|
||||
|
||||
if (errno == ENOENT)
|
||||
if (errno == ENOENT || errno == ENOTDIR)
|
||||
return page_not_found(pr->r);
|
||||
else
|
||||
return -1;
|
||||
|
@ -1314,7 +1402,7 @@ int page_bad_request(struct http_response *const r)
|
|||
int page_style(struct http_response *const r)
|
||||
{
|
||||
static const char body[] =
|
||||
"body, input\n"
|
||||
"body\n"
|
||||
"{\n"
|
||||
" font-family: 'Courier New', Courier, monospace;\n"
|
||||
"}\n"
|
||||
|
@ -1328,13 +1416,9 @@ int page_style(struct http_response *const r)
|
|||
"}\n"
|
||||
".userform\n"
|
||||
"{\n"
|
||||
" padding: 4px;\n"
|
||||
" padding: 10px;\n"
|
||||
"}\n"
|
||||
".loginform\n"
|
||||
"{\n"
|
||||
" display: grid;\n"
|
||||
"}\n"
|
||||
"form, label, table, input\n"
|
||||
"form, label, table\n"
|
||||
"{\n"
|
||||
" margin: auto;\n"
|
||||
"}\n"
|
||||
|
@ -1343,7 +1427,7 @@ int page_style(struct http_response *const r)
|
|||
" align-items: center;\n"
|
||||
" display: grid;\n"
|
||||
"}\n"
|
||||
"input\n"
|
||||
"input, .abutton\n"
|
||||
"{\n"
|
||||
" margin:auto;\n"
|
||||
" border: 1px solid;\n"
|
||||
|
@ -1544,3 +1628,151 @@ end:
|
|||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int add_search_results(struct html_node *const n,
|
||||
const struct page_search *const s)
|
||||
{
|
||||
struct html_node *table;
|
||||
|
||||
if (!(table = html_node_add_child(n, "table")))
|
||||
{
|
||||
fprintf(stderr, "%s: html_node_add_child table failed\n", __func__);
|
||||
return -1;
|
||||
}
|
||||
|
||||
for (size_t i = 0; i < s->n; i++)
|
||||
{
|
||||
const struct page_search_result *const r = &s->results[i];
|
||||
|
||||
if (add_element(table, "/user/", s->root, r->name))
|
||||
{
|
||||
fprintf(stderr, "%s: add_element failed\n", __func__);
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int prepare_back_button(struct html_node *const n)
|
||||
{
|
||||
struct html_node *div, *a;
|
||||
|
||||
if (!(div = html_node_add_child(n, "div")))
|
||||
{
|
||||
fprintf(stderr, "%s: html_node_add_child div failed\n", __func__);
|
||||
return -1;
|
||||
}
|
||||
else if (!(a = html_node_add_child(div, "a")))
|
||||
{
|
||||
fprintf(stderr, "%s: html_node_add_child a failed\n", __func__);
|
||||
return -1;
|
||||
}
|
||||
else if (html_node_add_attr(div, "class", "userform"))
|
||||
{
|
||||
fprintf(stderr, "%s: html_node_add_attr div failed\n", __func__);
|
||||
return -1;
|
||||
}
|
||||
else if (html_node_add_attr(a, "class", "abutton"))
|
||||
{
|
||||
fprintf(stderr, "%s: html_node_add_attr a class failed\n", __func__);
|
||||
return -1;
|
||||
}
|
||||
else if (html_node_add_attr(a, "href", "/user/"))
|
||||
{
|
||||
fprintf(stderr, "%s: html_node_add_attr a href failed\n", __func__);
|
||||
return -1;
|
||||
}
|
||||
else if (html_node_set_value(a, "Back"))
|
||||
{
|
||||
fprintf(stderr, "%s: html_node_set_value failed\n", __func__);
|
||||
return -1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int page_search(struct http_response *const r,
|
||||
const struct page_search *const s)
|
||||
{
|
||||
int ret = -1;
|
||||
struct dynstr out;
|
||||
struct html_node *const html = html_node_alloc("html"), *head, *body;
|
||||
|
||||
dynstr_init(&out);
|
||||
|
||||
if (!html)
|
||||
{
|
||||
fprintf(stderr, "%s: html_node_alloc failed\n", __func__);
|
||||
goto end;
|
||||
}
|
||||
else if (!(head = html_node_add_child(html, "head")))
|
||||
{
|
||||
fprintf(stderr, "%s: html_node_add_child head failed\n", __func__);
|
||||
goto end;
|
||||
}
|
||||
else if (!(body = html_node_add_child(html, "body")))
|
||||
{
|
||||
fprintf(stderr, "%s: html_node_add_child body failed\n", __func__);
|
||||
goto end;
|
||||
}
|
||||
else if (common_head(head, NULL))
|
||||
{
|
||||
fprintf(stderr, "%s: common_head failed\n", __func__);
|
||||
goto end;
|
||||
}
|
||||
else if (s->n && add_search_results(body, s))
|
||||
{
|
||||
fprintf(stderr, "%s: add_search_results failed\n", __func__);
|
||||
goto end;
|
||||
}
|
||||
else if (!s->n && html_node_set_value(body, "No results found"))
|
||||
{
|
||||
fprintf(stderr, "%s: html_node_set_value msg failed\n", __func__);
|
||||
goto end;
|
||||
}
|
||||
else if (prepare_back_button(body))
|
||||
{
|
||||
fprintf(stderr, "%s: prepare_back_button failed\n", __func__);
|
||||
goto end;
|
||||
}
|
||||
else if (prepare_footer(body))
|
||||
{
|
||||
fprintf(stderr, "%s: prepare_footer failed\n", __func__);
|
||||
goto end;
|
||||
}
|
||||
else if (dynstr_append(&out, DOCTYPE_TAG))
|
||||
{
|
||||
fprintf(stderr, "%s: dynstr_append out failed\n", __func__);
|
||||
goto end;
|
||||
}
|
||||
else if (html_serialize(html, &out))
|
||||
{
|
||||
fprintf(stderr, "%s: html_serialize failed\n", __func__);
|
||||
goto end;
|
||||
}
|
||||
|
||||
*r = (const struct http_response)
|
||||
{
|
||||
.status = HTTP_STATUS_PAYLOAD_TOO_LARGE,
|
||||
.buf.rw = out.str,
|
||||
.n = out.len,
|
||||
.free = free
|
||||
};
|
||||
|
||||
if (http_response_add_header(r, "Content-Type", "text/html"))
|
||||
{
|
||||
fprintf(stderr, "%s: http_response_add_header failed\n", __func__);
|
||||
goto end;
|
||||
}
|
||||
|
||||
ret = 0;
|
||||
|
||||
end:
|
||||
html_node_free(html);
|
||||
|
||||
if (ret)
|
||||
dynstr_free(&out);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
|
13
page.h
13
page.h
|
@ -2,6 +2,7 @@
|
|||
#define PAGE_H
|
||||
|
||||
#include "http.h"
|
||||
#include <stddef.h>
|
||||
|
||||
struct page_quota
|
||||
{
|
||||
|
@ -17,6 +18,17 @@ struct page_resource
|
|||
size_t n_args;
|
||||
};
|
||||
|
||||
struct page_search
|
||||
{
|
||||
struct page_search_result
|
||||
{
|
||||
char *name;
|
||||
} *results;
|
||||
|
||||
const char *root;
|
||||
size_t n;
|
||||
};
|
||||
|
||||
int page_login(struct http_response *r);
|
||||
int page_style(struct http_response *r);
|
||||
int page_failed_login(struct http_response *r);
|
||||
|
@ -27,5 +39,6 @@ int page_public(struct http_response *r, const char *res);
|
|||
int page_share(struct http_response *r, const char *path);
|
||||
int page_quota_exceeded(struct http_response *r, unsigned long long len,
|
||||
unsigned long long quota);
|
||||
int page_search(struct http_response *r, const struct page_search *s);
|
||||
|
||||
#endif /* PAGE_H */
|
||||
|
|
|
@ -0,0 +1,57 @@
|
|||
#include "wildcard_cmp.h"
|
||||
#include <stdbool.h>
|
||||
#include <stddef.h>
|
||||
#include <string.h>
|
||||
#include <strings.h>
|
||||
|
||||
int wildcard_cmp(const char *s, const char *p, const bool casecmp)
|
||||
{
|
||||
int (*const cmp)(const char *, const char *) =
|
||||
casecmp ? strcmp : strcasecmp;
|
||||
int (*const ncmp)(const char *, const char *, size_t) =
|
||||
casecmp ? strncmp : strncasecmp;
|
||||
|
||||
while (*p && *s)
|
||||
{
|
||||
const char *const wc = strchr(p, '*');
|
||||
|
||||
if (!wc)
|
||||
return cmp(s, p);
|
||||
|
||||
const size_t n = wc - p;
|
||||
|
||||
if (n)
|
||||
{
|
||||
const int r = ncmp(s, p, n);
|
||||
|
||||
if (r)
|
||||
return r;
|
||||
|
||||
p += n;
|
||||
s += n;
|
||||
}
|
||||
else
|
||||
{
|
||||
const char next = *(wc + 1), wca[2] = {next}, sa[sizeof wca] = {*s};
|
||||
|
||||
if (!cmp(wca, sa))
|
||||
{
|
||||
p = wc + 1;
|
||||
s += n;
|
||||
}
|
||||
else if (next == '*')
|
||||
p++;
|
||||
else
|
||||
{
|
||||
s++;
|
||||
p += n;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
while (*p)
|
||||
if (*p++ != '*')
|
||||
return -1;
|
||||
|
||||
return 0;
|
||||
}
|
|
@ -0,0 +1,8 @@
|
|||
#ifndef WILDCARD_CMP_H
|
||||
#define WILDCARD_CMP_H
|
||||
|
||||
#include <stdbool.h>
|
||||
|
||||
int wildcard_cmp(const char *s, const char *p, bool casecmp);
|
||||
|
||||
#endif /* WILDCARD_CMP_H */
|
Loading…
Reference in New Issue