time_t mtime, lastck;
struct child *children;
struct pattern *patterns;
+ char **index;
};
struct rule {
int type;
- char *pattern;
+ char **patterns;
};
struct pattern {
struct pattern *next;
char *childnm;
+ char **fchild;
struct rule **rules;
};
-struct config *cflist;
+static struct config *cflist;
+static struct config *gconfig, *lconfig;
static time_t now;
+static void freerule(struct rule *rule)
+{
+ freeca(rule->patterns);
+ free(rule);
+}
+
static void freepattern(struct pattern *pat)
{
struct rule **rule;
- for(rule = pat->rules; *rule; rule++) {
- if((*rule)->pattern != NULL)
- free((*rule)->pattern);
- free(*rule);
- }
+ for(rule = pat->rules; *rule; rule++)
+ freerule(*rule);
if(pat->childnm != NULL)
free(pat->childnm);
+ freeca(pat->fchild);
free(pat);
}
cf->next->prev = cf->prev;
if(cf == cflist)
cflist = cf->next;
- free(cf->path);
+ if(cf->path != NULL)
+ free(cf->path);
for(ch = cf->children; ch != NULL; ch = nch) {
nch = ch->next;
freechild(ch);
npat = pat->next;
freepattern(pat);
}
+ freeca(cf->index);
free(cf);
}
return(pat);
}
+static char **cadup(char **w)
+{
+ char **ret;
+ int i, l;
+
+ l = calen(w);
+ ret = smalloc(sizeof(*ret) * (l + 1));
+ for(i = 0; i < l; i++)
+ ret[i] = sstrdup(w[i]);
+ ret[i] = NULL;
+ return(ret);
+}
+
static struct pattern *parsepattern(struct cfstate *s)
{
struct pattern *pat;
}
rule = newrule(pat);
rule->type = PAT_BASENAME;
- rule->pattern = sstrdup(s->argv[1]);
+ rule->patterns = cadup(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);
}
rule = newrule(pat);
rule->type = PAT_PATHNAME;
- rule->pattern = sstrdup(s->argv[1]);
+ rule->patterns = cadup(s->argv + 1);
} else if(!strcmp(s->argv[0], "all")) {
newrule(pat)->type = PAT_ALL;
} else if(!strcmp(s->argv[0], "default")) {
if(pat->childnm != NULL)
free(pat->childnm);
pat->childnm = sstrdup(s->argv[1]);
+ } else if(!strcmp(s->argv[0], "fork")) {
+ pat->fchild = cadup(s->argv + 1);
} else if(!strcmp(s->argv[0], "end") || !strcmp(s->argv[0], "eof")) {
break;
} else {
freepattern(pat);
return(NULL);
}
- if(pat->childnm == NULL) {
+ if((pat->childnm == NULL) && (pat->fchild == NULL)) {
flog(LOG_WARNING, "%s:%i: missing handler in match declaration", s->file, sl);
freepattern(pat);
return(NULL);
} else if((pat = parsepattern(s)) != NULL) {
pat->next = cf->patterns;
cf->patterns = pat;
+ } else if(!strcmp(s->argv[0], "index-file")) {
+ freeca(cf->index);
+ cf->index = NULL;
+ if(s->argc > 1)
+ cf->index = cadup(s->argv + 1);
} else if(!strcmp(s->argv[0], "eof")) {
break;
} else {
cf->mtime = mtime;
cf->lastck = now;
cf->next = cflist;
+ cf->prev = NULL;
+ if(cflist != NULL)
+ cflist->prev = cf;
cflist = cf;
return(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 pattern *findmatch(char *file, int trydefault)
{
- int i, c;
+ int i, o, c;
char *bn;
struct config **cfs;
struct pattern *pat;
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))
+ 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) {
- if(fnmatch(rule->pattern, file, FNM_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) {
simpleerror(fd, 404, "Not Found", "The requested URL has no corresponding resource.");
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(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.");
}
-
- if(childhandle(ch, req, fd))
- simpleerror(fd, 500, "Server Error", "The request handler crashed.");
}
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.");
+ struct config **cfs;
+ int i, o;
+ struct stat sb;
+ char *inm, *ipath, *p;
+ DIR *dir;
+ struct dirent *dent;
+
+ cfs = getconfigs(sprintf3("%s/", path));
+ for(i = 0; cfs[i] != NULL; i++) {
+ if(cfs[i]->index != NULL) {
+ for(o = 0; cfs[i]->index[o] != NULL; o++) {
+ inm = cfs[i]->index[o];
+ ipath = sprintf2("%s/%s", path, inm);
+ if(!stat(ipath, &sb) && S_ISREG(sb.st_mode)) {
+ handlefile(req, fd, ipath);
+ free(ipath);
+ return;
+ }
+ free(ipath);
+
+ ipath = NULL;
+ if(!strchr(inm, '.') && ((dir = opendir(path)) != NULL)) {
+ while((dent = readdir(dir)) != NULL) {
+ if((p = strchr(dent->d_name, '.')) == NULL)
+ continue;
+ if(strncmp(dent->d_name, inm, strlen(inm)))
+ continue;
+ ipath = sprintf2("%s/%s", path, dent->d_name);
+ if(stat(ipath, &sb) || !S_ISREG(sb.st_mode)) {
+ free(ipath);
+ ipath = NULL;
+ continue;
+ }
+ break;
+ }
+ closedir(dir);
+ }
+ if(ipath != NULL) {
+ handlefile(req, fd, ipath);
+ free(ipath);
+ return;
+ }
+ }
+ break;
+ }
+ }
+ /* XXX: Directory listings */
+ simpleerror(fd, 403, "Not Authorized", "Will not send listings for this directory.");
}
static int checkdir(struct hthead *req, int fd, char *path)
} else {
*(p2++) = 0;
}
+ if((tmp = unquoteurl(p)) == NULL) {
+ simpleerror(fd, 400, "Bad Request", "The requested URL contains an invalid escape sequence.");
+ goto fail;
+ }
+ strcpy(p, tmp);
+ free(tmp);
if(!*p) {
if(p2 == NULL) {
free(path);
}
+static void usage(FILE *out)
+{
+ fprintf(out, "usage: dirplex [-hN] [-c CONFIG] DIR\n");
+}
+
int main(int argc, char **argv)
{
+ int c;
+ int nodef;
+ char *gcf, *lcf;
struct hthead *req;
int fd;
- if(argc < 2) {
- flog(LOG_ERR, "usage: dirplex DIR");
+ nodef = 0;
+ lcf = NULL;
+ while((c = getopt(argc, argv, "hNc:")) >= 0) {
+ switch(c) {
+ case 'h':
+ usage(stdout);
+ exit(0);
+ case 'N':
+ nodef = 1;
+ break;
+ case 'c':
+ lcf = optarg;
+ break;
+ default:
+ usage(stderr);
+ exit(1);
+ }
+ }
+ if(argc - optind < 1) {
+ usage(stderr);
exit(1);
}
- if(chdir(argv[1])) {
- flog(LOG_ERR, "could not change directory to %s: %s", argv[1], strerror(errno));
+ if(!nodef) {
+ if((gcf = findstdconf("ashd/dirplex.rc")) != NULL) {
+ gconfig = readconfig(gcf);
+ free(gcf);
+ }
+ }
+ if(lcf != NULL) {
+ if((lconfig = readconfig(lcf)) == NULL)
+ exit(1);
+ }
+ if(chdir(argv[optind])) {
+ flog(LOG_ERR, "could not change directory to %s: %s", argv[optind], strerror(errno));
exit(1);
}
signal(SIGCHLD, SIG_IGN);