X-Git-Url: http://dolda2000.com/gitweb/?a=blobdiff_plain;f=src%2Fdirplex.c;h=699819f4952ccfb7bc1f79de590f6b81e233802e;hb=755faed02a98d53ed7dd2889e36f177d926f4638;hp=a79a78c27f84724854ef8fbeaff0b0f7dd672cca;hpb=992ce9ef8adb25fdcc47264187450a3edb287167;p=ashd.git diff --git a/src/dirplex.c b/src/dirplex.c index a79a78c..699819f 100644 --- a/src/dirplex.c +++ b/src/dirplex.c @@ -34,9 +34,8 @@ #include #include #include - -#define CH_SOCKET 0 -#define CH_FORK 1 +#include +#include #define PAT_BASENAME 0 #define PAT_PATHNAME 1 @@ -51,14 +50,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; @@ -72,17 +63,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; @@ -120,17 +100,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; @@ -149,7 +118,7 @@ static struct rule *newrule(struct pattern *pat) for(i = 0; pat->rules[i]; i++); pat->rules = srealloc(pat->rules, sizeof(*pat->rules) * (i + 2)); - rule = pat->rules[i] = smalloc(sizeof(*rule)); + rule = pat->rules[i] = szmalloc(sizeof(*rule)); pat->rules[i + 1] = NULL; return(rule); } @@ -163,164 +132,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; - if(stat(path, &sb)) + p = sprintf3("%s/.htrc", path); + if(stat(p, &sb)) return(NULL); - if((s = fopen(sprintf3("%s/.htrc", path), "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); } @@ -331,7 +245,7 @@ static struct config *getconfig(char *path) for(cf = cflist; cf != NULL; cf = cf->next) { if(!strcmp(cf->path, path)) { - if(stat(path, &sb)) + if(stat(sprintf3("%s/.htrc", path), &sb)) return(NULL); if(sb.st_mtime != cf->mtime) { freeconfig(cf); @@ -347,96 +261,6 @@ static struct config *getconfig(char *path) return(cf); } -static char *findfile(struct hthead *req, char *nm) -{ - char *p, *p2, *path, *ftmp, *buf, *rv, *p3; - struct stat sb; - DIR *dir; - struct dirent *dent; - - path = sstrdup("."); - p = nm; - rv = NULL; - while(1) { - if((p2 = strchr(p, '/')) == NULL) { - } else { - *(p2++) = 0; - } - - if(!*p) { - if(p2 == NULL) { - rv = sstrdup(path); - break; - } else { - goto fail; - } - } - if(*p == '.') - goto fail; - - getconfig(path); - - /* - * First, check the name verbatimely: - */ - buf = sprintf3("%s/%s", path, p); - if(!stat(buf, &sb)) { - if(S_ISDIR(sb.st_mode)) { - ftmp = path; - if(!strcmp(path, ".")) - path = sstrdup(p); - else - path = sprintf2("%s/%s", path, p); - free(ftmp); - goto next; - } - if(S_ISREG(sb.st_mode)) { - rv = sstrdup(buf); - break; - } - goto fail; - } - - /* - * Check the file extensionlessly: - */ - if(!strchr(p, '.') && ((dir = opendir(path)) != NULL)) { - while((dent = readdir(dir)) != NULL) { - buf = sprintf3("%s/%s", path, dent->d_name); - if((p3 = strchr(dent->d_name, '.')) != NULL) - *p3 = 0; - if(strcmp(dent->d_name, p)) - continue; - if(stat(buf, &sb)) - continue; - if(!S_ISREG(sb.st_mode)) - continue; - rv = sstrdup(buf); - break; - } - closedir(dir); - if(dent != NULL) - break; - } - - goto fail; - - next: - if(p2 == NULL) - break; - p = p2; - } - if(!strncmp(rv, "./", 2)) - memmove(rv, rv + 2, strlen(rv + 2) + 1); - goto out; - -fail: - rv = NULL; -out: - free(path); - return(rv); -} - static struct child *findchild(char *file, char *name) { char *buf, *p; @@ -510,69 +334,155 @@ out: return(pat); } -static void forkchild(struct child *ch) +static void handlefile(struct hthead *req, int fd, char *path) { - ch->fd = stdmkchild(ch->argv); + struct pattern *pat; + struct child *ch; + + headappheader(req, "X-Ash-File", path); + if(((pat = findmatch(path, 0)) == NULL) && ((pat = findmatch(path, 1)) == NULL)) { + /* XXX: Send a 500 error? 404? */ + return; + } + if((ch = findchild(path, pat->childnm)) == NULL) { + flog(LOG_ERR, "child %s requested, but was not declared", pat->childnm); + simpleerror(fd, 500, "Configuration Error", "The server is erroneously configured. Handler %s was requested, but not declared.", pat->childnm); + return; + } + + if(childhandle(ch, req, fd)) + simpleerror(fd, 500, "Server Error", "The request handler crashed."); } -static void passreq(struct child *ch, struct hthead *req, int fd) +static void handledir(struct hthead *req, int fd, char *path) { - 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; - } + /* XXX: Todo */ + simpleerror(fd, 403, "Not Authorized", "Will not send directory listings or indices yet."); +} + +static int checkdir(struct hthead *req, int fd, char *path) +{ + return(0); } static void serve(struct hthead *req, int fd) { - char *file; + char *p, *p2, *path, *tmp, *buf, *p3, *nm; struct stat sb; - struct pattern *pat; - struct child *ch; + DIR *dir; + struct dirent *dent; - if((file = findfile(req, req->rest)) == NULL) { - /* XXX: Do 404 handling */ - return; - } - replrest(req, file); - if(stat(file, &sb)) { - flog(LOG_ERR, "could not stat previously found file %s: %s", file, strerror(errno)); - free(file); - return; - } - if(!S_ISREG(sb.st_mode)) { - /* XXX: Handle default files or similar stuff. */ - free(file); - return; - } - if(((pat = findmatch(file, 0)) == NULL) && ((pat = findmatch(file, 1)) == NULL)) { - /* XXX: Send a 500 error? 404? */ - free(file); - return; - } - if((ch = findchild(file, pat->childnm)) == NULL) { - /* XXX: Send a 500 error. */ - flog(LOG_ERR, "child %s requested, but was not declared", pat->childnm); - free(file); - return; + nm = req->rest; + path = sstrdup("."); + p = nm; + while(1) { + if((p2 = strchr(p, '/')) == NULL) { + } else { + *(p2++) = 0; + } + + if(!*p) { + if(p2 == NULL) { + if(stat(path, &sb)) { + flog(LOG_WARNING, "failed to stat previously stated directory %s: %s", path, strerror(errno)); + simpleerror(fd, 500, "Internal Server Error", "The server encountered an unexpected condition."); + goto fail; + } + break; + } else { + simpleerror(fd, 404, "Not Found", "The requested URL has no corresponding resource."); + goto fail; + } + } + if(*p == '.') { + simpleerror(fd, 404, "Not Found", "The requested URL has no corresponding resource."); + goto fail; + } + + getconfig(path); + + /* + * First, check the name verbatimely: + */ + buf = sprintf3("%s/%s", path, p); + if(!stat(buf, &sb)) { + if(S_ISDIR(sb.st_mode)) { + tmp = path; + if(!strcmp(path, ".")) + path = sstrdup(p); + 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; + } + if(S_ISREG(sb.st_mode)) { + tmp = path; + path = sprintf2("%s/%s", path, p); + free(tmp); + break; + } + simpleerror(fd, 404, "Not Found", "The requested URL has no corresponding resource."); + goto fail; + } + + /* + * Check the file extensionlessly: + */ + if(!strchr(p, '.') && ((dir = opendir(path)) != NULL)) { + while((dent = readdir(dir)) != NULL) { + buf = sprintf3("%s/%s", path, dent->d_name); + if((p3 = strchr(dent->d_name, '.')) != NULL) + *p3 = 0; + if(strcmp(dent->d_name, p)) + continue; + if(stat(buf, &sb)) + continue; + if(!S_ISREG(sb.st_mode)) + continue; + tmp = path; + path = sstrdup(buf); + free(tmp); + break; + } + closedir(dir); + if(dent != NULL) + break; + } + + simpleerror(fd, 404, "Not Found", "The requested URL has no corresponding resource."); + goto fail; + + next: + if(p2 == NULL) + break; + p = p2; } - - if(ch->type == CH_SOCKET) { - passreq(ch, req, fd); - } else if(ch->type == CH_FORK) { - stdforkserve(ch->argv, req, fd); + if(p2 == NULL) + replrest(req, ""); + else + replrest(req, p2); + if(!strncmp(path, "./", 2)) + memmove(path, path + 2, strlen(path + 2) + 1); + if(S_ISDIR(sb.st_mode)) { + handledir(req, fd, path); + } else if(S_ISREG(sb.st_mode)) { + handlefile(req, fd, path); + } else { + simpleerror(fd, 404, "Not Found", "The requested URL has no corresponding resource."); + goto fail; } + goto out; - free(file); +fail: + /* No special handling, for now at least. */ +out: + free(path); } int main(int argc, char **argv)