diff --git a/main.c b/main.c index 8a15e06..df8cd21 100644 --- a/main.c +++ b/main.c @@ -980,6 +980,61 @@ end: return ret; } +static int getnode_head(const struct http_payload *const p, + struct http_response *const r, void *const user) +{ + struct auth *const a = user; + + if (auth_cookie(a, &p->cookie)) + { + fprintf(stderr, "%s: auth_cookie failed\n", __func__); + return page_forbidden(r); + } + + const char *const username = p->cookie.field, + *const resource = p->resource + strlen("/user/"); + + if (path_invalid(resource)) + { + fprintf(stderr, "%s: illegal relative path %s\n", __func__, resource); + return page_forbidden(r); + } + + int ret = -1; + struct dynstr dir, root, d; + const char *const adir = auth_dir(a), + *const sep = p->resource[strlen(p->resource) - 1] != '/' ? "/" : ""; + + dynstr_init(&dir); + dynstr_init(&d); + dynstr_init(&root); + + if (!adir) + { + fprintf(stderr, "%s: auth_dir failed\n", __func__); + goto end; + } + else if (dynstr_append(&dir, "%s%s", p->resource, sep)) + { + fprintf(stderr, "%s: dynstr_append dird failed\n", __func__); + goto end; + } + else if (dynstr_append(&root, "%s/user/%s/", adir, username) + || dynstr_append(&d, "%s%s", root.str, resource)) + { + fprintf(stderr, "%s: dynstr_append failed\n", __func__); + goto end; + } + + ret = page_head_resource(r, d.str); + +end: + dynstr_free(&dir); + dynstr_free(&d); + dynstr_free(&root); + return ret; +} + static int move_file(const char *const old, const char *const new) { int ret = -1; @@ -1924,6 +1979,7 @@ static int add_urls(struct handler *const h, void *const user) {.url = "/index.html", .op = HTTP_OP_GET, .f = serve_index}, {.url = "/style.css", .op = HTTP_OP_GET, .f = serve_style}, {.url = "/user/*", .op = HTTP_OP_GET, .f = getnode}, + {.url = "/user/*", .op = HTTP_OP_HEAD, .f = getnode_head}, {.url = "/login", .op = HTTP_OP_POST, .f = login}, {.url = "/logout", .op = HTTP_OP_POST, .f = logout}, {.url = "/public/*", .op = HTTP_OP_GET, .f = getpublic}, diff --git a/page.c b/page.c index f3856a9..02049a3 100644 --- a/page.c +++ b/page.c @@ -2199,3 +2199,36 @@ end: return ret; } + +int page_head_resource(struct http_response *const r, const char *const res) +{ + struct stat sb; + + if (stat(res, &sb)) + { + if (errno == ENOENT || errno == ENOTDIR) + return page_not_found(r); + else + { + fprintf(stderr, "%s: stat(2) %s: %s\n", + __func__, res, strerror(errno)); + return -1; + } + } + + const mode_t m = sb.st_mode; + + if (!S_ISDIR(m) && !S_ISREG(m)) + { + fprintf(stderr, "%s: unexpected st_mode %jd\n", __func__, (intmax_t)m); + return -1; + } + + *r = (const struct http_response) + { + .status = HTTP_STATUS_OK, + .n = sb.st_size + }; + + return 0; +} diff --git a/page.h b/page.h index 01e7a0a..22658fd 100644 --- a/page.h +++ b/page.h @@ -43,6 +43,7 @@ int page_failed_login(struct http_response *r); int page_forbidden(struct http_response *r); int page_bad_request(struct http_response *r); int page_resource(const struct page_resource *r); +int page_head_resource(struct http_response *r, const char *res); 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,