summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorVincent Douillet <vincent@vdouillet.fr>2024-01-12 18:14:17 +0100
committerVincent Douillet <vincent@vdouillet.fr>2024-01-12 18:26:22 +0100
commit760031b4a74d70bdeaab4ce9aedfe772acd05bd3 (patch)
tree443a456770d5db052a3dfe3d2f1a8e5f66604ccb
parent43f65c76152017420ce723b4d4ef4230ff072818 (diff)
browse: build download url for files
-rw-r--r--Makefile8
-rw-r--r--browse.c106
-rw-r--r--download.c37
-rw-r--r--download.h10
-rw-r--r--file.c138
-rw-r--r--file.h70
-rw-r--r--util.c19
-rw-r--r--util.h10
8 files changed, 331 insertions, 67 deletions
diff --git a/Makefile b/Makefile
index d269beb..2b4d51c 100644
--- a/Makefile
+++ b/Makefile
@@ -30,11 +30,13 @@ CC=cc
CFLAGS_DEPS != pkg-config --cflags kcgi kcgi-html
LDFLAGS_DEPS != pkg-config --libs kcgi kcgi-html
-CFLAGS=-O2 -DLOG_INFO $(CFLAGS_DEPS)
+CFLAGS=-DLOG_INFO $(CFLAGS_DEPS)
LDFLAGS=-static $(LDFLAGS_DEPS)
.if make(debug)
-CFLAGS+=-g -W -Wall -Wextra -DTEMPLATE_DIR='"template"'
+CFLAGS+=-O0 -g -W -Wall -Wextra -DTEMPLATE_DIR='"template"'
+.else
+CFLAGS+=-O2
.endif
debug: main
@@ -44,7 +46,7 @@ all: main
.c.o:
$(CC) -o $@ -c $< $(CFLAGS)
-main: util.o url.o http.o download.o browse.o main.o
+main: util.o url.o http.o file.o download.o browse.o main.o
$(CC) -o $@ $> $(LDFLAGS)
env: env.o
diff --git a/browse.c b/browse.c
index 23a1001..79b3f9c 100644
--- a/browse.c
+++ b/browse.c
@@ -41,81 +41,52 @@
#include "browse.h"
#include "cgi.h"
#include "config.h"
+#include "download.h"
+#include "file.h"
#include "http.h"
#include "url.h"
#include "util.h"
/*
- * list of files for current directory
+ * a list of files
*/
SLIST_HEAD(, file) list;
-struct file {
- char *name;
- char *url;
- SLIST_ENTRY(file) files;
-};
/*
- * should be able to free incomplete files as per file_new usage
+ * browse url = r->pname / BROWSE_URL / file->path / file->name
*/
-static void
-file_free(struct file * file)
+static size_t
+build_browse_url(struct kreq * r, struct file * file)
{
- if (file == NULL)
- return;
-
- if (file->name != NULL) {
- free(file->name);
- file->name = NULL;
- }
- if (file->url != NULL) {
- free(file->url);
- file->url = NULL;
- }
- free(file);
-}
+ char action_url[PATH_MAX];
+ size_t action_url_len;
-static struct file *
-file_new(char *name, size_t name_len, char *url, size_t url_len)
-{
- struct file *file;
+ if (!file->is_dir)
+ return 0;
- file = calloc(1, sizeof(struct file));
- if (file == NULL)
- return NULL;
- file->name = malloc(sizeof(char) * (name_len + 1));
- if (strlcpy(file->name, name, name_len + 1) >= name_len + 1) {
- free(file);
- return NULL;
+ action_url_len = url_build(action_url, PATH_MAX, r->pname, BROWSE_URL,
+ file->path, file->name, NULL);
+ if (action_url_len == 0 || action_url_len >= PATH_MAX) {
+ kutil_warn(r, NULL,
+ "browse: action URL overflow: %s", action_url);
+ return 0;
}
- file->url = malloc(sizeof(char) * (url_len + 1));
- if (strlcpy(file->url, url, url_len + 1) >= url_len + 1) {
- free(file);
- return NULL;
+ file->action_url = v_strcpy(action_url, action_url_len);
+ if (file->action_url == NULL) {
+ kutil_warn(r, NULL,
+ "browse: unable to allocate file url buffer: %s",
+ action_url);
+ return 0;
}
- return file;
-}
-
-/*
- * file url = r->pname / r->pagename / r->path / file_name
- */
-static size_t
-build_browse_url(struct kreq * r, char *url, size_t url_len, const char *file)
-{
- char *page_name;
-
- page_name = strlen(r->pagename) == 0 ? BROWSE_URL : r->pagename;
- return url_build(url, url_len, r->pname, page_name, r->path, file,
- NULL);
+ return action_url_len;
}
static int
-build_file_list(struct kreq * r, char *request_dir)
+build_file_list(struct kreq * r, const char *request_dir)
{
+ bool action_url_ok;
char *file_name;
- char url[PATH_MAX];
DIR *data_dir;
- size_t url_len;
struct dirent *dir;
struct file *file;
struct file *last_file;
@@ -131,17 +102,28 @@ build_file_list(struct kreq * r, char *request_dir)
file_name = dir->d_name;
if (strcmp(".", file_name) == 0 || strcmp("..", file_name) == 0)
continue;
- url_len = build_browse_url(r, url, PATH_MAX, file_name);
- if (url_len == 0 || url_len >= PATH_MAX) {
- kutil_warn(r, NULL, "browse: Detected URL overflow: %s", url);
+ /* build file */
+ file = file_new(r->path, strlen(r->path), dir->d_name,
+ dir->d_namlen);
+ if (file == NULL) {
+ kutil_warn(r, NULL,
+ "browse: unable to allocate file, skipping %s",
+ file_name);
continue;
}
- /* build file and add to list */
- file = file_new(dir->d_name, dir->d_namlen, url, url_len);
- if (file == NULL) {
- kutil_warn(r, NULL, "browse: unable to build file info");
+ /* build action url */
+ if (file->is_dir)
+ action_url_ok = build_browse_url(r, file) > 0;
+ else
+ action_url_ok = build_download_url(r, file) > 0;
+ if (!action_url_ok) {
+ kutil_warn(r, NULL,
+ "browse: unable to build action url, skipping %s",
+ file_name);
+ file_free(file);
continue;
}
+ /* add file to list */
if (last_file == NULL)
SLIST_INSERT_HEAD(&list, file, files);
else
@@ -183,7 +165,7 @@ template_callback(size_t index, void *arg)
break;
case 1:
/* url */
- K_OK(khttp_puts(r, data->f->url), r);
+ K_OK(khttp_puts(r, data->f->action_url), r);
break;
default:
kutil_warnx(r, NULL, "Invalid key index for browse template: %zd", index);
diff --git a/download.c b/download.c
index 8512405..f506466 100644
--- a/download.c
+++ b/download.c
@@ -38,8 +38,40 @@
#include "cgi.h"
#include "config.h"
#include "download.h"
+#include "file.h"
#include "http.h"
#include "url.h"
+#include "util.h"
+
+/*
+ * download url = r->pname / DOWNLOAD_URL / file->path / file->name
+ */
+size_t
+build_download_url(struct kreq * r, struct file * file)
+{
+ char action_url[PATH_MAX];
+ size_t action_url_len;
+
+ /* don't download directories */
+ if (file->is_dir)
+ return 0;
+
+ action_url_len = url_build(action_url, PATH_MAX, r->pname, DOWNLOAD_URL,
+ file->path, file->name, NULL);
+ if (action_url_len == 0 || action_url_len >= PATH_MAX) {
+ kutil_warn(r, NULL,
+ "download: action URL overflow: %s", action_url);
+ return 0;
+ }
+ file->action_url = v_strcpy(action_url, action_url_len);
+ if (file->action_url == NULL) {
+ kutil_warn(r, NULL,
+ "download: unable to allocate file url buffer: %s",
+ action_url);
+ return 0;
+ }
+ return action_url_len;
+}
void
download(struct kreq * r)
@@ -55,13 +87,16 @@ download(struct kreq * r)
http_exit(r, KHTTP_400, "download: Invalid request path");
/* build requested file path */
- path_size = url_build(file_path, PATH_MAX, DATA_DIR, "File.txt",
+ path_size = url_build(file_path, PATH_MAX, DATA_DIR, r->path,
NULL);
if (path_size == 0)
http_exit(r, KHTTP_404, "download: Unable to build file path");
if (path_size >= PATH_MAX)
http_exit(r, KHTTP_414, NULL);
+ /* check that it is a file */
+
+
/* memory map the file */
fd = open(file_path, O_RDONLY);
if (fd < 0)
diff --git a/download.h b/download.h
index 87134b2..3d9943a 100644
--- a/download.h
+++ b/download.h
@@ -33,9 +33,19 @@
#include <kcgi.h>
+#include "file.h"
+
#define DOWNLOAD_URL "download"
/*
+ * Build the URL to download a file and assigns it to the file's action_url.
+ * All parameters are required
+ * Returns the length of the created URL, or 0 in case of failure.
+ */
+size_t
+build_download_url(struct kreq *, struct file *);
+
+/*
* Return a requested file.
* The KCGI request is required.
*/
diff --git a/file.c b/file.c
new file mode 100644
index 0000000..fba9682
--- /dev/null
+++ b/file.c
@@ -0,0 +1,138 @@
+/*
+ * Copyright 2023, 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 <sys/stat.h>
+
+#include <limits.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "config.h"
+#include "file.h"
+#include "url.h"
+#include "util.h"
+
+void
+file_free(struct file * file)
+{
+ if (file == NULL)
+ return;
+
+ if (file->path != NULL) {
+ free(file->path);
+ file->path = NULL;
+ }
+ if (file->name != NULL) {
+ free(file->name);
+ file->name = NULL;
+ }
+ if (file->action_url != NULL) {
+ free(file->action_url);
+ file->action_url = NULL;
+ }
+ free(file);
+}
+
+static bool
+ext_cmp(char *ext, char **ext_list)
+{
+ int i;
+
+ for (i = 0; ext_list[i] != NULL; i++) {
+ if (strcmp(ext, ext_list[i]) == 0)
+ return true;
+ }
+
+ return false;
+}
+
+static bool
+find_type(struct file * f)
+{
+ char *ext;
+ char *video_ext[] = {"mp4", "mkv", "avi", NULL};
+ char *audio_ext[] = {"mp3", "flac", "aac", NULL};
+ char *text_ext[] = {"txt", "doc", "docx", "odt", NULL};
+ char path[PATH_MAX];
+ struct stat sb;
+ size_t path_len;
+
+ path_len = url_build(path, PATH_MAX, DATA_DIR, f->path, f->name, NULL);
+ if (path_len == 0 || path_len >= PATH_MAX)
+ return false;
+
+ if (stat(path, &sb) != 0)
+ return false;
+
+ f->is_dir = S_ISDIR(sb.st_mode);
+
+ ext = strrchr(f->name, '.');
+ if (!ext || ext == f->name) {
+ f->type = OTHER;
+ return true;
+ }
+ ext++;
+ if (ext_cmp(ext, audio_ext))
+ f->type = AUDIO;
+ else if (ext_cmp(ext, video_ext))
+ f->type = VIDEO;
+ else if (ext_cmp(ext, text_ext))
+ f->type = TEXT;
+ else
+ f->type = OTHER;
+
+ return true;
+}
+
+struct file *
+file_new(char *dir, size_t dir_len, char *name, size_t name_len)
+{
+ struct file *file;
+
+ file = (struct file *) calloc(1, sizeof(struct file));
+ if (file == NULL)
+ return NULL;
+
+ file->path = v_strcpy(dir, dir_len);
+ if (file->path == NULL) {
+ file_free(file);
+ return NULL;
+ }
+ file->name = v_strcpy(name, name_len);
+ if (file->name == NULL) {
+ file_free(file);
+ return NULL;
+ }
+ if (!find_type(file)) {
+ file_free(file);
+ return NULL;
+ }
+ return file;
+}
diff --git a/file.h b/file.h
new file mode 100644
index 0000000..27b8a19
--- /dev/null
+++ b/file.h
@@ -0,0 +1,70 @@
+/*
+ * Copyright 2023, 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.
+ */
+
+#ifndef FILE_H
+#define FILE_H
+
+#include <sys/queue.h>
+
+#include <stdbool.h>
+
+enum file_type {
+ AUDIO,
+ VIDEO,
+ TEXT,
+ OTHER
+};
+
+/*
+ * a file
+ */
+struct file {
+ char *path; /* relative to DATA_DIR */
+ char *name;
+ char *action_url; /* action URL for HTML page */
+ bool is_dir;
+ enum file_type type;
+ SLIST_ENTRY(file) files;
+};
+
+/*
+ * Free a file struct. Should be able to free incomplete files as per file_new
+ * usage.
+ */
+void
+file_free(struct file *);
+
+/*
+ * Build a new file
+ */
+struct file *
+file_new(char *dir, size_t dir_len, char *name, size_t name_len);
+
+#endif /* FILE_H */
diff --git a/util.c b/util.c
index 54586c4..f36ee4e 100644
--- a/util.c
+++ b/util.c
@@ -1,5 +1,6 @@
#include <stdio.h>
#include <stdlib.h>
+#include <string.h>
#include "util.h"
@@ -41,3 +42,21 @@ read_file(char *path, char **output, size_t * read_size)
return 0;
}
+
+char *
+v_strcpy(char *str, size_t len)
+{
+ char *new_str;
+ size_t new_len;
+
+ new_str = (char *) malloc(sizeof(char) * (len + 1));
+ if (new_str == NULL)
+ return NULL;
+
+ new_len = strlcpy(new_str, str, len + 1);
+ if (new_len >= len + 1) {
+ free(new_str);
+ return NULL;
+ }
+ return new_str;
+}
diff --git a/util.h b/util.h
index 056f5a8..460ed9e 100644
--- a/util.h
+++ b/util.h
@@ -7,6 +7,14 @@
* be used in case of success).
*/
int
- read_file(char *path, char **output, size_t * read_size);
+read_file(char *path, char **output, size_t * read_size);
+
+/*
+ * Copies the provided string to a newly allocated buffer. Length of the
+ * created string is the same as the provided string.
+ * Returns the new string or NULL in case of failure.
+ */
+char *
+v_strcpy(char *str, size_t len);
#endif /* UTIL_H */