summaryrefslogtreecommitdiff
path: root/create.c
diff options
context:
space:
mode:
Diffstat (limited to 'create.c')
-rw-r--r--create.c238
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);
+}