summaryrefslogtreecommitdiff
path: root/browse.c
diff options
context:
space:
mode:
authorVincent Douillet <vincent@vdouillet.fr>2023-07-26 09:41:28 +0200
committerVincent Douillet <vincent@vdouillet.fr>2023-08-01 18:14:47 +0200
commit89a76cdd3fa168902d83f4c043d2cc6629b40024 (patch)
treed09e916129894e64010ae5d8f6dbe68ef842d02f /browse.c
parent519194a2199af44b157812705aa8838068a97bc8 (diff)
browse folders
Diffstat (limited to 'browse.c')
-rw-r--r--browse.c83
1 files changed, 71 insertions, 12 deletions
diff --git a/browse.c b/browse.c
index 1cd635f..65e3c5a 100644
--- a/browse.c
+++ b/browse.c
@@ -31,21 +31,78 @@
#include <dirent.h>
#include <kcgi.h>
#include <kcgihtml.h>
+#include <stdbool.h>
#include <string.h>
#include "browse.h"
#include "config.h"
#include "error.h"
#include "http.h"
+#include "url.h"
+
+#define URL_LENGTH_MAX 8192
+
+/*
+ * Checks that the path can be safely processed. Namely, it should not contain "..", which denotes an attempt to get out of the DATA_DIR root folder.
+ */
+static bool
+check_request_path(char *path)
+{
+ char *p_found;
+
+ p_found = strstr(path, "/..");
+ if (p_found != NULL)
+ return false;
+
+ p_found = strstr(path, "../");
+ return p_found == NULL;
+}
+
+/*
+ * file url = r->pname / r->pagename / r->path / file_name
+ */
+static size_t
+build_browse_url(struct kreq * r, char *url, size_t url_size, const char *file)
+{
+ char *page_name;
+
+ page_name = strlen(r->pagename) == 0 ? BROWSE_URL : r->pagename;
+ return url_build(url, url_size, 4, r->pname, page_name, r->path, file);
+}
int
browse(struct kreq * r)
{
- struct dirent *current_dir;
- DIR *data_dir;
- char *dir_name;
+ struct dirent *dir;
+ DIR *data_dir;
+ char *file_name;
+ size_t url_size;
+ char url[URL_LENGTH_MAX], current_dir[URL_LENGTH_MAX];
struct khtmlreq html;
+ /* check that the requested URL can be safely processed */
+ if (strlen(r->path) >= URL_LENGTH_MAX) {
+ http_open(r, KHTTP_414);
+ return VAULT_URI_ERROR;
+ }
+ if (!check_request_path(r->path)) {
+ http_open(r, KHTTP_400);
+ return VAULT_URI_ERROR;
+ }
+ /* list requested directory content */
+ url_size = url_build(current_dir, URL_LENGTH_MAX, 2, DATA_DIR, r->path);
+ if (url_size == 0) {
+ http_open(r, KHTTP_404);
+ return VAULT_IO_ERROR;
+ } else if (url_size >= URL_LENGTH_MAX) {
+ http_open(r, KHTTP_414);
+ return VAULT_URI_ERROR;
+ }
+ data_dir = opendir(current_dir);
+ if (NULL == data_dir) {
+ http_open(r, KHTTP_404);
+ return VAULT_IO_ERROR;
+ }
http_open(r, KHTTP_200);
if (KCGI_OK != khtml_open(&html, r, 0))
@@ -53,25 +110,27 @@ browse(struct kreq * r)
/* build basic html page */
khtml_elem(&html, KELEM_DOCTYPE);
+ khtml_elem(&html, KELEM_HEAD);
+ khtml_attr(&html, KELEM_META, KATTR_CHARSET, "utf-8", KATTR__MAX);
khtml_elem(&html, KELEM_HTML);
khtml_elem(&html, KELEM_BODY);
khtml_elem(&html, KELEM_P);
khtml_puts(&html, "/");
khtml_closeelem(&html, 1);
- /* list data directory content */
- data_dir = opendir(DATA_DIR);
- if (NULL == data_dir)
- return VAULT_IO_ERROR;
khtml_elem(&html, KELEM_UL);
- while ((current_dir = readdir(data_dir)) != NULL) {
+ while ((dir = readdir(data_dir)) != NULL) {
/* ignore special . and .. folders */
- dir_name = current_dir->d_name;
- if (strcmp(".", dir_name) == 0 || strcmp("..", dir_name) == 0)
+ file_name = dir->d_name;
+ if (strcmp(".", file_name) == 0 || strcmp("..", file_name) == 0)
+ continue;
+ url_size = build_browse_url(r, url, URL_LENGTH_MAX, file_name);
+ if (url_size == 0 || url_size >= URL_LENGTH_MAX)
continue;
khtml_elem(&html, KELEM_LI);
- khtml_puts(&html, current_dir->d_name);
- khtml_closeelem(&html, 1);
+ khtml_attr(&html, KELEM_A, KATTR_HREF, url, KATTR__MAX);
+ khtml_puts(&html, dir->d_name);
+ khtml_closeelem(&html, 2);
}
khtml_close(&html);
closedir(data_dir);