summaryrefslogtreecommitdiff
path: root/download.c
diff options
context:
space:
mode:
authorVincent Douillet <vincent@vdouillet.fr>2024-01-23 09:22:00 +0100
committerVincent Douillet <vincent@vdouillet.fr>2024-02-08 09:27:54 +0100
commit42f538cc66546997a166dbe67e489c9afabbb908 (patch)
tree718bb6b7161892c4b964499c1818c6d7bf0bd6a6 /download.c
parent760031b4a74d70bdeaab4ce9aedfe772acd05bd3 (diff)
download files
Diffstat (limited to 'download.c')
-rw-r--r--download.c99
1 files changed, 73 insertions, 26 deletions
diff --git a/download.c b/download.c
index f506466..af490e1 100644
--- a/download.c
+++ b/download.c
@@ -33,6 +33,8 @@
#include <fcntl.h>
#include <limits.h>
+#include <stdlib.h>
+#include <string.h>
#include <unistd.h>
#include "cgi.h"
@@ -63,7 +65,7 @@ build_download_url(struct kreq * r, struct file * file)
"download: action URL overflow: %s", action_url);
return 0;
}
- file->action_url = v_strcpy(action_url, action_url_len);
+ file->action_url = strndup(action_url, action_url_len);
if (file->action_url == NULL) {
kutil_warn(r, NULL,
"download: unable to allocate file url buffer: %s",
@@ -73,50 +75,95 @@ build_download_url(struct kreq * r, struct file * file)
return action_url_len;
}
+static char *
+strsplit(char * str, char c) {
+ char *right, *result;
+ size_t right_len;
+
+ right = strrchr(str, c);
+ if(!right || right == str)
+ return NULL;
+
+ // move right part to new buffer
+ right_len = strlen(right);
+ result = malloc(sizeof(char) * right_len);
+ if(result == NULL)
+ return NULL;
+
+ if(strlcpy(result, right + 1, right_len) >= right_len) {
+ free(result);
+ return NULL;
+ }
+
+ // remove right part from src buffer
+ *right = '\0';
+
+ return result;
+}
+
void
download(struct kreq * r)
{
+ char *file_name;
void *buffer;
- struct stat st;
- int st_ret, fd;
- char file_path[PATH_MAX];
+ struct file* f;
+ int fd;
+ char file_path[PATH_MAX], request_path[PATH_MAX];
size_t path_size;
/* check that the requested URL can be safely processed */
- if (!check_request_path(r->path))
- http_exit(r, KHTTP_400, "download: Invalid request path");
+ if (strlen(r->path) == 0 || !check_request_path(r->path, r->suffix))
+ http_exit(r, KHTTP_400, "download: invalid request path");
/* build requested file path */
- path_size = url_build(file_path, PATH_MAX, DATA_DIR, r->path,
+ if(strlen(r->suffix) > 0) {
+ /* request with suffix */
+ if(snprintf(request_path, sizeof(request_path), "%s.%s", r->path, r->suffix)
+ >= (int) sizeof(request_path))
+ http_exit(r, KHTTP_414, NULL);
+ }
+ else {
+ if(snprintf(request_path, sizeof(request_path), "%s", r->path) >= (int) sizeof(request_path))
+ http_exit(r, KHTTP_414, NULL);
+ }
+
+ path_size = url_build(file_path, PATH_MAX, DATA_DIR, request_path,
NULL);
if (path_size == 0)
- http_exit(r, KHTTP_404, "download: Unable to build file path");
+ 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 */
-
+ /* build file metadata */
+ file_name = strsplit(request_path, '/');
+ if(file_name == NULL)
+ f = file_new("/", 1, request_path, strlen(request_path)); /* ROOT file */
+ else {
+ f = file_new(request_path, strlen(request_path), file_name,
+ strlen(file_name));
+ free(file_name); /* copied in file_new */
+ }
+ if(f == NULL)
+ http_exit(r, KHTTP_404, "download: file metadata failure");
/* memory map the file */
fd = open(file_path, O_RDONLY);
- if (fd < 0)
- http_exit(r, KHTTP_404, "download: Unable to open file");
- st_ret = fstat(fd, &st);
- if (st_ret != 0)
- http_exit(r, KHTTP_404, "download: Unable to open file");
-
- /* TODO mmap does not work with empty file: st_size = 0 */
- buffer = mmap(NULL, st.st_size, PROT_READ, MAP_PRIVATE, fd, 0);
- if (buffer == MAP_FAILED)
- http_exit(r, KHTTP_500, "download: mmap failed");
+ if(fd < 0)
+ http_exit(r, KHTTP_404, "download: unable to open file");
+ /* mmap does not work with empty file: st_size = 0 */
+ if(f->size > 0) {
+ buffer = mmap(NULL, f->size, PROT_READ, MAP_PRIVATE, fd, 0);
+ if (buffer == MAP_FAILED)
+ http_exit(r, KHTTP_500, "download: mmap failed");
+ }
/* write the file */
- /* TODO proper filename & MIME type detection */
- K_OK(khttp_head(r, kresps[KRESP_CONTENT_DISPOSITION], "attachment; filename=\"File.txt\""), r);
- http_open(r, KHTTP_200, KMIME_TEXT_PLAIN);
- K_OK(khttp_write(r, (const char *) buffer, st.st_size), r);
+ http_open_file(r, KHTTP_200, f);
+ if(f->size > 0)
+ K_OK(khttp_write(r, (const char *) buffer, f->size), r);
/* cleanup */
- munmap(buffer, st.st_size);
- close(fd);
+ if(f->size > 0)
+ munmap(buffer, f->size);
+ free(f);
}