From 600a1ce79471493f8cad5fcf118dc9797331d5aa Mon Sep 17 00:00:00 2001 From: Fredrik Tolf Date: Sun, 5 Sep 2010 04:41:56 +0200 Subject: [PATCH] dirplex: Moved to its own directory and split off configuration code. --- configure.in | 1 + src/.gitignore | 1 - src/Makefile.am | 6 +- src/dirplex/.gitignore | 1 + src/dirplex/Makefile.am | 6 + src/{dirplex.c => dirplex/conf.c} | 329 ++------------------------------------ src/dirplex/dirplex.c | 315 ++++++++++++++++++++++++++++++++++++ src/dirplex/dirplex.h | 44 +++++ 8 files changed, 380 insertions(+), 323 deletions(-) create mode 100644 src/dirplex/.gitignore create mode 100644 src/dirplex/Makefile.am rename src/{dirplex.c => dirplex/conf.c} (53%) create mode 100644 src/dirplex/dirplex.c create mode 100644 src/dirplex/dirplex.h diff --git a/configure.in b/configure.in index fd42fd9..13dae8a 100644 --- a/configure.in +++ b/configure.in @@ -57,5 +57,6 @@ AC_SUBST(GNUTLS_LIBS) AC_OUTPUT([ Makefile src/Makefile +src/dirplex/Makefile lib/Makefile ]) diff --git a/src/.gitignore b/src/.gitignore index 9335700..4489a47 100644 --- a/src/.gitignore +++ b/src/.gitignore @@ -1,6 +1,5 @@ /htparser /debugsink -/dirplex /sendfile /callcgi /patplex diff --git a/src/Makefile.am b/src/Makefile.am index 9719507..cac55a3 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -1,9 +1,9 @@ -bin_PROGRAMS = htparser dirplex sendfile callcgi patplex userplex htls callscgi +SUBDIRS = dirplex + +bin_PROGRAMS = htparser sendfile callcgi patplex userplex htls callscgi noinst_PROGRAMS = debugsink htparser_SOURCES = htparser.c htparser.h plaintcp.c ssl-gnutls.c -dirplex_SOURCES = dirplex.c -debugsink_SOURCES = debugsink.c LDADD = $(top_srcdir)/lib/libht.a AM_CPPFLAGS = -I$(top_srcdir)/lib diff --git a/src/dirplex/.gitignore b/src/dirplex/.gitignore new file mode 100644 index 0000000..aca6107 --- /dev/null +++ b/src/dirplex/.gitignore @@ -0,0 +1 @@ +/dirplex diff --git a/src/dirplex/Makefile.am b/src/dirplex/Makefile.am new file mode 100644 index 0000000..97d9842 --- /dev/null +++ b/src/dirplex/Makefile.am @@ -0,0 +1,6 @@ +bin_PROGRAMS = dirplex + +dirplex_SOURCES = dirplex.c conf.c dirplex.h + +LDADD = $(top_srcdir)/lib/libht.a +AM_CPPFLAGS = -I$(top_srcdir)/lib diff --git a/src/dirplex.c b/src/dirplex/conf.c similarity index 53% rename from src/dirplex.c rename to src/dirplex/conf.c index de9ecf2..96a7704 100644 --- a/src/dirplex.c +++ b/src/dirplex/conf.c @@ -18,59 +18,23 @@ #include #include -#include #include +#include #include -#include -#include -#include #include -#include +#include #ifdef HAVE_CONFIG_H #include #endif #include -#include #include -#include -#include -#include #include -#define PAT_BASENAME 0 -#define PAT_PATHNAME 1 -#define PAT_ALL 2 -#define PAT_DEFAULT 3 - -#define PT_FILE 0 -#define PT_DIR 1 - -struct config { - struct config *next, *prev; - char *path; - time_t mtime, lastck; - struct child *children; - struct pattern *patterns; - char **index; -}; - -struct rule { - int type; - char **patterns; -}; - -struct pattern { - struct pattern *next; - int type; - char *childnm; - char **fchild; - struct rule **rules; -}; +#include "dirplex.h" static struct config *cflist; -static struct config *gconfig, *lconfig; -static time_t now; +struct config *gconfig, *lconfig; static void freerule(struct rule *rule) { @@ -115,7 +79,7 @@ static void freeconfig(struct config *cf) free(cf); } -static struct child *getchild(struct config *cf, char *name) +struct child *getchild(struct config *cf, char *name) { struct child *ch; @@ -236,7 +200,7 @@ static struct config *emptyconfig(void) return(cf); } -static struct config *readconfig(char *file) +struct config *readconfig(char *file) { struct cfstate *s; FILE *in; @@ -276,7 +240,7 @@ static struct config *readconfig(char *file) return(cf); } -static struct config *getconfig(char *path) +struct config *getconfig(char *path) { struct config *cf; struct stat sb; @@ -315,7 +279,7 @@ static struct config *getconfig(char *path) return(cf); } -static struct config **getconfigs(char *file) +struct config **getconfigs(char *file) { static struct config **ret = NULL; struct { @@ -347,7 +311,7 @@ static struct config **getconfigs(char *file) return(ret = buf.b); } -static struct child *findchild(char *file, char *name) +struct child *findchild(char *file, char *name) { int i; struct config **cfs; @@ -361,7 +325,7 @@ static struct child *findchild(char *file, char *name) return(ch); } -static struct pattern *findmatch(char *file, int trydefault, int dir) +struct pattern *findmatch(char *file, int trydefault, int dir) { int i, o, c; char *bn; @@ -409,276 +373,3 @@ static struct pattern *findmatch(char *file, int trydefault, int dir) 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 char *findfile(char *path, char *name, struct stat *sb) -{ - DIR *dir; - struct stat sbuf; - struct dirent *dent; - char *p, *fp, *ret; - - if(sb == NULL) - sb = &sbuf; - if((dir = opendir(path)) == NULL) - return(NULL); - ret = NULL; - while((dent = readdir(dir)) != NULL) { - /* Ignore backup files. - * XXX: There is probably a better and more extensible way to - * do this. */ - if(dent->d_name[strlen(dent->d_name) - 1] == '~') - continue; - if((p = strchr(dent->d_name, '.')) == NULL) - continue; - if(p - dent->d_name != strlen(name)) - continue; - if(strncmp(dent->d_name, name, strlen(name))) - continue; - fp = sprintf3("%s/%s", path, dent->d_name); - if(stat(fp, sb)) - continue; - if(!S_ISREG(sb->st_mode)) - continue; - ret = sstrdup(fp); - break; - } - closedir(dir); - return(ret); -} - -static void handledir(struct hthead *req, int fd, char *path) -{ - struct config **cfs; - int i, o; - struct stat sb; - char *inm, *ipath, *cpath; - struct pattern *pat; - - cpath = sprintf2("%s/", path); - cfs = getconfigs(cpath); - 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); - goto out; - } - free(ipath); - - if(!strchr(inm, '.') && ((ipath = findfile(path, inm, NULL)) != NULL)) { - handlefile(req, fd, ipath); - free(ipath); - goto out; - } - } - break; - } - } - if((pat = findmatch(cpath, 0, 1)) != NULL) { - handle(req, fd, cpath, pat); - goto out; - } - simpleerror(fd, 403, "Not Authorized", "Will not send listings for this directory."); - -out: - free(cpath); -} - -static int checkpath(struct hthead *req, int fd, char *path, char *rest); - -static int checkentry(struct hthead *req, int fd, char *path, char *rest, char *el) -{ - struct stat sb; - char *newpath; - int rv; - - if(!el == '.') { - simpleerror(fd, 404, "Not Found", "The requested URL has no corresponding resource."); - return(1); - } - if(!stat(sprintf3("%s/%s", path, el), &sb)) { - if(S_ISDIR(sb.st_mode)) { - if(!*rest) { - stdredir(req, fd, 301, sprintf3("%s/", el)); - return(1); - } - newpath = sprintf2("%s/%s", path, el); - rv = checkpath(req, fd, newpath, rest + 1); - free(newpath); - return(rv); - } else if(S_ISREG(sb.st_mode)) { - newpath = sprintf2("%s/%s", path, el); - replrest(req, rest); - handlefile(req, fd, newpath); - free(newpath); - return(1); - } - simpleerror(fd, 404, "Not Found", "The requested URL has no corresponding resource."); - return(1); - } - if(!strchr(el, '.') && ((newpath = findfile(path, el, NULL)) != NULL)) { - replrest(req, rest); - handlefile(req, fd, newpath); - free(newpath); - return(1); - } - return(0); -} - -static int checkpath(struct hthead *req, int fd, char *path, char *rest) -{ - struct config *cf; - char *p, *el; - int rv; - - el = NULL; - rv = 0; - - if(!strncmp(path, "./", 2)) - path += 2; - cf = getconfig(path); - - if((p = strchr(rest, '/')) == NULL) { - el = unquoteurl(rest); - rest = ""; - } else { - char buf[p - rest + 1]; - memcpy(buf, rest, p - rest); - buf[p - rest] = 0; - el = unquoteurl(buf); - rest = p; - } - if(el == NULL) { - simpleerror(fd, 400, "Bad Request", "The requested URL contains an invalid escape sequence."); - rv = 1; - goto out; - } - if(strchr(el, '/') || (!*el && *rest)) { - simpleerror(fd, 404, "Not Found", "The requested URL has no corresponding resource."); - rv = 1; - goto out; - } - if(!*el) { - replrest(req, rest); - handledir(req, fd, path); - return(1); - } - rv = checkentry(req, fd, path, rest, el); - -out: - if(el != NULL) - free(el); - return(rv); -} - -static void serve(struct hthead *req, int fd) -{ - now = time(NULL); - if(!checkpath(req, fd, ".", req->rest)) - simpleerror(fd, 404, "Not Found", "The requested URL has no corresponding resource."); -} - -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, *clcf; - struct hthead *req; - int fd; - - 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(!nodef) { - if((gcf = findstdconf("ashd/dirplex.rc")) != NULL) { - gconfig = readconfig(gcf); - free(gcf); - } - } - if(lcf != NULL) { - if(strchr(lcf, '/') == NULL) { - if((clcf = findstdconf(sprintf3("ashd/%s", lcf))) == NULL) { - flog(LOG_ERR, "could not find requested configuration `%s'", lcf); - exit(1); - } - if((lconfig = readconfig(clcf)) == NULL) - exit(1); - free(clcf); - } else { - 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); - while(1) { - if((fd = recvreq(0, &req)) < 0) { - if(errno != 0) - flog(LOG_ERR, "recvreq: %s", strerror(errno)); - break; - } - serve(req, fd); - freehthead(req); - close(fd); - } - return(0); -} diff --git a/src/dirplex/dirplex.c b/src/dirplex/dirplex.c new file mode 100644 index 0000000..f1f99e4 --- /dev/null +++ b/src/dirplex/dirplex.c @@ -0,0 +1,315 @@ +/* + ashd - A Sane HTTP Daemon + Copyright (C) 2008 Fredrik Tolf + + 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 . +*/ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#ifdef HAVE_CONFIG_H +#include +#endif +#include +#include +#include +#include +#include +#include + +#include "dirplex.h" + +time_t now; + +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 char *findfile(char *path, char *name, struct stat *sb) +{ + DIR *dir; + struct stat sbuf; + struct dirent *dent; + char *p, *fp, *ret; + + if(sb == NULL) + sb = &sbuf; + if((dir = opendir(path)) == NULL) + return(NULL); + ret = NULL; + while((dent = readdir(dir)) != NULL) { + /* Ignore backup files. + * XXX: There is probably a better and more extensible way to + * do this. */ + if(dent->d_name[strlen(dent->d_name) - 1] == '~') + continue; + if((p = strchr(dent->d_name, '.')) == NULL) + continue; + if(p - dent->d_name != strlen(name)) + continue; + if(strncmp(dent->d_name, name, strlen(name))) + continue; + fp = sprintf3("%s/%s", path, dent->d_name); + if(stat(fp, sb)) + continue; + if(!S_ISREG(sb->st_mode)) + continue; + ret = sstrdup(fp); + break; + } + closedir(dir); + return(ret); +} + +static void handledir(struct hthead *req, int fd, char *path) +{ + struct config **cfs; + int i, o; + struct stat sb; + char *inm, *ipath, *cpath; + struct pattern *pat; + + cpath = sprintf2("%s/", path); + cfs = getconfigs(cpath); + 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); + goto out; + } + free(ipath); + + if(!strchr(inm, '.') && ((ipath = findfile(path, inm, NULL)) != NULL)) { + handlefile(req, fd, ipath); + free(ipath); + goto out; + } + } + break; + } + } + if((pat = findmatch(cpath, 0, 1)) != NULL) { + handle(req, fd, cpath, pat); + goto out; + } + simpleerror(fd, 403, "Not Authorized", "Will not send listings for this directory."); + +out: + free(cpath); +} + +static int checkpath(struct hthead *req, int fd, char *path, char *rest); + +static int checkentry(struct hthead *req, int fd, char *path, char *rest, char *el) +{ + struct stat sb; + char *newpath; + int rv; + + if(!el == '.') { + simpleerror(fd, 404, "Not Found", "The requested URL has no corresponding resource."); + return(1); + } + if(!stat(sprintf3("%s/%s", path, el), &sb)) { + if(S_ISDIR(sb.st_mode)) { + if(!*rest) { + stdredir(req, fd, 301, sprintf3("%s/", el)); + return(1); + } + newpath = sprintf2("%s/%s", path, el); + rv = checkpath(req, fd, newpath, rest + 1); + free(newpath); + return(rv); + } else if(S_ISREG(sb.st_mode)) { + newpath = sprintf2("%s/%s", path, el); + replrest(req, rest); + handlefile(req, fd, newpath); + free(newpath); + return(1); + } + simpleerror(fd, 404, "Not Found", "The requested URL has no corresponding resource."); + return(1); + } + if(!strchr(el, '.') && ((newpath = findfile(path, el, NULL)) != NULL)) { + replrest(req, rest); + handlefile(req, fd, newpath); + free(newpath); + return(1); + } + return(0); +} + +static int checkpath(struct hthead *req, int fd, char *path, char *rest) +{ + struct config *cf; + char *p, *el; + int rv; + + el = NULL; + rv = 0; + + if(!strncmp(path, "./", 2)) + path += 2; + cf = getconfig(path); + + if((p = strchr(rest, '/')) == NULL) { + el = unquoteurl(rest); + rest = ""; + } else { + char buf[p - rest + 1]; + memcpy(buf, rest, p - rest); + buf[p - rest] = 0; + el = unquoteurl(buf); + rest = p; + } + if(el == NULL) { + simpleerror(fd, 400, "Bad Request", "The requested URL contains an invalid escape sequence."); + rv = 1; + goto out; + } + if(strchr(el, '/') || (!*el && *rest)) { + simpleerror(fd, 404, "Not Found", "The requested URL has no corresponding resource."); + rv = 1; + goto out; + } + if(!*el) { + replrest(req, rest); + handledir(req, fd, path); + return(1); + } + rv = checkentry(req, fd, path, rest, el); + +out: + if(el != NULL) + free(el); + return(rv); +} + +static void serve(struct hthead *req, int fd) +{ + now = time(NULL); + if(!checkpath(req, fd, ".", req->rest)) + simpleerror(fd, 404, "Not Found", "The requested URL has no corresponding resource."); +} + +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, *clcf; + struct hthead *req; + int fd; + + 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(!nodef) { + if((gcf = findstdconf("ashd/dirplex.rc")) != NULL) { + gconfig = readconfig(gcf); + free(gcf); + } + } + if(lcf != NULL) { + if(strchr(lcf, '/') == NULL) { + if((clcf = findstdconf(sprintf3("ashd/%s", lcf))) == NULL) { + flog(LOG_ERR, "could not find requested configuration `%s'", lcf); + exit(1); + } + if((lconfig = readconfig(clcf)) == NULL) + exit(1); + free(clcf); + } else { + 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); + while(1) { + if((fd = recvreq(0, &req)) < 0) { + if(errno != 0) + flog(LOG_ERR, "recvreq: %s", strerror(errno)); + break; + } + serve(req, fd); + freehthead(req); + close(fd); + } + return(0); +} diff --git a/src/dirplex/dirplex.h b/src/dirplex/dirplex.h new file mode 100644 index 0000000..14b704c --- /dev/null +++ b/src/dirplex/dirplex.h @@ -0,0 +1,44 @@ +#ifndef _ASH_DIRPLEX_H +#define _ASH_DIRPLEX_H + +#define PAT_BASENAME 0 +#define PAT_PATHNAME 1 +#define PAT_ALL 2 +#define PAT_DEFAULT 3 + +#define PT_FILE 0 +#define PT_DIR 1 + +struct config { + struct config *next, *prev; + char *path; + time_t mtime, lastck; + struct child *children; + struct pattern *patterns; + char **index; +}; + +struct rule { + int type; + char **patterns; +}; + +struct pattern { + struct pattern *next; + int type; + char *childnm; + char **fchild; + struct rule **rules; +}; + +struct child *getchild(struct config *cf, char *name); +struct config *readconfig(char *file); +struct config *getconfig(char *path); +struct config **getconfigs(char *file); +struct child *findchild(char *file, char *name); +struct pattern *findmatch(char *file, int trydefault, int dir); + +extern time_t now; +extern struct config *gconfig, *lconfig; + +#endif -- 2.11.0