From b70b2d4f237082541d01b4b33abc86ef2b7b2223 Mon Sep 17 00:00:00 2001 From: Fredrik Tolf Date: Fri, 28 Jan 2011 04:10:11 +0100 Subject: [PATCH] dirplex: Made the 404 response indirectible and reusable. --- doc/dirplex.doc | 36 +++++++++++++++++++++++++++++------- src/dirplex/conf.c | 21 +++++++++++++++++++++ src/dirplex/dirplex.c | 28 ++++++++++++++++++++-------- src/dirplex/dirplex.h | 1 + 4 files changed, 71 insertions(+), 15 deletions(-) diff --git a/doc/dirplex.doc b/doc/dirplex.doc index 7e9ab38..d41c1ad 100644 --- a/doc/dirplex.doc +++ b/doc/dirplex.doc @@ -55,11 +55,10 @@ being examined is considered the result of the mapping. Otherwise, any escape sequences in the path element under consideration are unescaped before examining it. -Any path element that begins with a dot is considered invalid and -results in a 404 response to the client. If the path element names a -directory in the current directory, the procedure continues in that -directory. If it names a file, that file is considered the result of -the mapping (even if the rest string has not been exhausted yet). +If the path element names a directory in the current directory, the +procedure continues in that directory. If it names a file, that file +is considered the result of the mapping (even if the rest string has +not been exhausted yet). If the path element does not name anything in the directory under consideration, but contains no dots, then the directory is searched @@ -75,6 +74,8 @@ index file name contains no dots and there is no exact match, then, again, the directory is searched for a file whose name before the first dot matches the index file name. +See also 404 RESPONSES below. + CONFIGURATION ------------- @@ -245,8 +246,29 @@ following actions are recognized: by a *fchild* stanza. This action exists mostly for convenience. -If no *match* stanza matches, a 404 response is returned to the -client. +404 RESPONSES +------------- + +Any of the following cases will result in a 404 response being sent to +the client. + + * Failure of the mapping procedure to find a matching physical file. + * Presence of a path element during mapping that begins with a dot. + * A path element which, after URL unescaping, contains slashes. + * The mapping procedure finding a file which is neither a directory + nor a regular file. + * Presence of a non-final but empty path element during mapping. + * A physical file having been found which is not being matched by any + *match* stanza. + +*dirplex* will send a built-in 404 response by default, but any +`.htrc` file or global configuration may define a request handler +named `.notfound` to customize the behavior. Note that, unlike +successful requests, such a handler will not be passed the +`X-Ash-File` header. + +The built-in `.notfound` handler can also be used in *match* or +*capture* stanzas. EXAMPLES -------- diff --git a/src/dirplex/conf.c b/src/dirplex/conf.c index b90163a..03d5477 100644 --- a/src/dirplex/conf.c +++ b/src/dirplex/conf.c @@ -30,6 +30,7 @@ #include #include #include +#include #include "dirplex.h" @@ -332,6 +333,8 @@ struct child *findchild(char *file, char *name, struct config **cf) struct config **cfs; struct child *ch; + if(cf != NULL) + *cf = NULL; cfs = getconfigs(file); for(i = 0; cfs[i] != NULL; i++) { if((ch = getchild(cfs[i], name)) != NULL) { @@ -340,6 +343,8 @@ struct child *findchild(char *file, char *name, struct config **cf) return(ch); } } + if(!strcmp(name, ".notfound")) + return(notfound); return(NULL); } @@ -398,3 +403,19 @@ struct pattern *findmatch(char *file, int trydefault, int dir) return(findmatch(file, 1, dir)); return(NULL); } + +static int donotfound(struct child *ch, struct hthead *req, int fd, void (*chinit)(void *), void *idata) +{ + simpleerror(fd, 404, "Not Found", "The requested URL has no corresponding resource."); + return(0); +} + +static struct chandler i_notfound = { + .handle = donotfound, +}; + +static struct child s_notfound = { + .name = ".notfound", + .iface = &i_notfound, +}; +struct child *notfound = &s_notfound; diff --git a/src/dirplex/dirplex.c b/src/dirplex/dirplex.c index 162e4fd..baf24fa 100644 --- a/src/dirplex/dirplex.c +++ b/src/dirplex/dirplex.c @@ -70,8 +70,7 @@ static void handle(struct hthead *req, int fd, char *path, struct pattern *pat) simpleerror(fd, 500, "Configuration Error", "The server is erroneously configured. Handler %s was requested, but not declared.", pat->childnm); return; } - twd = NULL; - if((twd = ccf->path) != NULL) { + if((twd = ccf?ccf->path:NULL) != NULL) { if(!strcmp(twd, ".")) { twd = NULL; } else if(strncmp(path, twd, strlen(twd)) || (path[strlen(twd)] != '/')) { @@ -89,12 +88,25 @@ static void handle(struct hthead *req, int fd, char *path, struct pattern *pat) } } +static void handle404(struct hthead *req, int fd, char *path) +{ + struct child *ch; + struct config *ccf; + char *tmp; + + tmp = sstrdup(path); + ch = findchild(tmp, ".notfound", &ccf); + if(childhandle(ch, req, fd, chinit, ccf?ccf->path:NULL)) + simpleerror(fd, 500, "Server Error", "The request handler crashed."); + free(tmp); +} + 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."); + handle404(req, fd, path); return; } handle(req, fd, path, pat); @@ -186,7 +198,7 @@ static int checkentry(struct hthead *req, int fd, char *path, char *rest, char * int rv; if(*el == '.') { - simpleerror(fd, 404, "Not Found", "The requested URL has no corresponding resource."); + handle404(req, fd, sprintf3("%s/", path)); return(1); } if(!stat(sprintf3("%s/%s", path, el), &sb)) { @@ -206,7 +218,7 @@ static int checkentry(struct hthead *req, int fd, char *path, char *rest, char * free(newpath); return(1); } - simpleerror(fd, 404, "Not Found", "The requested URL has no corresponding resource."); + handle404(req, fd, sprintf3("%s/", path)); return(1); } if(!strchr(el, '.') && ((newpath = findfile(path, el, NULL)) != NULL)) { @@ -237,7 +249,7 @@ static int checkdir(struct hthead *req, int fd, char *path, char *rest) if(*rest == '/') rest++; replrest(req, rest); - if(childhandle(ch, req, fd, chinit, ccf->path)) + if(childhandle(ch, req, fd, chinit, ccf?ccf->path:NULL)) simpleerror(fd, 500, "Server Error", "The request handler crashed."); return(1); } @@ -273,7 +285,7 @@ static int checkpath(struct hthead *req, int fd, char *path, char *rest) goto out; } if(strchr(el, '/') || (!*el && *rest)) { - simpleerror(fd, 404, "Not Found", "The requested URL has no corresponding resource."); + handle404(req, fd, sprintf3("%s/", path)); rv = 1; goto out; } @@ -295,7 +307,7 @@ 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."); + handle404(req, fd, "."); } static void chldhandler(int sig) diff --git a/src/dirplex/dirplex.h b/src/dirplex/dirplex.h index 028a3d9..a025719 100644 --- a/src/dirplex/dirplex.h +++ b/src/dirplex/dirplex.h @@ -41,6 +41,7 @@ struct child *findchild(char *file, char *name, struct config **cf); struct pattern *findmatch(char *file, int trydefault, int dir); extern time_t now; +extern struct child *notfound; extern struct config *gconfig, *lconfig; #endif -- 2.11.0