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
--- /dev/null
+/*
+ ashd - A Sane HTTP Daemon
+ Copyright (C) 2008 Fredrik Tolf <fredrik@dolda2000.com>
+
+ 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 <http://www.gnu.org/licenses/>.
+*/
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <unistd.h>
+#include <string.h>
+#include <ctype.h>
+#include <glob.h>
+#include <errno.h>
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+#include <utils.h>
+#include <cf.h>
+#include <mt.h>
+#include <proc.h>
+#include <log.h>
+
+#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);
+}
--- /dev/null
+#ifndef _ASHCONF_H
+#define _ASHCONF_H
+
+#include <req.h>
+
+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
{
char **c;
+ if(ca == NULL)
+ return;
for(c = ca; *c; c++)
free(*c);
free(ca);
#include <req.h>
#include <proc.h>
#include <resp.h>
+#include <cf.h>
#define CH_SOCKET 0
#define CH_FORK 1
struct pattern *patterns;
};
-struct child {
- struct child *next;
- char *name;
- int type;
- char **argv;
- int fd;
-};
-
struct rule {
int type;
char *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;
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;
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);
}
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)
#include <req.h>
#include <proc.h>
#include <resp.h>
-
-#define CH_SOCKET 0
-#define CH_FORK 1
+#include <cf.h>
#define PAT_REST 0
#define PAT_URL 1
struct pattern *patterns;
};
-struct child {
- struct child *next;
- char *name;
- int type;
- char **argv;
- int fd;
-};
-
struct rule {
int type;
int fl;
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;
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);
}
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);
}
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;
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)