diff options
Diffstat (limited to 'create.c')
-rw-r--r-- | create.c | 238 |
1 files changed, 238 insertions, 0 deletions
diff --git a/create.c b/create.c new file mode 100644 index 0000000..e5a98b0 --- /dev/null +++ b/create.c @@ -0,0 +1,238 @@ +/* + * Copyright 2025, Vincent Douillet <vincent@vdouillet.fr> + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * 3. Neither the name of the copyright holder nor the names of its contributors + * may be used to endorse or promote products derived from this software without + * specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#include <stdlib.h> +#include <kcgi.h> +#include <kcgihtml.h> +#include <limits.h> +#include <stdio.h> +#include <string.h> + +#include "browse.h" +#include "cgi.h" +#include "http.h" +#include "template.h" +#include "create.h" +#include "url.h" + +/* + * create url = r->pname / CREATE_URL / file->path + */ +size_t +build_create_url(const struct kreq * r, struct file * file) +{ + char action_url[PATH_MAX]; + size_t action_url_len; + + if (!file->is_dir) + return 0; + + action_url_len = url_build(action_url, PATH_MAX, r->pname, CREATE_URL, + file->path, NULL); + if (action_url_len == 0 || action_url_len >= PATH_MAX) { + kutil_warn(r, NULL, + "create: action URL overflow: %s", action_url); + return 0; + } + file->action_url = strndup(action_url, action_url_len); + if (file->action_url == NULL) { + kutil_warn(r, NULL, + "create: unable to allocate file url buffer: %s", + action_url); + return 0; + } + return action_url_len; +} + +/* + * data required in the template functions + */ +struct template_data { + struct kreq *r; + struct khtmlreq *html; + struct file *f; +}; + +static const char *const header_template_keys[] = {"path", "submit_url"}; + +static int +header_template_callback(size_t index, void *arg) +{ + struct kreq *r; + struct khtmlreq *html; + struct template_data *data; + + if (arg == NULL) { + kutil_warn(NULL, NULL, + "Invalid data for create header template"); + return 0; + } + data = arg; + r = data->r; + html = data->html; + + switch (index) { + case 0: + /* path */ + K_OK(khtml_puts(html, data->f->path), r); + break; + case 1: + /* submit_url */ + K_OK(khtml_puts(html, data->f->action_url), r); + break; + default: + kutil_warnx(r, NULL, + "Invalid key index for create header template: %zd", + index); + return 0; + } + + return 1; +} + +/* + * GET request, we print create form + */ +void +create_get(struct kreq * r, struct file * file) +{ + struct khtmlreq html; + struct ktemplate template; + struct page_template *tmpl; + struct template_data data; + + tmpl = NULL; + + /* action url is form submit url */ + if (build_create_url(r, file) == 0) { + http_exit(r, KHTTP_500, "create: Can't build create url"); + goto end; + } + /* read template */ + tmpl = page_template_new(CREATE_URL); + if (tmpl == NULL) { + http_exit(r, KHTTP_500, "create: Unable to read template"); + goto end; + } + /* print create form */ + http_open(r, KHTTP_200, KMIME_TEXT_HTML); + + K_OK(khttp_puts(r, tmpl->header), r); + K_OK(khtml_open(&html, r, 0), r); + + template.key = header_template_keys; + template.keysz = 2; + template.cb = header_template_callback; + template.arg = &data; + data.r = r; + data.html = &html; + data.f = file; + K_OK(khttp_template_buf(r, &template, tmpl->page_header, + strlen(tmpl->page_header)), r); + + K_OK(khttp_puts(r, tmpl->page_footer), r); + K_OK(khttp_puts(r, tmpl->footer), r); + + K_OK(khtml_close(&html), r); + +end: + page_template_free(tmpl); +} + +/* + * POST request, we handle create form + */ +void +create_post(struct kreq * r, struct file * f) +{ + char path[PATH_MAX]; + size_t path_len, i; + struct kpair *name; + + /* prepare action url for return redirection in case of success */ + if (build_browse_url(r, f) == 0) { + http_exit(r, KHTTP_500, "create: can't build return url"); + return; + } + /* validate input data */ + if (r->fieldsz != 1) { + http_exit(r, KHTTP_400, "create: missing folder name"); + return; + } + name = &(r->fields[0]); + /* + * TODO name->val == NULL is not enough, need better sanitization + * for example, some chars are not allowed in a folder name + * an empty non-NULL string is also not ok + */ + if (strncmp(name->key, "name", 4) || name->val == NULL) { + http_exit(r, KHTTP_400, "create: invalide folder name"); + return; + } + path_len = file_get_data_path(f, path, PATH_MAX, name->val); + if (path_len == 0 || path_len >= PATH_MAX) { + http_exit(r, KHTTP_500, + "create: can't build file path"); + return; + } + /* TODO check if folder already exists */ + if (mkdir(path, 0755)) { + http_exit(r, KHTTP_500, + "create: can't create directory"); + return; + } + + /* on success, redirect to the new folder */ + khttp_head(r, kresps[KRESP_LOCATION], "%s", f->action_url); + http_open(r, KHTTP_303, r->mime); +} + +void +create(struct kreq * r) +{ + struct file *file; + + file = NULL; + + /* build file corresponding to request (ie. create) path */ + file = file_new(r->path); + if (file == NULL) { + http_exit(r, KHTTP_404, "create: Unable to build data file"); + goto end; + } + /* print form or handle submission according to HTTP method */ + if (r->method == KMETHOD_POST) + create_post(r, file); + else + create_get(r, file); + +end: + file_free(file); +} |