Template overrides in subdirs, prefetch templates
Some checks failed
continuous-integration/drone/push Build is failing

This commit is contained in:
Armin Friedl 2020-08-29 20:36:10 +02:00
parent 5b6f8e5083
commit a22ac176ca
4 changed files with 150 additions and 123 deletions

179
dirl.c
View file

@ -1,5 +1,6 @@
/* See LICENSE file for copyright and license details. */ /* See LICENSE file for copyright and license details. */
#include <dirent.h> #include <dirent.h>
#include <errno.h>
#include <fcntl.h> #include <fcntl.h>
#include <stdio.h> #include <stdio.h>
#include <stdlib.h> #include <stdlib.h>
@ -31,25 +32,13 @@ suffix(int t)
} }
static char* static char*
dirl_read_template(char* tpl) dirl_read(char* tpl)
{ {
/* Try find template in root (note that we are chroot'ed) */
FILE* tpl_fp; FILE* tpl_fp;
char* tpl_abs;
tpl_abs = calloc(strlen(tpl)+2, sizeof(char)); if (!(tpl_fp = fopen(tpl, "r"))) {
if(tpl_abs == NULL) {
return NULL; return NULL;
} }
tpl_abs[0] = '/';
strcat(tpl_abs, tpl);
if (!(tpl_fp = fopen(tpl_abs, "r"))) {
free(tpl_abs);
return NULL;
}
free(tpl_abs);
/* Get size of template */ /* Get size of template */
if (fseek(tpl_fp, 0L, SEEK_END) < 0) { if (fseek(tpl_fp, 0L, SEEK_END) < 0) {
@ -66,7 +55,7 @@ dirl_read_template(char* tpl)
rewind(tpl_fp); rewind(tpl_fp);
/* Read template into tpl_buf */ /* Read template into tpl_buf */
char* tpl_buf = (char*)malloc(sizeof(char) * tpl_size); char* tpl_buf = (char*)calloc(sizeof(char), tpl_size);
if (tpl_buf == NULL) { if (tpl_buf == NULL) {
fclose(tpl_fp); fclose(tpl_fp);
@ -91,119 +80,120 @@ dirl_read_template(char* tpl)
return tpl_buf; return tpl_buf;
} }
static enum status /* Try to find templates up until root
dirl_header_default(int fd, const struct response* res) *
* Iterates the directory hierarchy upwards. Returns the closest path containing
* a template file or NULL if none could be found.
*
* Note that we are chrooted.
*/
static char*
dirl_find_templ_dir(const char* start_path)
{ {
char esc[PATH_MAX]; char* path_buf = calloc(sizeof(char), strlen(start_path));
html_escape(res->uri, esc, sizeof(esc)); strcat(path_buf, start_path);
if (dprintf(fd,
"<!DOCTYPE html>\n" while (strlen(path_buf) != 0) {
"<html>\n" DIR* cur = opendir(path_buf);
" <head>\n" struct dirent* de;
" <link rel=\"stylesheet\" href=\"/"DIRL_STYLE"\">\n" errno = 0;
" <title>Index of %s</title>\n" while ((de = readdir(cur))) {
" </head>\n" if (de->d_type == DT_REG) {
" <body>\n" if (strcmp(DIRL_HEADER, de->d_name) || strcmp(DIRL_ENTRY, de->d_name) ||
" <h1>Index of %s</h1>\n" strcmp(DIRL_FOOTER, de->d_name)) {
" <a href=\"..\">..</a>", closedir(cur);
esc, return path_buf;
esc) < 0) { }
return S_REQUEST_TIMEOUT; }
}
char* parent = strrchr(path_buf, '/');
(*parent) = '\0'; // strip tail from path_buf
} }
return 0; free(path_buf);
return NULL;
}
struct dirl_templ
dirl_read_templ(const char* path)
{
struct dirl_templ templates = { .header = DIRL_HEADER_DEFAULT,
.entry = DIRL_ENTRY_DEFAULT,
.footer = DIRL_FOOTER_DEFAULT };
char* templ_dir = dirl_find_templ_dir(path);
char* header_file =
calloc(sizeof(char), strlen(templ_dir) + strlen(DIRL_HEADER));
strcpy(header_file, templ_dir);
strcat(header_file, DIRL_HEADER);
char* header = dirl_read(header_file);
if (header)
templates.header = header;
free(header_file);
char* entry_file =
calloc(sizeof(char), strlen(templ_dir) + strlen(DIRL_ENTRY));
strcpy(entry_file, templ_dir);
strcat(entry_file, DIRL_ENTRY);
char* entry = dirl_read(entry_file);
if (entry)
templates.entry = entry;
free(entry_file);
char* footer_file =
calloc(sizeof(char), strlen(templ_dir) + strlen(DIRL_FOOTER));
strcpy(footer_file, templ_dir);
strcat(footer_file, DIRL_FOOTER);
char* footer = dirl_read(footer_file);
if (footer)
templates.footer = footer;
free(footer_file);
free(templ_dir);
return templates;
} }
enum status enum status
dirl_header(int fd, const struct response* res) dirl_header(int fd, const struct response* res, const struct dirl_templ* templ)
{ {
char* tpl = dirl_read_template(DIRL_HEADER);
if(tpl == NULL) {
return dirl_header_default(fd, res);
}
/* Replace placeholder */ /* Replace placeholder */
char* nhead = replace(tpl, "{idx}", "something"); char* nhead = replace(templ->header, "{curdir}", "something");
/* Write header */ /* Write header */
write(fd, nhead, strlen(nhead)); write(fd, nhead, strlen(nhead));
free(tpl);
free(nhead); free(nhead);
/* listing header */ /* listing header */
return 0; return 0;
} }
static enum status
dirl_entry_default(int fd, const struct dirent* entry)
{
char esc[PATH_MAX];
html_escape(entry->d_name, esc, sizeof(esc));
if (dprintf(fd,
"<br />\n\t\t<a href=\"%s%s\">%s%s</a>",
esc,
(entry->d_type == DT_DIR) ? "/" : "",
esc,
suffix(entry->d_type)) < 0) {
return S_REQUEST_TIMEOUT;
}
return 0;
}
enum status enum status
dirl_entry(int fd, const struct dirent* entry) dirl_entry(int fd, const struct dirent* entry, const struct dirl_templ* templ)
{ {
char* tpl = dirl_read_template(DIRL_ENTRY);
if (tpl == NULL) {
return dirl_entry_default(fd, entry);
}
/* Replace placeholder */ /* Replace placeholder */
char* nentry = replace(tpl, "{entry}", entry->d_name); char* nentry = replace(templ->entry, "{entry}", entry->d_name);
/* Write entry */ /* Write entry */
write(fd, nentry, strlen(nentry)); write(fd, nentry, strlen(nentry));
free(tpl);
free(nentry); free(nentry);
return 0; return 0;
} }
static enum status
dirl_footer_default(int fd)
{
if (dprintf(fd,
"\n"
" </body>\n"
"</html>") < 0) {
return S_REQUEST_TIMEOUT;
}
return 0;
}
enum status enum status
dirl_footer(int fd) dirl_footer(int fd, const struct dirl_templ* templ)
{ {
char* tpl = dirl_read_template(DIRL_FOOTER);
if(tpl == NULL) {
return dirl_footer_default(fd);
}
/* Replace placeholder */ /* Replace placeholder */
char* nfoot = replace(tpl, "{idx}", "something"); char* nfoot = replace(templ->footer, "{idx}", "something");
/* Write footer */ /* Write footer */
write(fd, nfoot, strlen(nfoot)); write(fd, nfoot, strlen(nfoot));
free(tpl);
free(nfoot); free(nfoot);
return 0; return 0;
} }
@ -211,10 +201,9 @@ dirl_footer(int fd)
int int
dirl_skip(const char* name) dirl_skip(const char* name)
{ {
(void)name; // noop; avoid unused warning return name[0] == '.' //
|| !strcmp(name, DIRL_HEADER) //
return !strcmp(name, DIRL_HEADER) //
|| !strcmp(name, DIRL_ENTRY) // || !strcmp(name, DIRL_ENTRY) //
|| !strcmp(name, DIRL_FOOTER) // || !strcmp(name, DIRL_FOOTER) //
|| !strcmp(name, DIRL_STYLE); || !strcmp(name, DIRL_STYLE); //
} }

75
dirl.h
View file

@ -9,27 +9,66 @@
#include "http.h" #include "http.h"
#define DIRL_HEADER ".header.tpl" #define DIRL_HEADER ".header.tpl"
#define DIRL_ENTRY ".entry.tpl" #define DIRL_ENTRY ".entry.tpl"
#define DIRL_FOOTER ".footer.tpl" #define DIRL_FOOTER ".footer.tpl"
#define DIRL_STYLE "style.css" #define DIRL_STYLE "style.css"
struct dirl_env_entry { /* Default template definitions
char *name; *
char *value; * Used if no template files can be found
};
struct dirl_env {
struct dirl_env_entry *entries;
};
/*
* Determine if an dirlist entry should be skipped because it has special
* meaning. Skips header-, entry-, footer templates and dirlist style css.
*/ */
int dirl_skip(const char*); #define DIRL_HEADER_DEFAULT \
"<!DOCTYPE HTML PUBLIC \" - // W3C//DTD HTML 3.2 Final//EN\">\n" \
"<html>\n" \
" <head>\n" \
" <link rel=\"stylesheet\" href=\"/" DIRL_STYLE "\">\n" \
" <title>Index of {curdir}</title>\n" \
" </head>\n" \
" <body>\n" \
" <h1>Index of {curdir}</h1>\n" \
" <a href=\"..\">..</a>\n"
enum status dirl_header(int, const struct response*); #define DIRL_ENTRY_DEFAULT \
enum status dirl_entry(int, const struct dirent*); " <br />\n" \
enum status dirl_footer(int); " <a href=\"{entry}\">{entry}</a>\n"
#define DIRL_FOOTER_DEFAULT \
" </body>\n" \
"</html>"
struct dirl_templ
{
const char* header;
const char* entry;
const char* footer;
};
struct dirl_templ
dirl_read_templ(const char* path);
/* Determine if an dirlist entry should be skipped
*
* Skips:
* - hidden files and directories
* - special directory entries (., ..)
* - header template: DIRL_HEADER
* - entry template: DIRL_ENTRY
* - footer template: DIRL_FOOTER
* - dirlist style: DRIL_STYLE
*/
int
dirl_skip(const char*);
/* Print header into the response */
enum status
dirl_header(int, const struct response*, const struct dirl_templ*);
/* Print entry into the response */
enum status
dirl_entry(int, const struct dirent*, const struct dirl_templ*);
/* Print footer into the response */
enum status
dirl_footer(int, const struct dirl_templ*);
#endif /* DIRL_H */ #endif /* DIRL_H */

14
resp.c
View file

@ -40,32 +40,30 @@ resp_dir(int fd, const struct response *res)
return S_FORBIDDEN; return S_FORBIDDEN;
} }
/* read templates */
struct dirl_templ templates = dirl_read_templ(res->path);
/* listing header */ /* listing header */
if ((ret = dirl_header(fd, res))) { if ((ret = dirl_header(fd, res, &templates))) {
return ret; return ret;
} }
/* entries */ /* entries */
for (i = 0; i < (size_t)dirlen; i++) { for (i = 0; i < (size_t)dirlen; i++) {
/* skip hidden files, "." and ".." */
if (e[i]->d_name[0] == '.') {
continue;
}
/* skip dirl special files */ /* skip dirl special files */
if(dirl_skip(e[i]->d_name)) { if(dirl_skip(e[i]->d_name)) {
continue; continue;
} }
/* entry line */ /* entry line */
if ((ret = dirl_entry(fd, e[i]))) { if ((ret = dirl_entry(fd, e[i], &templates))) {
goto cleanup; goto cleanup;
} }
} }
/* listing footer */ /* listing footer */
if ((ret = dirl_footer(fd))) { if ((ret = dirl_footer(fd, &templates))) {
goto cleanup; goto cleanup;
} }

5
util.c
View file

@ -183,7 +183,7 @@ replace(const char *src, const char *old, const char* new) {
} }
/* Allocate enough space for the new string */ /* Allocate enough space for the new string */
char *buf = malloc( (sizeof(char)*src_len) + (sizeof(char)*replc*(new_len-old_len)) + 1); char *buf = calloc( sizeof(char), src_len + replc*(abs(new_len-old_len)) + 1);
/* Now start replacing */ /* Now start replacing */
const char *srcidx = src; const char *srcidx = src;
@ -193,7 +193,8 @@ replace(const char *src, const char *old, const char* new) {
while (replc--) { while (replc--) {
srcidx_old = strstr(srcidx, old); srcidx_old = strstr(srcidx, old);
bufidx = strncpy(bufidx, srcidx, srcidx_old - srcidx) + (srcidx_old-srcidx); long repl_len = labs(srcidx_old - srcidx);
bufidx = strncpy(bufidx, srcidx, repl_len) + repl_len;
bufidx = strcpy(bufidx, new) + new_len; bufidx = strcpy(bufidx, new) + new_len;
srcidx = srcidx_old+old_len; srcidx = srcidx_old+old_len;