Read from template files with placeholder replacement

This commit is contained in:
Armin Friedl 2020-08-28 00:40:04 +02:00
parent 329dedc33b
commit 5b6f8e5083
7 changed files with 287 additions and 109 deletions

137
.clang-format Normal file
View file

@ -0,0 +1,137 @@
---
Language: Cpp
# BasedOnStyle: Mozilla
AccessModifierOffset: -2
AlignAfterOpenBracket: Align
AlignConsecutiveMacros: false
AlignConsecutiveAssignments: false
AlignConsecutiveDeclarations: false
AlignEscapedNewlines: Right
AlignOperands: true
AlignTrailingComments: true
AllowAllArgumentsOnNextLine: true
AllowAllConstructorInitializersOnNextLine: true
AllowAllParametersOfDeclarationOnNextLine: false
AllowShortBlocksOnASingleLine: Never
AllowShortCaseLabelsOnASingleLine: false
AllowShortFunctionsOnASingleLine: Inline
AllowShortLambdasOnASingleLine: All
AllowShortIfStatementsOnASingleLine: Never
AllowShortLoopsOnASingleLine: false
AlwaysBreakAfterDefinitionReturnType: TopLevel
AlwaysBreakAfterReturnType: TopLevel
AlwaysBreakBeforeMultilineStrings: false
AlwaysBreakTemplateDeclarations: Yes
BinPackArguments: false
BinPackParameters: false
BraceWrapping:
AfterCaseLabel: false
AfterClass: true
AfterControlStatement: false
AfterEnum: true
AfterFunction: true
AfterNamespace: false
AfterObjCDeclaration: false
AfterStruct: true
AfterUnion: true
AfterExternBlock: true
BeforeCatch: false
BeforeElse: false
IndentBraces: false
SplitEmptyFunction: true
SplitEmptyRecord: false
SplitEmptyNamespace: true
BreakBeforeBinaryOperators: None
BreakBeforeBraces: Mozilla
BreakBeforeInheritanceComma: false
BreakInheritanceList: BeforeComma
BreakBeforeTernaryOperators: true
BreakConstructorInitializersBeforeComma: false
BreakConstructorInitializers: BeforeComma
BreakAfterJavaFieldAnnotations: false
BreakStringLiterals: true
ColumnLimit: 80
CommentPragmas: '^ IWYU pragma:'
CompactNamespaces: false
ConstructorInitializerAllOnOneLineOrOnePerLine: false
ConstructorInitializerIndentWidth: 2
ContinuationIndentWidth: 2
Cpp11BracedListStyle: false
DeriveLineEnding: true
DerivePointerAlignment: false
DisableFormat: false
ExperimentalAutoDetectBinPacking: false
FixNamespaceComments: false
ForEachMacros:
- foreach
- Q_FOREACH
- BOOST_FOREACH
IncludeBlocks: Preserve
IncludeCategories:
- Regex: '^"(llvm|llvm-c|clang|clang-c)/'
Priority: 2
SortPriority: 0
- Regex: '^(<|"(gtest|gmock|isl|json)/)'
Priority: 3
SortPriority: 0
- Regex: '.*'
Priority: 1
SortPriority: 0
IncludeIsMainRegex: '(Test)?$'
IncludeIsMainSourceRegex: ''
IndentCaseLabels: true
IndentGotoLabels: true
IndentPPDirectives: None
IndentWidth: 2
IndentWrappedFunctionNames: false
JavaScriptQuotes: Leave
JavaScriptWrapImports: true
KeepEmptyLinesAtTheStartOfBlocks: true
MacroBlockBegin: ''
MacroBlockEnd: ''
MaxEmptyLinesToKeep: 1
NamespaceIndentation: None
ObjCBinPackProtocolList: Auto
ObjCBlockIndentWidth: 2
ObjCSpaceAfterProperty: true
ObjCSpaceBeforeProtocolList: false
PenaltyBreakAssignment: 2
PenaltyBreakBeforeFirstCallParameter: 19
PenaltyBreakComment: 300
PenaltyBreakFirstLessLess: 120
PenaltyBreakString: 1000
PenaltyBreakTemplateDeclaration: 10
PenaltyExcessCharacter: 1000000
PenaltyReturnTypeOnItsOwnLine: 200
PointerAlignment: Left
ReflowComments: true
SortIncludes: true
SortUsingDeclarations: true
SpaceAfterCStyleCast: false
SpaceAfterLogicalNot: false
SpaceAfterTemplateKeyword: false
SpaceBeforeAssignmentOperators: true
SpaceBeforeCpp11BracedList: false
SpaceBeforeCtorInitializerColon: true
SpaceBeforeInheritanceColon: true
SpaceBeforeParens: ControlStatements
SpaceBeforeRangeBasedForLoopColon: true
SpaceInEmptyBlock: false
SpaceInEmptyParentheses: false
SpacesBeforeTrailingComments: 1
SpacesInAngles: false
SpacesInConditionalStatement: false
SpacesInContainerLiterals: true
SpacesInCStyleCastParentheses: false
SpacesInParentheses: false
SpacesInSquareBrackets: false
SpaceBeforeSquareBrackets: false
Standard: Latest
StatementMacros:
- Q_UNUSED
- QT_REQUIRE_VERSION
TabWidth: 8
UseCRLF: false
UseTab: Never
...

