summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--Makefile2
-rw-r--r--browse.c23
-rw-r--r--download.c86
-rw-r--r--download.h44
-rw-r--r--http.c4
-rw-r--r--http.h4
-rw-r--r--main.c8
-rw-r--r--url.c18
-rw-r--r--url.h11
9 files changed, 171 insertions, 29 deletions
diff --git a/Makefile b/Makefile
index 4e014aa..eace3fd 100644
--- a/Makefile
+++ b/Makefile
@@ -38,7 +38,7 @@ all: main
.c.o:
$(CC) -o $@ -c $< $(CFLAGS)
-main: url.o http.o browse.o main.o
+main: url.o http.o download.o browse.o main.o
$(CC) -o $@ $> $(LDFLAGS)
env: env.o
diff --git a/browse.c b/browse.c
index f12ed70..7526853 100644
--- a/browse.c
+++ b/browse.c
@@ -40,25 +40,6 @@
#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
*/
@@ -84,8 +65,6 @@ browse(struct kreq * r)
/* check that the requested URL can be safely processed */
if (!check_request_path(r->path))
http_exit(r, KHTTP_400, "browse: Invalid request path");
- if (strlen(r->path) >= URL_LENGTH_MAX)
- http_exit(r, KHTTP_414, NULL);
/* list requested directory content */
url_size = url_build(current_dir, URL_LENGTH_MAX, 2, DATA_DIR, r->path);
@@ -97,7 +76,7 @@ browse(struct kreq * r)
if (NULL == data_dir)
http_exit(r, KHTTP_404, NULL);
- http_open(r, KHTTP_200);
+ http_open(r, KHTTP_200, r->mime);
K_OK(khtml_open(&html, r, 0), r);
diff --git a/download.c b/download.c
new file mode 100644
index 0000000..ba59b68
--- /dev/null
+++ b/download.c
@@ -0,0 +1,86 @@
+/*
+ * 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/mman.h>
+#include <sys/stat.h>
+
+#include <fcntl.h>
+#include <unistd.h>
+
+#include "cgi.h"
+#include "config.h"
+#include "download.h"
+#include "http.h"
+#include "url.h"
+
+void
+download(struct kreq * r)
+{
+ void *buffer;
+ struct stat st;
+ int st_ret, fd;
+ char file_path[URL_LENGTH_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");
+
+ /* build requested file path */
+ path_size = url_build(file_path, URL_LENGTH_MAX, 2, DATA_DIR,
+ "File.txt");
+ if (path_size == 0)
+ http_exit(r, KHTTP_404, "download: Unable to build file path");
+ if (path_size >= URL_LENGTH_MAX)
+ http_exit(r, KHTTP_414, NULL);
+
+ /* 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");
+
+ /* 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);
+
+ /* cleanup */
+ munmap(buffer, st.st_size);
+ close(fd);
+}
diff --git a/download.h b/download.h
new file mode 100644
index 0000000..87134b2
--- /dev/null
+++ b/download.h
@@ -0,0 +1,44 @@
+/*
+ * 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 DOWNLOAD_H
+#define DOWNLOAD_H
+
+#include <kcgi.h>
+
+#define DOWNLOAD_URL "download"
+
+/*
+ * Return a requested file.
+ * The KCGI request is required.
+ */
+void download(struct kreq *);
+
+#endif /* DOWNLOAD_H */
diff --git a/http.c b/http.c
index d0fcbe8..4df7d93 100644
--- a/http.c
+++ b/http.c
@@ -35,10 +35,10 @@
#include "http.h"
void
-http_open(struct kreq * r, enum khttp code)
+http_open(struct kreq * r, enum khttp code, enum kmime mime)
{
khttp_head(r, kresps[KRESP_STATUS], "%s", khttps[code]);
- khttp_head(r, kresps[KRESP_CONTENT_TYPE], "%s", kmimetypes[r->mime]);
+ khttp_head(r, kresps[KRESP_CONTENT_TYPE], "%s", kmimetypes[mime]);
khttp_body(r);
}
diff --git a/http.h b/http.h
index b354b98..64ce472 100644
--- a/http.h
+++ b/http.h
@@ -35,9 +35,9 @@
/*
* Initialize headers and start the document body with the provided http code.
- * The KCGI request and khttp code are both required.
+ * All parameters are required.
*/
-void http_open(struct kreq *, enum khttp);
+void http_open(struct kreq * r, enum khttp code, enum kmime mime);
/*
* Send a plain text error response.
diff --git a/main.c b/main.c
index eab7bca..4ad1bf6 100644
--- a/main.c
+++ b/main.c
@@ -36,15 +36,18 @@
#include "browse.h"
#include "cgi.h"
#include "config.h"
+#include "download.h"
#include "http.h"
enum page {
PAGE_BROWSE,
+ PAGE_DOWNLOAD,
PAGE__MAX
};
static const char *const pages[PAGE__MAX] = {
- BROWSE_URL
+ BROWSE_URL,
+ DOWNLOAD_URL
};
int
@@ -80,6 +83,9 @@ main(void)
case PAGE_BROWSE:
browse(&r);
break;
+ case PAGE_DOWNLOAD:
+ download(&r);
+ break;
default:
http_exit(&r, KHTTP_404, NULL);
}
diff --git a/url.c b/url.c
index b4c30a6..3e71289 100644
--- a/url.c
+++ b/url.c
@@ -34,6 +34,22 @@
#include "url.h"
+bool
+check_request_path(char *path)
+{
+ char *p_found;
+
+ if (strlen(path) >= URL_LENGTH_MAX)
+ return false;
+
+ p_found = strstr(path, "/..");
+ if (p_found != NULL)
+ return false;
+
+ p_found = strstr(path, "../");
+ return p_found == NULL;
+}
+
size_t
url_build(char *dst, size_t dst_size, int count,...)
{
@@ -60,7 +76,7 @@ url_build(char *dst, size_t dst_size, int count,...)
continue;
if (path[0] != '/' && dst[w_size - 1] != '/')
- w_size = strlcat(dst, "/", dst_size);
+ strlcat(dst, "/", dst_size);
w_size = strlcat(dst, path, dst_size);
}
diff --git a/url.h b/url.h
index 7bfa247..b4552a7 100644
--- a/url.h
+++ b/url.h
@@ -31,8 +31,19 @@
#ifndef URL_H
#define URL_H
+#include <stdbool.h>
#include <stdio.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.
+ * The path is required.
+ */
+bool
+check_request_path(char *);
+
/*
* Build an URL from the provided components.
* The first argument is the destination buffer where the URL will be written.