Read dirlist from templates

Reads header, footer and entry templates from files defined in config.h.
Defaults to original output if not found.
This commit is contained in:
Armin Friedl 2020-08-25 21:08:23 +02:00
parent 670d2ed65c
commit 329dedc33b
8 changed files with 280 additions and 44 deletions

View file

@ -4,14 +4,15 @@
include config.mk
COMPONENTS = util sock http resp
COMPONENTS = util sock http resp dirl
all: quark
util.o: util.c util.h config.mk
sock.o: sock.c sock.h util.h config.mk
http.o: http.c http.h util.h http.h resp.h config.h config.mk
resp.o: resp.c resp.h util.h http.h config.mk
resp.o: resp.c resp.h util.h http.h dirl.h config.mk
dirl.o: dirl.c dirl.h util.h http.h config.mk
main.o: main.c util.h sock.h http.h arg.h config.h config.mk
quark: $(COMPONENTS:=.o) $(COMPONENTS:=.h) main.o config.mk

View file

@ -1,5 +1,9 @@
#define HEADER_MAX 4096
#define FIELD_MAX 200
#define DIRL_HEADER "header.qhtml"
#define DIRL_ENTRY "entry.qhtml"
#define DIRL_FOOTER "footer.qhtml"
#define DIRL_STYLE "dirlist.css"
/* mime-types */
static const struct {

185
dirl.c Normal file
View file

@ -0,0 +1,185 @@
/* See LICENSE file for copyright and license details. */
#include <dirent.h>
#include <fcntl.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/sendfile.h>
#include <sys/stat.h>
#include <unistd.h>
#include "dirl.h"
#include "http.h"
#include "util.h"
#include "config.h"
static char *suffix(int t) {
switch (t) {
case DT_FIFO:
return "|";
case DT_DIR:
return "/";
case DT_LNK:
return "@";
case DT_SOCK:
return "=";
}
return "";
}
enum status
dirl_header_default(int fd, const struct response *res) {
char esc[PATH_MAX];
html_escape(res->uri, esc, sizeof(esc));
if (dprintf(fd,
"<!DOCTYPE html>\n<html>\n\t<head>"
"<title>Index of %s</title></head>\n"
"\t<body>\n"
"\t\t<h1>Index of %s</h1>\n"
"\t\t\t<a href=\"..\">..</a>",
esc, esc) < 0) {
return S_REQUEST_TIMEOUT;
}
return 0;
}
enum status
dirl_header(int fd, const struct response *res)
{
/* No header file defined, default */
#ifndef DIRL_HEADER
return dirl_header_default(fd, res);
#endif
/* Try find header in root (note that we are chroot'ed) */
int header_fd;
if ( (header_fd = open(("/" DIRL_HEADER), O_RDONLY)) < 0 ) {
return dirl_header_default(fd, res);
}
/* Get size of header */
struct stat header_stat;
if (fstat(header_fd, &header_stat) < 0) {
return dirl_header_default(fd, res);
}
/* Allocate space for file */
char *header = (char *) malloc(sizeof(char) * header_stat.st_size);
if (header == NULL) {
return dirl_header_default(fd, res);
}
/* Read header into string for template replacement */
if ( (read(header_fd, header, header_stat.st_size)) < 0) {
free(header);
return dirl_header_default(fd, res);
}
/* Replace placeholder */
char *nhead = replace(header, "{idx}", "something");
/* Write header */
write(fd, nhead, strlen(nhead));
free(header);
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) {
/* Try find entry in root (note that we are chroot'ed) */
int entry_fd;
if ((entry_fd = open(("/" DIRL_ENTRY), O_RDONLY)) < 0) {
return dirl_entry_default(fd, entry);
}
/* Get size of entry*/
struct stat entry_stat;
if (fstat(entry_fd, &entry_stat) < 0) {
return dirl_entry_default(fd, entry);
}
/* Write entry */
if (sendfile(fd, entry_fd, NULL, entry_stat.st_size) < 0) {
return dirl_entry_default(fd, entry);
}
return 0;
}
static enum status
dirl_footer_default(int fd) {
if (dprintf(fd, "\n\t</body>\n</html>\n") < 0) {
return S_REQUEST_TIMEOUT;
}
return 0;
}
enum status
dirl_footer(int fd) {
/* Try find footer in root (note that we are chroot'ed) */
int footer_fd;
if ((footer_fd = open(("/" DIRL_FOOTER), O_RDONLY)) < 0) {
return dirl_footer_default(fd);
}
/* Get size of footer */
struct stat footer_stat;
if (fstat(footer_fd, &footer_stat) < 0) {
return dirl_footer_default(fd);
}
/* Write footer */
if (sendfile(fd, footer_fd, NULL, footer_stat.st_size) < 0) {
return dirl_footer_default(fd);
}
return 0;
}
int dirl_skip(const char *name) {
(void) name;
#ifdef DIRL_HEADER
if(!strcmp(name, DIRL_HEADER)) {
return 1;
}
#endif
#ifdef DIRL_ENTRY
if (!strcmp(name, DIRL_ENTRY)) {
return 1;
}
#endif
#ifdef DIRL_FOOTER
if (!strcmp(name, DIRL_FOOTER)) {
return 1;
}
#endif
#ifdef DIRL_STYLE
if (!strcmp(name, DIRL_STYLE)) {
return 1;
}
#endif
return 0;
}

29
dirl.h Normal file
View file

@ -0,0 +1,29 @@
/* See LICENSE file for copyright and license details. */
#ifndef DIRL_H
#define DIRL_H
#include <dirent.h>
#include <sys/stat.h>
#include <sys/types.h>
#include "http.h"
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.
*/
int dirl_skip(const char*);
enum status dirl_header(int, const struct response*);
enum status dirl_entry(int, const struct dirent*);
enum status dirl_footer(int);
#endif /* DIRL_H */

14
http.c
View file

@ -61,7 +61,7 @@ const char *res_field_str[] = {
enum status
http_send_header(int fd, const struct response *res)
{
char t[FIELD_MAX], esc[PATH_MAX];
char t[FIELD_MAX];
size_t i;
if (timestamp(t, sizeof(t), time(NULL))) {
@ -89,18 +89,6 @@ http_send_header(int fd, const struct response *res)
return S_REQUEST_TIMEOUT;
}
/* listing header */
if (res->type == RESTYPE_DIRLISTING) {
html_escape(res->uri, esc, sizeof(esc));
if (dprintf(fd,
"<!DOCTYPE html>\n<html>\n\t<head>"
"<title>Index of %s</title></head>\n"
"\t<body>\n\t\t<a href=\"..\">..</a>",
esc) < 0) {
return S_REQUEST_TIMEOUT;
}
}
return res->status;
}

50
resp.c
View file

@ -10,6 +10,7 @@
#include "http.h"
#include "resp.h"
#include "util.h"
#include "dirl.h"
static int
compareent(const struct dirent **d1, const struct dirent **d2)
@ -25,19 +26,6 @@ compareent(const struct dirent **d1, const struct dirent **d2)
return strcmp((*d1)->d_name, (*d2)->d_name);
}
static char *
suffix(int t)
{
switch (t) {
case DT_FIFO: return "|";
case DT_DIR: return "/";
case DT_LNK: return "@";
case DT_SOCK: return "=";
}
return "";
}
enum status
resp_dir(int fd, const struct response *res)
{
@ -52,30 +40,34 @@ resp_dir(int fd, const struct response *res)
return S_FORBIDDEN;
}
/* listing */
/* listing header */
if ((ret = dirl_header(fd, res))) {
return ret;
}
/* entries */
for (i = 0; i < (size_t)dirlen; i++) {
/* skip hidden files, "." and ".." */
if (e[i]->d_name[0] == '.') {
continue;
}
/* entry line */
html_escape(e[i]->d_name, esc, sizeof(esc));
if (dprintf(fd, "<br />\n\t\t<a href=\"%s%s\">%s%s</a>",
esc,
(e[i]->d_type == DT_DIR) ? "/" : "",
esc,
suffix(e[i]->d_type)) < 0) {
ret = S_REQUEST_TIMEOUT;
goto cleanup;
}
/* skip dirl special files */
if(dirl_skip(e[i]->d_name)) {
continue;
}
/* entry line */
if ((ret = dirl_entry(fd, e[i]))) {
goto cleanup;
}
}
/* listing footer */
if (dprintf(fd, "\n\t</body>\n</html>\n") < 0) {
ret = S_REQUEST_TIMEOUT;
goto cleanup;
}
/* listing footer */
if ((ret = dirl_footer(fd))) {
goto cleanup;
}
cleanup:
while (dirlen--) {

36
util.c
View file

@ -168,6 +168,42 @@ html_escape(const char *src, char *dst, size_t dst_siz)
dst[j] = '\0';
}
char*
replace(const char *src, const char *old, const char* new) {
int old_len = strlen(old);
int new_len = strlen(new);
int src_len = strlen(src);
/* Count needed replacements */
const char* tmp = src;
int replc=0;
while ((tmp=strstr(tmp, old))) {
replc++;
tmp += old_len;
}
/* Allocate enough space for the new string */
char *buf = malloc( (sizeof(char)*src_len) + (sizeof(char)*replc*(new_len-old_len)) + 1);
/* Now start replacing */
const char *srcidx = src;
const char *srcidx_old = src;
char *bufidx = buf;
while (replc--) {
srcidx_old = strstr(srcidx, old);
bufidx = strncpy(bufidx, srcidx, srcidx_old - srcidx) + (srcidx_old-srcidx);
bufidx = strcpy(bufidx, new) + new_len;
srcidx = srcidx_old+old_len;
}
strcpy(bufidx, srcidx); // copy tail
return buf;
}
#define INVALID 1
#define TOOSMALL 2
#define TOOLARGE 3

1
util.h
View file

@ -53,6 +53,7 @@ int timestamp(char *, size_t, time_t);
int esnprintf(char *, size_t, const char *, ...);
int prepend(char *, size_t, const char *);
void html_escape(const char *, char *, size_t);
char *replace(const char *, const char *, const char *);
void *reallocarray(void *, size_t, size_t);
long long strtonum(const char *, long long, long long, const char **);