Custom error messages and directory redirect patch for publicfile 0.52 Changes to httpd: If /errors/.html exists, display it instead of the default error response (i.e. "file does not exist"). Available error codes include 400, 404, 412, 417, and 501. All failed open() calls are treated as error 404 (this is desirable). If the given url is a directory, but the trailing slash is omitted, redirect the user to the same url, slash appended. Note that if the browser does not supply a desired hostname, the prior behavior will hold true, and error code 404 will be returned. Other servers may simply use the default hostname for redirection. Any browsers that do not supply a hostname have no virtual host support, and are not likely to be used. ari edelkind (08/16/2001) last modified 08/16/2001 diff -r -u publicfile-0.52/error.c publicfile-0.52+errors+redirect/error.c --- publicfile-0.52/error.c Tue Nov 9 02:23:46 1999 +++ publicfile-0.52+errors+redirect/error.c Tue Oct 16 22:22:19 2001 @@ -100,3 +100,11 @@ #else -14; #endif + +int error_isdir = +#ifdef EISDIR +EISDIR; +#else +-15; +#endif + diff -r -u publicfile-0.52/error.h publicfile-0.52+errors+redirect/error.h --- publicfile-0.52/error.h Tue Nov 9 02:23:46 1999 +++ publicfile-0.52+errors+redirect/error.h Tue Oct 16 22:22:41 2001 @@ -17,6 +17,7 @@ extern int error_perm; extern int error_acces; extern int error_nodevice; +extern int error_isdir; extern char *error_str(); extern int error_temp(); diff -r -u publicfile-0.52/error_str.c publicfile-0.52+errors+redirect/error_str.c --- publicfile-0.52/error_str.c Tue Nov 9 02:23:46 1999 +++ publicfile-0.52+errors+redirect/error_str.c Tue Oct 16 22:22:32 2001 @@ -21,6 +21,7 @@ X(error_perm,"permission denied") X(error_acces,"access denied") X(error_nodevice,"device not configured") + X(error_isdir,"is a directory") #ifdef ESRCH X(ESRCH,"no such process") #endif diff -r -u publicfile-0.52/file.c publicfile-0.52+errors+redirect/file.c --- publicfile-0.52/file.c Tue Nov 9 02:23:46 1999 +++ publicfile-0.52+errors+redirect/file.c Tue Oct 16 22:09:49 2001 @@ -66,6 +66,12 @@ return -1; } if (flagread) + if ((st.st_mode & S_IFMT) == S_IFDIR) { + log(fn,": ","is a directory",flagread); + close(fd); + errno = error_isdir; + return -1; + } if ((st.st_mode & S_IFMT) != S_IFREG) { log(fn,": ","not a regular file",flagread); close(fd); diff -r -u publicfile-0.52/httpd.c publicfile-0.52+errors+redirect/httpd.c --- publicfile-0.52/httpd.c Tue Nov 9 02:23:46 1999 +++ publicfile-0.52+errors+redirect/httpd.c Tue Oct 16 23:41:47 2001 @@ -15,6 +15,7 @@ #include "substdio.h" #include "error.h" #include "getln.h" +#include int safewrite(int fd,char *buf,int len) { @@ -75,8 +76,44 @@ out_puts("\r\n"); } +stralloc fn = {0}; +stralloc contenttype = {0}; + +extern void get(); void barf(char *code,char *message) { + + static char barfed = 0; + int codelen = str_len(code); + char cod[codelen]; + + if (!barfed) { + barfed++; + if (!stralloc_copys(&path, "errors/")) _exit(21); + memcpy (cod, code, codelen-1); + cod[codelen-1] = 0; + if (!stralloc_cats(&path, cod)) _exit(21); + if (!stralloc_cats(&path, ".html")) _exit(21); + + host.len = byte_chr(host.s,host.len,':'); + if (!host.len) { + if (!stralloc_copys(&host,"0")) _exit(21); + } + case_lowerb(host.s,host.len); + percent(&path); + + if (!stralloc_copys(&fn, "./")) _exit(21); + if (!stralloc_cat(&fn, &host)) _exit(21); + if (!stralloc_cats(&fn, "/")) _exit(21); + if (!stralloc_cat(&fn, &path)) _exit(21); + if (!stralloc_0(&fn)) _exit(21); + + if (close(open(fn.s, O_RDONLY)) != -1) { + get(code, message); + _exit(0); + } + } + if (protocolnum > 0) { tai_now(&now); header(code,message); @@ -100,15 +137,25 @@ _exit(0); } -stralloc fn = {0}; -stralloc contenttype = {0}; +void redirect(char *code, char *message) +{ + header (code, message); + out_puts("Location: "); + out_put(url.s, url.len); + out_puts("\r\n"); + out_puts("Content-Length: 0\r\n"); + out_puts("Content-Type: text/html\r\n"); + out_puts("Connection: close\r\n\r\n"); + out_flush(); + _exit(0); +} -void get(void) +void get(char *rcode, char *rcomment) { unsigned long length; int fd; int r; - + host.len = byte_chr(host.s,host.len,':'); if (!host.len) { if (protocolnum > 1) @@ -126,18 +173,33 @@ if (!stralloc_0(&fn)) _exit(21); fd = file_open(fn.s,&mtime,&length,1); - if (fd == -1) + if (fd == -1) { + /* if host is '0', we don't necessarily know what to return. */ + if (errno == error_isdir && (!(host.s[0] == '0' && host.len == 1))) { + if (!case_startb(url.s,url.len,"http://")) { + if (!stralloc_copys(&url, "http://")) _exit(21); + if (!stralloc_cat(&url, &host)) _exit(21); + if (path.s[0] != '/') if (!stralloc_cats(&url, "/")) _exit(21); + if (!stralloc_cat(&url, &path)) _exit(21); + } + if (!stralloc_cats(&url, "/")) _exit(21); + redirect("302 ", "Please add a trailing slash"); + } barf("404 ",error_str(errno)); + } if (protocolnum > 0) { tai_now(&now); if (!httpdate(&mtimestr,&mtime)) _exit(21); - if ((ims.len < mtimestr.len) || byte_diff(mtimestr.s,mtimestr.len,ims.s)) - header("200 ","OK"); - else { - header("304 ","OK"); - flagbody = 0; - } + if (!rcode) { + if ((ims.len < mtimestr.len) || byte_diff(mtimestr.s,mtimestr.len,ims.s)) + header("200 ","OK"); + else { + header("304 ","OK"); + flagbody = 0; + } + } else + header(rcode,rcomment); if (tai_less(&mtime,&now)) { tai_sub(&mtimeage,&now,&mtime); if (tai_approx(&mtimeage) >= 60.0) { @@ -309,6 +371,6 @@ } } - get(); + get(0, 0); } }