View file

@ -12,7 +12,7 @@ steps:
image: debian
commands:
- cp quark /usr/local/bin
- useradd web && su web && cd
- useradd web
- mkdir -p web && cd web && echo "hello from quark" > index.html
- quark -p 9130 -h run -l -u web -g web
detach: true

4
.gitignore vendored Normal file
View file

@ -0,0 +1,4 @@
*.o
.gdb_history
config.h
quark

View file

@ -1,9 +1,5 @@
#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 {

215
dirl.c
View file

@ -8,12 +8,14 @@
#include <sys/stat.h>
#include <unistd.h>
#include "config.h"
#include "dirl.h"
#include "http.h"
#include "util.h"
#include "config.h"
static char *suffix(int t) {
static char*
suffix(int t)
{
switch (t) {
case DT_FIFO:
return "|";
@ -28,17 +30,84 @@ static char *suffix(int t) {
return "";
}
enum status
dirl_header_default(int fd, const struct response *res) {
static char*
dirl_read_template(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) {
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) {
fclose(tpl_fp);
return NULL;
}
long tpl_size;
if ((tpl_size = ftell(tpl_fp)) < 0) {
fclose(tpl_fp);
return NULL;
}
rewind(tpl_fp);
/* Read template into tpl_buf */
char* tpl_buf = (char*)malloc(sizeof(char) * tpl_size);
if (tpl_buf == NULL) {
fclose(tpl_fp);
free(tpl_buf);
return NULL;
}
if (fread(tpl_buf, 1, tpl_size, tpl_fp) < tpl_size) {
if (feof(tpl_fp)) {
warn("Reached end of template %s prematurely", tpl);
} else if (ferror(tpl_fp)) {
warn("Error while reading template %s", tpl);
}
fclose(tpl_fp);
free(tpl_buf);
clearerr(tpl_fp);
return NULL;
}
return tpl_buf;
}
static 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) {
"<!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;
}
@ -48,43 +117,19 @@ dirl_header_default(int fd, const struct response *res) {
enum status
dirl_header(int fd, const struct response* res)
{
char* tpl = dirl_read_template(DIRL_HEADER);
/* 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);
if(tpl == NULL) {
return dirl_header_default(fd, res);
}
/* Replace placeholder */
char *nhead = replace(header, "{idx}", "something");
char* nhead = replace(tpl, "{idx}", "something");
/* Write header */
write(fd, nhead, strlen(nhead));
free(header);
free(tpl);
free(nhead);
/* listing header */
@ -92,12 +137,16 @@ dirl_header(int fd, const struct response *res)
}
static enum status
dirl_entry_default(int fd, const struct dirent* entry) {
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,
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;
}
@ -106,30 +155,33 @@ dirl_entry_default(int fd, const struct dirent* entry) {
}
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) {
dirl_entry(int fd, const struct dirent* entry)
{
char* tpl = dirl_read_template(DIRL_ENTRY);
if (tpl == NULL) {
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);
}
/* Replace placeholder */
char* nentry = replace(tpl, "{entry}", entry->d_name);
/* Write entry */
if (sendfile(fd, entry_fd, NULL, entry_stat.st_size) < 0) {
return dirl_entry_default(fd, entry);
}
write(fd, nentry, strlen(nentry));
free(tpl);
free(nentry);
return 0;
}
static enum status
dirl_footer_default(int fd) {
if (dprintf(fd, "\n\t</body>\n</html>\n") < 0) {
dirl_footer_default(int fd)
{
if (dprintf(fd,
"\n"
" </body>\n"
"</html>") < 0) {
return S_REQUEST_TIMEOUT;
}
@ -137,49 +189,32 @@ dirl_footer_default(int fd) {
}
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) {
dirl_footer(int fd)
{
char* tpl = dirl_read_template(DIRL_FOOTER);
if(tpl == NULL) {
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);
}
/* Replace placeholder */
char* nfoot = replace(tpl, "{idx}", "something");
/* Write footer */
if (sendfile(fd, footer_fd, NULL, footer_stat.st_size) < 0) {
return dirl_footer_default(fd);
}
write(fd, nfoot, strlen(nfoot));
free(tpl);
free(nfoot);
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
int
dirl_skip(const char* name)
{
(void)name; // noop; avoid unused warning
return 0;
return !strcmp(name, DIRL_HEADER) //
|| !strcmp(name, DIRL_ENTRY) //
|| !strcmp(name, DIRL_FOOTER) //
|| !strcmp(name, DIRL_STYLE);
}

6
dirl.h
View file

@ -8,6 +8,11 @@
#include "http.h"
#define DIRL_HEADER ".header.tpl"
#define DIRL_ENTRY ".entry.tpl"
#define DIRL_FOOTER ".footer.tpl"
#define DIRL_STYLE "style.css"
struct dirl_env_entry {
char *name;
char *value;
@ -22,6 +27,7 @@ struct dirl_env {
* 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);

2
util.c
View file

@ -199,7 +199,7 @@ replace(const char *src, const char *old, const char* new) {
srcidx = srcidx_old+old_len;
}
strcpy(bufidx, srcidx); // copy tail
strncpy(bufidx, srcidx, strlen(srcidx)); // copy tail
return buf;
}