+ static struct config **ret = NULL;
+ struct {
+ struct config **b;
+ size_t s, d;
+ } buf;
+ struct config *cf;
+ char *tmp, *p;
+
+ if(ret != NULL)
+ free(ret);
+ bufinit(buf);
+ tmp = sstrdup(file);
+ while(1) {
+ if((p = strrchr(tmp, '/')) == NULL)
+ break;
+ *p = 0;
+ if((cf = getconfig(tmp)) != NULL)
+ bufadd(buf, cf);
+ }
+ free(tmp);
+ if((cf = getconfig(".")) != NULL)
+ bufadd(buf, cf);
+ if(lconfig != NULL)
+ bufadd(buf, lconfig);
+ if(gconfig != NULL)
+ bufadd(buf, gconfig);
+ 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;
+ }
+ return(ch);
+}
+
+static struct pattern *findmatch(char *file, int trydefault, int dir)
+{
+ int i, o, c;
+ char *bn;
+ struct config **cfs;
+ struct pattern *pat;
+ struct rule *rule;
+
+ if((bn = strrchr(file, '/')) != NULL)
+ bn++;
+ else
+ bn = file;
+ cfs = getconfigs(file);
+ for(c = 0; cfs[c] != NULL; c++) {
+ for(pat = cfs[c]->patterns; pat != NULL; pat = pat->next) {
+ if(!dir && (pat->type == PT_DIR))
+ continue;
+ if(dir && (pat->type != PT_DIR))
+ continue;
+ for(i = 0; (rule = pat->rules[i]) != NULL; i++) {
+ if(rule->type == PAT_BASENAME) {
+ for(o = 0; rule->patterns[o] != NULL; o++) {
+ if(!fnmatch(rule->patterns[o], bn, 0))
+ break;
+ }
+ if(rule->patterns[o] == NULL)
+ break;
+ } else if(rule->type == PAT_PATHNAME) {
+ for(o = 0; rule->patterns[o] != NULL; o++) {
+ if(!fnmatch(rule->patterns[o], file, FNM_PATHNAME))
+ break;
+ }
+ if(rule->patterns[o] == NULL)
+ break;
+ } else if(rule->type == PAT_ALL) {
+ } else if(rule->type == PAT_DEFAULT) {
+ if(!trydefault)
+ break;
+ }
+ }
+ if(!rule)
+ return(pat);
+ }
+ }
+ if(!trydefault)
+ return(findmatch(file, 1, dir));
+ return(NULL);
+}
+
+static void handle(struct hthead *req, int fd, char *path, struct pattern *pat)
+{
+ struct child *ch;
+
+ headappheader(req, "X-Ash-File", path);
+ if(pat->fchild) {
+ stdforkserve(pat->fchild, req, fd);
+ } else {
+ 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 handlefile(struct hthead *req, int fd, char *path)
+{
+ struct pattern *pat;
+
+ if((pat = findmatch(path, 0, 0)) == NULL) {
+ simpleerror(fd, 404, "Not Found", "The requested URL has no corresponding resource.");
+ return;
+ }
+ handle(req, fd, path, pat);
+}
+
+static void handledir(struct hthead *req, int fd, char *path)
+{
+ struct config **cfs;
+ int i, o;