Template overrides in subdirs, prefetch templates

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. */
#include <dirent.h>
#include <errno.h>
#include <fcntl.h>
#include <stdio.h>
#include <stdlib.h>
@ -31,25 +32,13 @@ suffix(int t)
}
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;
char* tpl_abs;
tpl_abs = calloc(strlen(tpl)+2, sizeof(char));
if(tpl_abs == NULL) {
if (!(tpl_fp = fopen(tpl, "r"))) {
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 */
if (fseek(tpl_fp, 0L, SEEK_END) < 0) {
@ -66,7 +55,7 @@ dirl_read_template(char* tpl)
rewind(tpl_fp);
/* 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) {
fclose(tpl_fp);
@ -91,119 +80,120 @@ dirl_read_template(char* tpl)
return tpl_buf;
}
static enum status
dirl_header_default(int fd, const struct response* res)
/* Try to find templates up until root
*
* 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];
html_escape(res->uri, esc, sizeof(esc));
if (dprintf(fd,
"<!DOCTYPE html>\n"
"<html>\n"
" <head>\n"
" <link rel=\"stylesheet\" href=\"/"DIRL_STYLE"\">\n"
" <title>Index of %s</title>\n"
" </head>\n"
" <body>\n"
" <h1>Index of %s</h1>\n"
" <a href=\"..\">..</a>",
esc,
esc) < 0) {
return S_REQUEST_TIMEOUT;
char* path_buf = calloc(sizeof(char), strlen(start_path));
strcat(path_buf, start_path);
while (strlen(path_buf) != 0) {
DIR* cur = opendir(path_buf);
struct dirent* de;
errno = 0;
while ((de = readdir(cur))) {
if (de->d_type == DT_REG) {
if (strcmp(DIRL_HEADER, de->d_name) || strcmp(DIRL_ENTRY, de->d_name) ||
strcmp(DIRL_FOOTER, de->d_name)) {
closedir(cur);
return path_buf;
}
}
}
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
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 */
char* nhead = replace(tpl, "{idx}", "something");
char* nhead = replace(templ->header, "{curdir}", "something");
/* Write header */
write(fd, nhead, strlen(nhead));
free(tpl);
free(nhead);
/* listing header */
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
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 */
char* nentry = replace(tpl, "{entry}", entry->d_name);
char* nentry = replace(templ->entry, "{entry}", entry->d_name);
/* Write entry */
write(fd, nentry, strlen(nentry));
free(tpl);
free(nentry);
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
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 */
char* nfoot = replace(tpl, "{idx}", "something");
char* nfoot = replace(templ->footer, "{idx}", "something");
/* Write footer */
write(fd, nfoot, strlen(nfoot));
free(tpl);
free(nfoot);
return 0;
}
@ -211,10 +201,9 @@ dirl_footer(int fd)
int
dirl_skip(const char* name)
{
(void)name; // noop; avoid unused warning
return !strcmp(name, DIRL_HEADER) //
return name[0] == '.' //
|| !strcmp(name, DIRL_HEADER) //
|| !strcmp(name, DIRL_ENTRY) //
|| !strcmp(name, DIRL_FOOTER) //
|| !strcmp(name, DIRL_STYLE);
|| !strcmp(name, DIRL_STYLE); //
}

75
dirl.h
View file

@ -9,27 +9,66 @@
#include "http.h"
#define DIRL_HEADER ".header.tpl"
#define DIRL_ENTRY ".entry.tpl"
#define DIRL_ENTRY ".entry.tpl"
#define DIRL_FOOTER ".footer.tpl"
#define DIRL_STYLE "style.css"
#define DIRL_STYLE "style.css"
struct dirl_env_entry {
char *name;
char *value;
};
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.
/* Default template definitions
*
* Used if no template files can be found
*/
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*);
enum status dirl_entry(int, const struct dirent*);
enum status dirl_footer(int);
#define DIRL_ENTRY_DEFAULT \
" <br />\n" \
" <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 */

14
resp.c
View file

@ -40,32 +40,30 @@ resp_dir(int fd, const struct response *res)
return S_FORBIDDEN;
}
/* read templates */
struct dirl_templ templates = dirl_read_templ(res->path);
/* listing header */
if ((ret = dirl_header(fd, res))) {
if ((ret = dirl_header(fd, res, &templates))) {
return ret;
}
/* entries */
for (i = 0; i < (size_t)dirlen; i++) {
/* skip hidden files, "." and ".." */
if (e[i]->d_name[0] == '.') {
continue;
}
/* skip dirl special files */
if(dirl_skip(e[i]->d_name)) {
continue;
}
/* entry line */
if ((ret = dirl_entry(fd, e[i]))) {
if ((ret = dirl_entry(fd, e[i], &templates))) {
goto cleanup;
}
}
/* listing footer */
if ((ret = dirl_footer(fd))) {
if ((ret = dirl_footer(fd, &templates))) {
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 */
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 */
const char *srcidx = src;
@ -193,7 +193,8 @@ replace(const char *src, const char *old, const char* new) {
while (replc--) {
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;
srcidx = srcidx_old+old_len;