Template overrides in subdirs, prefetch templates
Some checks failed
continuous-integration/drone/push Build is failing
Some checks failed
continuous-integration/drone/push Build is failing
This commit is contained in:
parent
5b6f8e5083
commit
a22ac176ca
4 changed files with 150 additions and 123 deletions
179
dirl.c
179
dirl.c
|
@ -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;
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return 0;
|
char* parent = strrchr(path_buf, '/');
|
||||||
|
(*parent) = '\0'; // strip tail from path_buf
|
||||||
|
}
|
||||||
|
|
||||||
|
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); //
|
||||||
}
|
}
|
||||||
|
|
71
dirl.h
71
dirl.h
|
@ -13,23 +13,62 @@
|
||||||
#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
14
resp.c
|
@ -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
5
util.c
|
@ -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;
|
||||||
|
|
Loading…
Reference in a new issue