X-Git-Url: http://git.dolda2000.com/gitweb/?a=blobdiff_plain;ds=sidebyside;f=src%2Fdirplex.c;h=fa4bae51dbd38d5e2e85691f0a77345f74c59b70;hb=c3b910928f34306f34ee6a9c3c13debbf8ff67f4;hp=6dccff56b40053dd02cdd6cd8021bb5473212cdd;hpb=06c1a7183754349e29a6f4656d88d3f89e4f448a;p=ashd.git diff --git a/src/dirplex.c b/src/dirplex.c index 6dccff5..fa4bae5 100644 --- a/src/dirplex.c +++ b/src/dirplex.c @@ -25,6 +25,7 @@ #include #include #include +#include #ifdef HAVE_CONFIG_H #include @@ -37,9 +38,6 @@ #include #include -#define CH_SOCKET 0 -#define CH_FORK 1 - #define PAT_BASENAME 0 #define PAT_PATHNAME 1 #define PAT_ALL 2 @@ -48,7 +46,7 @@ struct config { struct config *next, *prev; char *path; - time_t mtime; + time_t mtime, lastck; struct child *children; struct pattern *patterns; }; @@ -65,6 +63,7 @@ struct pattern { }; struct config *cflist; +static time_t now; static void freepattern(struct pattern *pat) { @@ -199,27 +198,28 @@ static struct pattern *parsepattern(struct cfstate *s) return(pat); } -static struct config *readconfig(char *path) +static struct config *emptyconfig(void) +{ + struct config *cf; + + omalloc(cf); + return(cf); +} + +static struct config *readconfig(char *file) { struct cfstate *s; FILE *in; struct config *cf; struct child *child; struct pattern *pat; - struct stat sb; - char *p; - p = sprintf3("%s/.htrc", path); - if(stat(p, &sb)) - return(NULL); - if((in = fopen(p, "r")) == NULL) { - flog(LOG_WARNING, "%s: %s", p, strerror(errno)); + if((in = fopen(file, "r")) == NULL) { + flog(LOG_WARNING, "%s: %s", file, strerror(errno)); return(NULL); } - s = mkcfparser(in, p); - omalloc(cf); - cf->mtime = sb.st_mtime; - cf->path = sstrdup(path); + s = mkcfparser(in, file); + cf = emptyconfig(); while(1) { getcfline(s); @@ -245,55 +245,85 @@ static struct config *getconfig(char *path) { struct config *cf; struct stat sb; + char *fn; + time_t mtime; + fn = sprintf3("%s/.htrc", path); for(cf = cflist; cf != NULL; cf = cf->next) { if(!strcmp(cf->path, path)) { - if(stat(sprintf3("%s/.htrc", path), &sb)) - return(NULL); - if(sb.st_mtime != cf->mtime) { - freeconfig(cf); - break; + if(now - cf->lastck > 5) { + if(stat(fn, &sb) || (sb.st_mtime != cf->mtime)) { + freeconfig(cf); + break; + } } + cf->lastck = now; return(cf); } } - if((cf = readconfig(path)) != NULL) { - cf->next = cflist; - cflist = cf; + if(access(fn, R_OK) || stat(fn, &sb)) { + cf = emptyconfig(); + mtime = 0; + } else { + if((cf = readconfig(fn)) == NULL) + return(NULL); + mtime = sb.st_mtime; } + cf->path = sstrdup(path); + cf->mtime = mtime; + cf->lastck = now; + cf->next = cflist; + cflist = cf; return(cf); } -static struct child *findchild(char *file, char *name) +static struct config **getconfigs(char *file) { - char *buf, *p; + static struct config **ret = NULL; + struct { + struct config **b; + size_t s, d; + } buf; struct config *cf; - struct child *ch; - - buf = sstrdup(file); + char *tmp, *p; + + if(ret != NULL) + free(ret); + bufinit(buf); + tmp = sstrdup(file); while(1) { - ch = NULL; - if(!strcmp(buf, ".")) + if((p = strrchr(tmp, '/')) == NULL) break; - if((p = strrchr(buf, '/')) != NULL) - *p = 0; - else - strcpy(buf, "."); - cf = getconfig(buf); - if(cf == NULL) - continue; - if((ch = getchild(cf, name)) != NULL) + *p = 0; + if((cf = getconfig(tmp)) != NULL) + bufadd(buf, cf); + } + free(tmp); + if((cf = getconfig(".")) != NULL) + bufadd(buf, cf); + bufadd(buf, NULL); + return(ret = buf.b); +} + +static struct child *findchild(char *file, char *name) +{ + int i; + struct config **cfs; + struct child *ch; + + cfs = getconfigs(file); + for(i = 0; cfs[i] != NULL; i++) { + if((ch = getchild(cfs[i], name)) != NULL) break; } - free(buf); return(ch); } static struct pattern *findmatch(char *file, int trydefault) { - int i; - char *buf, *p, *bn; - struct config *cf; + int i, c; + char *bn; + struct config **cfs; struct pattern *pat; struct rule *rule; @@ -301,19 +331,9 @@ static struct pattern *findmatch(char *file, int trydefault) bn++; else bn = file; - buf = sstrdup(file); - while(1) { - pat = NULL; - if(!strcmp(buf, ".")) - break; - if((p = strrchr(buf, '/')) != NULL) - *p = 0; - else - strcpy(buf, "."); - cf = getconfig(buf); - if(cf == NULL) - continue; - for(pat = cf->patterns; pat != NULL; pat = pat->next) { + cfs = getconfigs(file); + for(c = 0; cfs[c] != NULL; c++) { + for(pat = cfs[c]->patterns; pat != NULL; pat = pat->next) { for(i = 0; (rule = pat->rules[i]) != NULL; i++) { if(rule->type == PAT_BASENAME) { if(fnmatch(rule->pattern, bn, 0)) @@ -328,36 +348,10 @@ static struct pattern *findmatch(char *file, int trydefault) } } if(!rule) - goto out; + return(pat); } } - -out: - free(buf); - return(pat); -} - -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; - simpleerror(fd, 500, "Server Error", "The request handler crashed."); - } + return(NULL); } static void handlefile(struct hthead *req, int fd, char *path) @@ -367,7 +361,7 @@ static void handlefile(struct hthead *req, int fd, char *path) headappheader(req, "X-Ash-File", path); if(((pat = findmatch(path, 0)) == NULL) && ((pat = findmatch(path, 1)) == NULL)) { - /* XXX: Send a 500 error? 404? */ + simpleerror(fd, 404, "Not Found", "The requested URL has no corresponding resource."); return; } if((ch = findchild(path, pat->childnm)) == NULL) { @@ -376,11 +370,8 @@ static void handlefile(struct hthead *req, int fd, char *path) 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."); } static void handledir(struct hthead *req, int fd, char *path) @@ -401,6 +392,7 @@ static void serve(struct hthead *req, int fd) DIR *dir; struct dirent *dent; + now = time(NULL); nm = req->rest; path = sstrdup("."); p = nm; @@ -442,6 +434,10 @@ static void serve(struct hthead *req, int fd) else path = sprintf2("%s/%s", path, p); free(tmp); + if(p2 == NULL) { + stdredir(req, fd, 301, sprintf3("%s/", p)); + goto out; + } if(checkdir(req, fd, path)) break; goto next;