dirplex: Made the 404 response indirectible and reusable.
authorFredrik Tolf <fredrik@dolda2000.com>
Fri, 28 Jan 2011 03:10:11 +0000 (04:10 +0100)
committerFredrik Tolf <fredrik@dolda2000.com>
Fri, 28 Jan 2011 03:13:03 +0000 (04:13 +0100)
doc/dirplex.doc
src/dirplex/conf.c
src/dirplex/dirplex.c
src/dirplex/dirplex.h

index 7e9ab38..d41c1ad 100644 (file)
@@ -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.
 
 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
 
 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.
 
 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
 -------------
 
 CONFIGURATION
 -------------
 
@@ -245,8 +246,29 @@ following actions are recognized:
        by a *fchild* stanza. This action exists mostly for
        convenience.
 
        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
 --------
 
 EXAMPLES
 --------
index b90163a..03d5477 100644 (file)
@@ -30,6 +30,7 @@
 #include <utils.h>
 #include <log.h>
 #include <cf.h>
 #include <utils.h>
 #include <log.h>
 #include <cf.h>
+#include <resp.h>
 
 #include "dirplex.h"
 
 
 #include "dirplex.h"
 
@@ -332,6 +333,8 @@ struct child *findchild(char *file, char *name, struct config **cf)
     struct config **cfs;
     struct child *ch;
     
     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) {
     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);
        }
     }
            return(ch);
        }
     }
+    if(!strcmp(name, ".notfound"))
+       return(notfound);
     return(NULL);
 }
 
     return(NULL);
 }
 
@@ -398,3 +403,19 @@ struct pattern *findmatch(char *file, int trydefault, int dir)
        return(findmatch(file, 1, dir));
     return(NULL);
 }
        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;
index 162e4fd..baf24fa 100644 (file)
@@ -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;
        }
            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)] != '/')) {
            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) {
 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);
        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 == '.') {
     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)) {
        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);
        }
            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)) {
        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(*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);
     }
            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)) {
        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;
     }
        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))
 {
     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)
 }
 
 static void chldhandler(int sig)
index 028a3d9..a025719 100644 (file)
@@ -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;
 struct pattern *findmatch(char *file, int trydefault, int dir);
 
 extern time_t now;
+extern struct child *notfound;
 extern struct config *gconfig, *lconfig;
 
 #endif
 extern struct config *gconfig, *lconfig;
 
 #endif