diff options
Diffstat (limited to 'download.c')
-rw-r--r-- | download.c | 99 |
1 files changed, 73 insertions, 26 deletions
@@ -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); } |