kore

An easy to use, scalable and secure web application framework for writing web APIs in C.
Commits | Files | Refs | README | LICENSE | git clone https://git.kore.io/kore.git

commit 202234cf970182207ccb8fc7ee8df87a58fe63eb
parent 521ff6a11d535f61d28bce03c8fe1862c4b0236e
Author: Joris Vink <joris@coders.se>
Date:   Thu, 28 Jun 2018 23:00:42 +0200

filemap and fileref improvements.

- make sure we can serve updated files even if we have an old
  fileref around.

- add filemap_index as a configuration option: allows one to specify
  what file to serve if a directory was requested (eg: index.html)

Diffstat:
conf/kore.conf.example | 5+++++
include/kore/kore.h | 12+++++++++---
src/config.c | 11+++++++++++
src/filemap.c | 25+++++++++++++++++++++++--
src/fileref.c | 49+++++++++++++++++++++++++++++++++++++++++--------
5 files changed, 89 insertions(+), 13 deletions(-)

diff --git a/conf/kore.conf.example b/conf/kore.conf.example @@ -68,6 +68,11 @@ workers 4 # NOTE: This file location must be inside your chrooted environment. #rand_file random.data +# Filemap settings +# filemap_index Name of the file to be used as the directory +# index for a filemap. +#filemap_index index.html + # HTTP specific settings. # http_header_max Maximum size of HTTP headers (in bytes). # diff --git a/include/kore/kore.h b/include/kore/kore.h @@ -109,15 +109,18 @@ extern int daemon(int, int); struct http_request; #endif +#define KORE_FILEREF_SOFT_REMOVED 0x1000 + struct kore_fileref { + int fd; int cnt; + int flags; off_t size; char *path; + time_t mtime; u_int64_t expiration; #if !defined(KORE_USE_PLATFORM_SENDFILE) void *base; -#else - int fd; #endif TAILQ_ENTRY(kore_fileref) list; }; @@ -641,13 +644,16 @@ void kore_msg_send(u_int16_t, u_int8_t, const void *, u_int32_t); int kore_msg_register(u_int8_t, void (*cb)(struct kore_msg *, const void *)); +#if !defined(KORE_NO_HTTP) void kore_filemap_init(void); int kore_filemap_create(struct kore_domain *, const char *, const char *); +extern char *kore_filemap_index; +#endif void kore_fileref_init(void); struct kore_fileref *kore_fileref_get(const char *); -struct kore_fileref *kore_fileref_create(const char *, int, off_t); +struct kore_fileref *kore_fileref_create(const char *, int, off_t, time_t); void kore_fileref_release(struct kore_fileref *); void kore_domain_init(void); diff --git a/src/config.c b/src/config.c @@ -82,6 +82,7 @@ static int configure_dynamic_handler(char *); static int configure_accesslog(char *); static int configure_http_header_max(char *); static int configure_http_body_max(char *); +static int configure_filemap_index(char *); static int configure_http_media_type(char *); static int configure_http_hsts_enable(char *); static int configure_http_keepalive_time(char *); @@ -150,6 +151,7 @@ static struct { #endif #if !defined(KORE_NO_HTTP) { "filemap", configure_filemap }, + { "filemap_index", configure_filemap_index }, { "static", configure_static_handler }, { "dynamic", configure_dynamic_handler }, { "accesslog", configure_accesslog }, @@ -660,6 +662,15 @@ configure_accesslog(char *path) } static int +configure_filemap_index(char *index) +{ + kore_free(kore_filemap_index); + kore_filemap_index = kore_strdup(index); + + return (KORE_RESULT_OK); +} + +static int configure_http_media_type(char *type) { int i; diff --git a/src/filemap.c b/src/filemap.c @@ -42,6 +42,8 @@ static void filemap_serve(struct http_request *, struct filemap_entry *); static TAILQ_HEAD(, filemap_entry) maps; +char *kore_filemap_index = NULL; + void kore_filemap_init(void) { @@ -124,7 +126,7 @@ filemap_serve(struct http_request *req, struct filemap_entry *map) { struct stat st; struct kore_fileref *ref; - int len, fd; + int len, fd, index; char fpath[MAXPATHLEN]; len = snprintf(fpath, sizeof(fpath), "%s/%s", map->ondisk, @@ -144,6 +146,11 @@ filemap_serve(struct http_request *req, struct filemap_entry *map) return; } + index = 0; + +lookup: + printf("path: %s\n", fpath); + if ((ref = kore_fileref_get(fpath)) == NULL) { if ((fd = open(fpath, O_RDONLY | O_NOFOLLOW)) == -1) { switch (errno) { @@ -176,13 +183,27 @@ filemap_serve(struct http_request *req, struct filemap_entry *map) } /* kore_fileref_create() takes ownership of the fd. */ - ref = kore_fileref_create(fpath, fd, st.st_size); + ref = kore_fileref_create(fpath, fd, + st.st_size, st.st_mtime); if (ref == NULL) { http_response(req, HTTP_STATUS_INTERNAL_ERROR, NULL, 0); } else { fd = -1; } + } else if (S_ISDIR(st.st_mode) && index == 0) { + len = snprintf(fpath, sizeof(fpath), + "%s/%s%s", map->ondisk, + req->path + map->root_len, + kore_filemap_index != NULL ? + kore_filemap_index : "index.html"); + if (len == -1 || (size_t)len >= sizeof(fpath)) { + http_response(req, + HTTP_STATUS_INTERNAL_ERROR, NULL, 0); + return; + } + index++; + goto lookup; } else { http_response(req, HTTP_STATUS_NOT_FOUND, NULL, 0); } diff --git a/src/fileref.c b/src/fileref.c @@ -28,6 +28,7 @@ /* cached filerefs expire after 30 seconds of inactivity. */ #define FILEREF_EXPIRATION (1000 * 30) +static void fileref_soft_remove(struct kore_fileref *); static void fileref_expiration_check(void *, u_int64_t); static TAILQ_HEAD(, kore_fileref) refs; @@ -42,7 +43,7 @@ kore_fileref_init(void) } struct kore_fileref * -kore_fileref_create(const char *path, int fd, off_t size) +kore_fileref_create(const char *path, int fd, off_t size, time_t mtime) { struct kore_fileref *ref; @@ -52,7 +53,10 @@ kore_fileref_create(const char *path, int fd, off_t size) ref = kore_pool_get(&ref_pool); ref->cnt = 1; + ref->fd = fd; + ref->flags = 0; ref->size = size; + ref->mtime = mtime; ref->path = kore_strdup(path); #if !defined(KORE_USE_PLATFORM_SENDFILE) @@ -64,9 +68,6 @@ kore_fileref_create(const char *path, int fd, off_t size) fatal("net_send_file: mmap failed: %s", errno_s); if (madvise(ref->base, (size_t)size, MADV_SEQUENTIAL) == -1) fatal("net_send_file: madvise: %s", errno_s); - close(fd); -#else - ref->fd = fd; #endif #if defined(FILEREF_DEBUG) @@ -85,10 +86,23 @@ kore_fileref_create(const char *path, int fd, off_t size) struct kore_fileref * kore_fileref_get(const char *path) { + struct stat st; struct kore_fileref *ref; TAILQ_FOREACH(ref, &refs, list) { if (!strcmp(ref->path, path)) { + if (stat(ref->path, &st) == -1) { + kore_log(LOG_ERR, "stat(%s): %s", + ref->path, errno_s); + fileref_soft_remove(ref); + return (NULL); + } + + if (st.st_mtime != ref->mtime) { + fileref_soft_remove(ref); + return (NULL); + } + ref->cnt++; #if defined(FILEREF_DEBUG) kore_log(LOG_DEBUG, "ref:%p cnt:%d", @@ -127,6 +141,23 @@ kore_fileref_release(struct kore_fileref *ref) } static void +fileref_soft_remove(struct kore_fileref *ref) +{ + TAILQ_REMOVE(&refs, ref, list); + ref->flags |= KORE_FILEREF_SOFT_REMOVED; + + if (ref->cnt == 0) { + close(ref->fd); + kore_free(ref->path); + +#if !defined(KORE_USE_PLATFORM_SENDFILE) + (void)munmap(ref->base, ref->size); +#endif + kore_pool_put(&ref_pool, ref); + } +} + +static void fileref_expiration_check(void *arg, u_int64_t now) { struct kore_fileref *ref, *next; @@ -143,12 +174,14 @@ fileref_expiration_check(void *arg, u_int64_t now) #if defined(FILEREF_DEBUG) kore_log(LOG_DEBUG, "ref:%p expired, removing", (void *)ref); #endif - TAILQ_REMOVE(&refs, ref, list); - kore_free(ref->path); -#if defined(KORE_USE_PLATFORM_SENDFILE) + if (!(ref->flags & KORE_FILEREF_SOFT_REMOVED)) + TAILQ_REMOVE(&refs, ref, list); + close(ref->fd); -#else + kore_free(ref->path); + +#if !defined(KORE_USE_PLATFORM_SENDFILE) (void)munmap(ref->base, ref->size); #endif kore_pool_put(&ref_pool, ref);