From 06c1a7183754349e29a6f4656d88d3f89e4f448a Mon Sep 17 00:00:00 2001 From: Fredrik Tolf Date: Tue, 24 Aug 2010 16:49:26 +0200 Subject: [PATCH] Added a generic config parser/child handler and used it for dirplex and patplex. --- lib/Makefile.am | 2 +- lib/cf.c | 304 +++++++++++++++++++++++++++++++++++++++++++++ lib/cf.h | 32 +++++ lib/utils.c | 2 + src/dirplex.c | 263 ++++++++++++++------------------------- src/patplex.c | 375 ++++++++++++++++++++------------------------------------ 6 files changed, 558 insertions(+), 420 deletions(-) create mode 100644 lib/cf.c create mode 100644 lib/cf.h diff --git a/lib/Makefile.am b/lib/Makefile.am index 74dec1a..4de8166 100644 --- a/lib/Makefile.am +++ b/lib/Makefile.am @@ -1,5 +1,5 @@ noinst_LIBRARIES = libht.a -libht_a_SOURCES = utils.c mt.c log.c req.c proc.c mtio.c resp.c +libht_a_SOURCES = utils.c mt.c log.c req.c proc.c mtio.c resp.c cf.c libht_a_CFLAGS = -fPIC libht_a_CPPFLAGS = -D_GNU_SOURCE diff --git a/lib/cf.c b/lib/cf.c new file mode 100644 index 0000000..5df5c59 --- /dev/null +++ b/lib/cf.c @@ -0,0 +1,304 @@ +/* + ashd - A Sane HTTP Daemon + Copyright (C) 2008 Fredrik Tolf + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . +*/ + +#include +#include +#include +#include +#include +#include +#include + +#ifdef HAVE_CONFIG_H +#include +#endif +#include +#include +#include +#include +#include + +#define CH_SOCKET 0 +#define CH_FORK 1 + +static int parsefile(struct cfstate *s, FILE *in) +{ + int i, o, ret; + glob_t globm; + char line[1024]; + int eof, argc; + int ind, indst[80], indl; + char *p, **w, *fbk; + FILE *inc; + + s->lno = 0; + indst[indl = 0] = 0; + eof = 0; + while(1) { + if(fgets(line, sizeof(line), in) == NULL) { + eof = 1; + line[0] = 0; + } + s->lno++; + for(p = line + strlen(line) - 1; p >= line; p--) { + if(isspace(*p)) + *p = 0; + else + break; + } + for(ind = 0, p = line; *p; p++) { + if(*p == ' ') { + ind++; + } else if(*p == '\t') { + ind = ind - (ind % 8) + 8; + } else { + break; + } + } + if(!eof && (!*p || (*p == '#'))) + continue; + + reindent: + if(ind > indst[indl]) { + indst[++indl] = ind; + if(!s->expstart) { + s->res = tokenize("start"); + if(yield()) + return(1); + } else { + s->expstart = 0; + } + } else { + if(s->expstart) { + s->res = tokenize("end"); + if(yield()) + return(1); + s->expstart = 0; + } + while(ind < indst[indl]) { + indl--; + s->res = tokenize("end"); + if(yield()) + return(1); + } + if(ind > indst[indl]) { + flog(LOG_WARNING, "%s:%i: unexpected indentation level", s->file, s->lno); + goto reindent; + } + } + + if(eof) + return(0); + + argc = calen(w = tokenize(line)); + if(argc < 1) { + /* Shouldn't happen, but... */ + freeca(w); + continue; + } + + if(indl == 0) { + if(!strcmp(w[0], "include")) { + fbk = s->file; + for(i = 1; i < argc; i++) { + if((ret = glob(w[i], 0, NULL, &globm)) == 0) { + for(o = 0; o < globm.gl_pathc; o++) { + if((inc = fopen(globm.gl_pathv[o], "r")) != NULL) { + s->file = globm.gl_pathv[o]; + if(parsefile(s, inc)) { + fclose(inc); + globfree(&globm); + freeca(w); + return(1); + } + fclose(inc); + } + } + globfree(&globm); + } + } + freeca(w); + s->file = fbk; + continue; + } + } + + if(!strcmp(w[0], "start") || + !strcmp(w[0], "end") || + !strcmp(w[0], "eof")) { + flog(LOG_WARNING, "%s:%i: illegal directive: %s", s->file, s->lno, w[0]); + } else { + s->res = w; + if(yield()) + return(1); + } + } +} + +static void parsefn(struct muth *mt, va_list args) +{ + vavar(struct cfstate *, s); + vavar(FILE *, in); + vavar(char *, file); + + s->file = sstrdup(file); + if(parsefile(s, in)) + goto out; + do { + s->res = tokenize("eof"); + } while(!yield()); + +out: + free(s->file); +} + +char **getcfline(struct cfstate *s) +{ + freeca(s->argv); + if(s->res == NULL) + resume(s->pf, 0); + s->argc = calen(s->argv = s->res); + s->res = NULL; + return(s->argv); +} + +struct cfstate *mkcfparser(FILE *in, char *name) +{ + struct cfstate *s; + + omalloc(s); + s->pf = mustart(parsefn, s, in, name); + return(s); +} + +void freecfparser(struct cfstate *s) +{ + resume(s->pf, -1); + freeca(s->argv); + freeca(s->res); + free(s); +} + +static struct child *newchild(char *name, int type) +{ + struct child *ch; + + omalloc(ch); + ch->name = sstrdup(name); + ch->type = type; + ch->fd = -1; + return(ch); +} + +void freechild(struct child *ch) +{ + if(ch->fd != -1) + close(ch->fd); + if(ch->name != NULL) + free(ch->name); + if(ch->argv != NULL) + freeca(ch->argv); + free(ch); +} + +void skipcfblock(struct cfstate *s) +{ + char **w; + + while(1) { + w = getcfline(s); + if(!strcmp(w[0], "end") || !strcmp(w[0], "eof")) + return; + } +} + +struct child *parsechild(struct cfstate *s) +{ + struct child *ch; + int i; + int sl; + + sl = s->lno; + if(!strcmp(s->argv[0], "child")) { + s->expstart = 1; + if(s->argc < 2) { + flog(LOG_WARNING, "%s:%i: missing name in child declaration", s->file, s->lno); + skipcfblock(s); + return(NULL); + } + ch = newchild(s->argv[1], CH_SOCKET); + } else if(!strcmp(s->argv[0], "fchild")) { + s->expstart = 1; + if(s->argc < 2) { + flog(LOG_WARNING, "%s:%i: missing name in child declaration", s->file, s->lno); + skipcfblock(s); + return(NULL); + } + ch = newchild(s->argv[1], CH_FORK); + } else { + return(NULL); + } + + while(1) { + getcfline(s); + if(!strcmp(s->argv[0], "exec")) { + if(s->argc < 2) { + flog(LOG_WARNING, "%s:%i: too few parameters to `exec'", s->file, s->lno); + continue; + } + ch->argv = szmalloc(sizeof(*ch->argv) * s->argc); + for(i = 0; i < s->argc - 1; i++) + ch->argv[i] = sstrdup(s->argv[i + 1]); + } else if(!strcmp(s->argv[0], "end") || !strcmp(s->argv[0], "eof")) { + break; + } else { + flog(LOG_WARNING, "%s:%i: unknown directive `%s' in child declaration", s->file, s->lno, s->argv[0]); + } + } + if(ch->argv == NULL) { + flog(LOG_WARNING, "%s:%i: missing `exec' in child declaration %s", s->file, sl, ch->name); + freechild(ch); + return(NULL); + } + return(ch); +} + +int childhandle(struct child *ch, struct hthead *req, int fd) +{ + if(ch->type == CH_SOCKET) { + if(ch->fd < 0) + ch->fd = stdmkchild(ch->argv); + if(sendreq(ch->fd, req, fd)) { + if(errno == EPIPE) { + /* Assume that the child has crashed and restart it. */ + close(ch->fd); + ch->fd = stdmkchild(ch->argv); + if(!sendreq(ch->fd, req, fd)) + return(-1); + } + flog(LOG_ERR, "could not pass on request to child %s: %s", ch->name, strerror(errno)); + close(ch->fd); + ch->fd = -1; + return(-1); + } + } else if(ch->type == CH_FORK) { + if(stdforkserve(ch->argv, req, fd) < 0) + return(-1); + } + return(0); +} diff --git a/lib/cf.h b/lib/cf.h new file mode 100644 index 0000000..09dad29 --- /dev/null +++ b/lib/cf.h @@ -0,0 +1,32 @@ +#ifndef _ASHCONF_H +#define _ASHCONF_H + +#include + +struct cfstate { + struct muth *pf; + int expstart; + char **res, **argv; + int argc; + int lno; + char *file; +}; + +struct child { + struct child *next; + char *name; + int type; + char **argv; + int fd; +}; + +void skipcfblock(struct cfstate *s); +struct cfstate *mkcfparser(FILE *in, char *name); +void freecfparser(struct cfstate *s); +char **getcfline(struct cfstate *s); + +void freechild(struct child *ch); +struct child *parsechild(struct cfstate *s); +int childhandle(struct child *ch, struct hthead *req, int fd); + +#endif diff --git a/lib/utils.c b/lib/utils.c index 2ecae5a..2b251e3 100644 --- a/lib/utils.c +++ b/lib/utils.c @@ -163,6 +163,8 @@ void freeca(char **ca) { char **c; + if(ca == NULL) + return; for(c = ca; *c; c++) free(*c); free(ca); diff --git a/src/dirplex.c b/src/dirplex.c index d47a23e..6dccff5 100644 --- a/src/dirplex.c +++ b/src/dirplex.c @@ -35,6 +35,7 @@ #include #include #include +#include #define CH_SOCKET 0 #define CH_FORK 1 @@ -52,14 +53,6 @@ struct config { struct pattern *patterns; }; -struct child { - struct child *next; - char *name; - int type; - char **argv; - int fd; -}; - struct rule { int type; char *pattern; @@ -73,17 +66,6 @@ struct pattern { struct config *cflist; -static void freechild(struct child *ch) -{ - if(ch->fd != -1) - close(ch->fd); - if(ch->name != NULL) - free(ch->name); - if(ch->argv != NULL) - freeca(ch->argv); - free(ch); -} - static void freepattern(struct pattern *pat) { struct rule **rule; @@ -121,17 +103,6 @@ static void freeconfig(struct config *cf) free(cf); } -static struct child *newchild(char *name, int type) -{ - struct child *ch; - - omalloc(ch); - ch->name = sstrdup(name); - ch->type = type; - ch->fd = -1; - return(ch); -} - static struct child *getchild(struct config *cf, char *name) { struct child *ch; @@ -164,165 +135,109 @@ static struct pattern *newpattern(void) return(pat); } +static struct pattern *parsepattern(struct cfstate *s) +{ + struct pattern *pat; + struct rule *rule; + int sl; + + if(!strcmp(s->argv[0], "match")) { + s->expstart = 1; + pat = newpattern(); + } else { + return(NULL); + } + + sl = s->lno; + while(1) { + getcfline(s); + if(!strcmp(s->argv[0], "filename")) { + if(s->argc < 2) { + flog(LOG_WARNING, "%s:%i: missing pattern for `filename' match", s->file, s->lno); + continue; + } + rule = newrule(pat); + rule->type = PAT_BASENAME; + rule->pattern = sstrdup(s->argv[1]); + } else if(!strcmp(s->argv[0], "pathname")) { + if(s->argc < 2) { + flog(LOG_WARNING, "%s:%i: missing pattern for `pathname' match", s->file, s->lno); + continue; + } + rule = newrule(pat); + rule->type = PAT_PATHNAME; + rule->pattern = sstrdup(s->argv[1]); + } else if(!strcmp(s->argv[0], "all")) { + newrule(pat)->type = PAT_ALL; + } else if(!strcmp(s->argv[0], "default")) { + newrule(pat)->type = PAT_DEFAULT; + } else if(!strcmp(s->argv[0], "handler")) { + if(s->argc < 2) { + flog(LOG_WARNING, "%s:%i: missing child name for `handler' directive", s->file, s->lno); + continue; + } + if(pat->childnm != NULL) + free(pat->childnm); + pat->childnm = sstrdup(s->argv[1]); + } else if(!strcmp(s->argv[0], "end") || !strcmp(s->argv[0], "eof")) { + break; + } else { + flog(LOG_WARNING, "%s:%i: unknown directive `%s' in pattern declaration", s->file, s->lno, s->argv[0]); + } + } + + if(pat->rules[0] == NULL) { + flog(LOG_WARNING, "%s:%i: missing rules in match declaration", s->file, sl); + freepattern(pat); + return(NULL); + } + if(pat->childnm == NULL) { + flog(LOG_WARNING, "%s:%i: missing handler in match declaration", s->file, sl); + freepattern(pat); + return(NULL); + } + return(pat); +} + static struct config *readconfig(char *path) { - int i; + struct cfstate *s; + FILE *in; struct config *cf; - FILE *s; - char line[1024]; - char *p, **w; - int ind, eof; - int lno; - int state; - int rv; - int argc; struct child *child; struct pattern *pat; - struct rule *rule; struct stat sb; + char *p; p = sprintf3("%s/.htrc", path); if(stat(p, &sb)) return(NULL); - if((s = fopen(p, "r")) == NULL) + if((in = fopen(p, "r")) == NULL) { + flog(LOG_WARNING, "%s: %s", p, strerror(errno)); return(NULL); + } + s = mkcfparser(in, p); omalloc(cf); cf->mtime = sb.st_mtime; cf->path = sstrdup(path); - eof = 0; - state = 0; - w = NULL; - lno = 0; - do { - if(fgets(line, sizeof(line), s) == NULL) { - eof = 1; - line[0] = 0; - } - lno++; - for(p = line; *p; p++) { - if(*p == '#') - continue; - if(!isspace(*p)) - break; - } - ind = isspace(line[0]); - w = tokenize(line); - argc = calen(w); - - retry: - if(state == 0) { - if(ind) { - flog(LOG_WARNING, "%s%i: unexpected line indentation in global scope", path, lno); - goto next; - } else { - if(!w[0]) { - } else if(!strcmp(w[0], "child")) { - if(argc < 2) { - flog(LOG_WARNING, "%s:%i: missing name in child declaration", path, lno); - goto next; - } - child = newchild(w[1], CH_SOCKET); - state = 1; - } else if(!strcmp(w[0], "fchild")) { - if(argc < 2) { - flog(LOG_WARNING, "%s:%i: missing name in child declaration", path, lno); - goto next; - } - child = newchild(w[1], CH_FORK); - state = 1; - } else if(!strcmp(w[0], "match")) { - pat = newpattern(); - state = 2; - } else { - flog(LOG_WARNING, "%s:%i: unknown directive %s", path, lno, w[0]); - } - } - } else if(state == 1) { - if(ind) { - if(!w[0]) { - } else if(!strcmp(w[0], "exec")) { - if(argc < 2) { - flog(LOG_WARNING, "%s:%i: too few parameters to `exec'", path, lno); - goto next; - } - child->argv = szmalloc(sizeof(*child->argv) * argc); - for(i = 0; i < argc - 1; i++) - child->argv[i] = sstrdup(w[i + 1]); - } else { - flog(LOG_WARNING, "%s:%i: unknown directive %s", path, lno, w[0]); - } - } else { - state = 0; - if(child->argv == NULL) { - flog(LOG_WARNING, "%s:%i: missing `exec' in child declaration %s", path, lno, child->name); - freechild(child); - goto retry; - } - child->next = cf->children; - cf->children = child; - goto retry; - } - } else if(state == 2) { - if(ind) { - if(!w[0]) { - } else if(!strcmp(w[0], "filename")) { - if(argc < 2) { - flog(LOG_WARNING, "%s:%i: missing pattern for `filename' match", path, lno); - goto next; - } - rule = newrule(pat); - rule->type = PAT_BASENAME; - rule->pattern = sstrdup(w[1]); - } else if(!strcmp(w[0], "pathname")) { - if(argc < 2) { - flog(LOG_WARNING, "%s:%i: missing pattern for `pathname' match", path, lno); - goto next; - } - rule = newrule(pat); - rule->type = PAT_PATHNAME; - rule->pattern = sstrdup(w[1]); - } else if(!strcmp(w[0], "all")) { - newrule(pat)->type = PAT_ALL; - } else if(!strcmp(w[0], "default")) { - newrule(pat)->type = PAT_DEFAULT; - } else if(!strcmp(w[0], "handler")) { - if(argc < 2) { - flog(LOG_WARNING, "%s:%i: missing child name for `handler' directive", path, lno); - goto next; - } - if(pat->childnm != NULL) - free(pat->childnm); - pat->childnm = sstrdup(w[1]); - } else { - flog(LOG_WARNING, "%s:%i: unknown directive %s", path, lno, w[0]); - } - } else { - state = 0; - if(pat->rules[0] == NULL) { - flog(LOG_WARNING, "%s:%i: missing rules in match declaration", path, lno); - freepattern(pat); - goto retry; - } - if(pat->childnm == NULL) { - flog(LOG_WARNING, "%s:%i: missing handler in match declaration", path, lno); - freepattern(pat); - goto retry; - } - pat->next = cf->patterns; - cf->patterns = pat; - goto retry; - } + + while(1) { + getcfline(s); + if((child = parsechild(s)) != NULL) { + child->next = cf->children; + cf->children = child; + } else if((pat = parsepattern(s)) != NULL) { + pat->next = cf->patterns; + cf->patterns = pat; + } else if(!strcmp(s->argv[0], "eof")) { + break; + } else { + flog(LOG_WARNING, "%s:%i: unknown directive `%s'", s->file, s->lno, s->argv[0]); } - - next: - freeca(w); - w = NULL; - } while(!eof); - rv = 0; + } - if(w != NULL) - freeca(w); - fclose(s); + freecfparser(s); + fclose(in); return(cf); } @@ -471,7 +386,7 @@ static void handlefile(struct hthead *req, int fd, char *path) static void handledir(struct hthead *req, int fd, char *path) { /* XXX: Todo */ - simpleerror(fd, 403, "Not Authorized", "Will not send directory listings or indices yet"); + simpleerror(fd, 403, "Not Authorized", "Will not send directory listings or indices yet."); } static int checkdir(struct hthead *req, int fd, char *path) diff --git a/src/patplex.c b/src/patplex.c index 6e6a78f..26c6bd3 100644 --- a/src/patplex.c +++ b/src/patplex.c @@ -33,9 +33,7 @@ #include #include #include - -#define CH_SOCKET 0 -#define CH_FORK 1 +#include #define PAT_REST 0 #define PAT_URL 1 @@ -51,14 +49,6 @@ struct config { struct pattern *patterns; }; -struct child { - struct child *next; - char *name; - int type; - char **argv; - int fd; -}; - struct rule { int type; int fl; @@ -93,28 +83,6 @@ static void freepattern(struct pattern *pat) free(pat); } -static void freechild(struct child *ch) -{ - if(ch->fd != -1) - close(ch->fd); - if(ch->name != NULL) - free(ch->name); - if(ch->argv != NULL) - freeca(ch->argv); - free(ch); -} - -static struct child *newchild(char *name, int type) -{ - struct child *ch; - - omalloc(ch); - ch->name = sstrdup(name); - ch->type = type; - ch->fd = -1; - return(ch); -} - static struct child *getchild(struct config *cf, char *name) { struct child *ch; @@ -163,202 +131,144 @@ static regex_t *regalloc(char *regex, int flags) return(ret); } -static struct config *readconfig(char *filename) +static struct pattern *parsepattern(struct cfstate *s) { - int i; - struct config *cf; - FILE *s; - char line[1024]; - char *p, **w; - int ind, eof; - int lno; - int state; - int rv; - int argc; - struct child *child; struct pattern *pat; + int sl; struct rule *rule; regex_t *regex; int rxfl; - if((s = fopen(filename, "r")) == NULL) + if(!strcmp(s->argv[0], "match")) { + s->expstart = 1; + pat = newpattern(); + } else { return(NULL); - omalloc(cf); - eof = 0; - state = 0; - w = NULL; - lno = 0; - do { - if(fgets(line, sizeof(line), s) == NULL) { - eof = 1; - line[0] = 0; - } - lno++; - for(p = line; *p; p++) { - if(*p == '#') + } + + sl = s->lno; + while(1) { + getcfline(s); + if(!strcmp(s->argv[0], "point") || + !strcmp(s->argv[0], "url") || + !strcmp(s->argv[0], "method")) { + if(s->argc < 2) { + flog(LOG_WARNING, "%s:%i: missing pattern for `%s' match", s->file, s->lno, s->argv[0]); continue; - if(!isspace(*p)) - break; - } - ind = isspace(line[0]); - w = tokenize(line); - argc = calen(w); - - retry: - if(state == 0) { - if(ind) { - flog(LOG_WARNING, "%s%i: unexpected line indentation in global scope", filename, lno); - goto next; - } else { - if(!w[0]) { - } else if(!strcmp(w[0], "child")) { - if(argc < 2) { - flog(LOG_WARNING, "%s:%i: missing name in child declaration", filename, lno); - goto next; - } - child = newchild(w[1], CH_SOCKET); - state = 1; - } else if(!strcmp(w[0], "fchild")) { - if(argc < 2) { - flog(LOG_WARNING, "%s:%i: missing name in child declaration", filename, lno); - goto next; - } - child = newchild(w[1], CH_FORK); - state = 1; - } else if(!strcmp(w[0], "match")) { - pat = newpattern(); - state = 2; - } else { - flog(LOG_WARNING, "%s:%i: unknown directive %s", filename, lno, w[0]); - } } - } else if(state == 1) { - if(ind) { - if(!w[0]) { - } else if(!strcmp(w[0], "exec")) { - if(argc < 2) { - flog(LOG_WARNING, "%s:%i: too few parameters to `exec'", filename, lno); - goto next; - } - child->argv = szmalloc(sizeof(*child->argv) * argc); - for(i = 0; i < argc - 1; i++) - child->argv[i] = sstrdup(w[i + 1]); - } else { - flog(LOG_WARNING, "%s:%i: unknown directive %s", filename, lno, w[0]); - } - } else { - state = 0; - if(child->argv == NULL) { - flog(LOG_WARNING, "%s:%i: missing `exec' in child declaration %s", filename, lno, child->name); - freechild(child); - goto retry; - } - child->next = cf->children; - cf->children = child; - goto retry; + if(s->argc >= 3) { + if(strchr(s->argv[2], 'i')) + rxfl |= REG_ICASE; } - } else if(state == 2) { - if(ind) { - rxfl = 0; - if(!w[0]) { - } else if(!strcmp(w[0], "point") || - !strcmp(w[0], "url") || - !strcmp(w[0], "method")) { - if(argc < 2) { - flog(LOG_WARNING, "%s:%i: missing pattern for `%s' match", w[0], filename, lno); - goto next; - } - if(argc >= 3) { - if(strchr(w[2], 'i')) - rxfl |= REG_ICASE; - } - if((regex = regalloc(w[1], rxfl)) == NULL) { - flog(LOG_WARNING, "%s:%i: invalid regex for `%s' match", w[0], filename, lno); - goto next; - } - rule = newrule(pat); - if(!strcmp(w[0], "point")) - rule->type = PAT_REST; - else if(!strcmp(w[0], "url")) - rule->type = PAT_URL; - else if(!strcmp(w[0], "method")) - rule->type = PAT_METHOD; - rule->pattern = regex; - if(argc >= 3) { - if(strchr(w[2], 's')) - rule->fl |= PATFL_MSS; - } - } else if(!strcmp(w[0], "header")) { - if(argc < 3) { - flog(LOG_WARNING, "%s:%i: missing header name or pattern for `header' match", filename, lno); - goto next; - } - if(argc >= 4) { - if(strchr(w[3], 'i')) - rxfl |= REG_ICASE; - } - if((regex = regalloc(w[2], rxfl)) == NULL) { - flog(LOG_WARNING, "%s:%i: invalid regex for `header' match", filename, lno); - goto next; - } - rule = newrule(pat); - rule->type = PAT_HEADER; - rule->header = sstrdup(w[1]); - rule->pattern = regex; - if(argc >= 4) { - if(strchr(w[3], 's')) - rule->fl |= PATFL_MSS; - } - } else if(!strcmp(w[0], "all")) { - newrule(pat)->type = PAT_ALL; - } else if(!strcmp(w[0], "default")) { - newrule(pat)->type = PAT_DEFAULT; - } else if(!strcmp(w[0], "handler")) { - if(argc < 2) { - flog(LOG_WARNING, "%s:%i: missing child name for `handler' directive", filename, lno); - goto next; - } - if(pat->childnm != NULL) - free(pat->childnm); - pat->childnm = sstrdup(w[1]); - } else if(!strcmp(w[0], "restpat")) { - if(argc < 2) { - flog(LOG_WARNING, "%s:%i: missing pattern for `restpat' directive", filename, lno); - goto next; - } - if(pat->restpat != NULL) - free(pat->restpat); - pat->restpat = sstrdup(w[1]); - } else { - flog(LOG_WARNING, "%s:%i: unknown directive %s", filename, lno, w[0]); - } - } else { - state = 0; - if(pat->rules[0] == NULL) { - flog(LOG_WARNING, "%s:%i: missing rules in match declaration", filename, lno); - freepattern(pat); - goto retry; - } - if(pat->childnm == NULL) { - flog(LOG_WARNING, "%s:%i: missing handler in match declaration", filename, lno); - freepattern(pat); - goto retry; - } - pat->next = cf->patterns; - cf->patterns = pat; - goto retry; + if((regex = regalloc(s->argv[1], rxfl)) == NULL) { + flog(LOG_WARNING, "%s:%i: invalid regex for `%s' match", s->file, s->lno, s->argv[0]); + continue; + } + rule = newrule(pat); + if(!strcmp(s->argv[0], "point")) + rule->type = PAT_REST; + else if(!strcmp(s->argv[0], "url")) + rule->type = PAT_URL; + else if(!strcmp(s->argv[0], "method")) + rule->type = PAT_METHOD; + rule->pattern = regex; + if(s->argc >= 3) { + if(strchr(s->argv[2], 's')) + rule->fl |= PATFL_MSS; + } + } else if(!strcmp(s->argv[0], "header")) { + if(s->argc < 3) { + flog(LOG_WARNING, "%s:%i: missing header name or pattern for `header' match", s->file, s->lno); + continue; + } + if(s->argc >= 4) { + if(strchr(s->argv[3], 'i')) + rxfl |= REG_ICASE; + } + if((regex = regalloc(s->argv[2], rxfl)) == NULL) { + flog(LOG_WARNING, "%s:%i: invalid regex for `header' match", s->file, s->lno); + continue; + } + rule = newrule(pat); + rule->type = PAT_HEADER; + rule->header = sstrdup(s->argv[1]); + rule->pattern = regex; + if(s->argc >= 4) { + if(strchr(s->argv[3], 's')) + rule->fl |= PATFL_MSS; } + } else if(!strcmp(s->argv[0], "all")) { + newrule(pat)->type = PAT_ALL; + } else if(!strcmp(s->argv[0], "default")) { + newrule(pat)->type = PAT_DEFAULT; + } else if(!strcmp(s->argv[0], "handler")) { + if(s->argc < 2) { + flog(LOG_WARNING, "%s:%i: missing child name for `handler' directive", s->file, s->lno); + continue; + } + if(pat->childnm != NULL) + free(pat->childnm); + pat->childnm = sstrdup(s->argv[1]); + } else if(!strcmp(s->argv[0], "restpat")) { + if(s->argc < 2) { + flog(LOG_WARNING, "%s:%i: missing pattern for `restpat' directive", s->file, s->lno); + continue; + } + if(pat->restpat != NULL) + free(pat->restpat); + pat->restpat = sstrdup(s->argv[1]); + } else if(!strcmp(s->argv[0], "end") || !strcmp(s->argv[0], "eof")) { + break; + } else { + flog(LOG_WARNING, "%s:%i: unknown directive `%s' in pattern declaration", s->file, s->lno, s->argv[0]); } - - next: - freeca(w); - w = NULL; - } while(!eof); - rv = 0; + } + + if(pat->rules[0] == NULL) { + flog(LOG_WARNING, "%s:%i: missing rules in match declaration", s->file, sl); + freepattern(pat); + return(NULL); + } + if(pat->childnm == NULL) { + flog(LOG_WARNING, "%s:%i: missing handler in match declaration", s->file, sl); + freepattern(pat); + return(NULL); + } + return(pat); +} + +static struct config *readconfig(char *filename) +{ + struct cfstate *s; + struct config *cf; + struct child *ch; + struct pattern *pat; + FILE *in; - if(w != NULL) - freeca(w); - fclose(s); + if((in = fopen(filename, "r")) == NULL) { + flog(LOG_WARNING, "%s: %s", filename, strerror(errno)); + return(NULL); + } + s = mkcfparser(in, filename); + omalloc(cf); + + while(1) { + getcfline(s); + if((ch = parsechild(s)) != NULL) { + ch->next = cf->children; + cf->children = ch; + } else if((pat = parsepattern(s)) != NULL) { + pat->next = cf->patterns; + cf->patterns = pat; + } else if(!strcmp(s->argv[0], "eof")) { + break; + } else { + flog(LOG_WARNING, "%s:%i: unknown directive `%s'", s->file, s->lno, s->argv[0]); + } + } + + freecfparser(s); + fclose(in); return(cf); } @@ -387,10 +297,10 @@ static void exprestpat(struct hthead *req, struct pattern *pat, char **mstr) bufadd(buf, '$'); p++; } else if(*p == '{') { - if((p2 = strchr(p, '{')) == NULL) { + if((p2 = strchr(p, '}')) == NULL) { p++; } else { - hdr = getheader(req, sprintf3("$.*s", p2 - p - 1, p + 1)); + hdr = getheader(req, sprintf3("%.*s", p2 - p - 1, p + 1)); if(hdr) bufcatstr(buf, hdr); } @@ -478,28 +388,6 @@ static char *findmatch(struct config *cf, struct hthead *req, int trydefault) return(NULL); } -static void forkchild(struct child *ch) -{ - ch->fd = stdmkchild(ch->argv); -} - -static void passreq(struct child *ch, struct hthead *req, int fd) -{ - if(ch->fd < 0) - forkchild(ch); - if(sendreq(ch->fd, req, fd)) { - if(errno == EPIPE) { - /* Assume that the child has crashed and restart it. */ - forkchild(ch); - if(!sendreq(ch->fd, req, fd)) - return; - } - flog(LOG_ERR, "could not pass on request to child %s: %s", ch->name, strerror(errno)); - close(ch->fd); - ch->fd = -1; - } -} - static void serve(struct hthead *req, int fd) { char *chnm; @@ -515,11 +403,8 @@ static void serve(struct hthead *req, int fd) return; } - if(ch->type == CH_SOCKET) { - passreq(ch, req, fd); - } else if(ch->type == CH_FORK) { - stdforkserve(ch->argv, req, fd); - } + if(childhandle(ch, req, fd)) + simpleerror(fd, 500, "Server Error", "The request handler crashed."); } int main(int argc, char **argv) -- 2.11.0