ref: db15b1a63659f3f731f15bbabce7d4257e98ff3d
#include <u.h>
#include <libc.h>
#include <ctype.h>
#include <auth.h>
#include <bio.h>
#include <regexp.h>
typedef struct Pair Pair;
typedef struct Ctype Ctype;
typedef struct HResponse HResponse;
struct Pair {
Pair *next;
char key[64];
char val[256];
char *att;
};
struct Ctype {
char *suffix;
char *type;
};
int trusted;
char remote[128];
char method[64];
char location[1024];
int redir_errno[64];
Pair *header;
int naheader;
Pair aheader[64];
// Expanded with information from
// https://developer.mozilla.org/en-US/docs/Web/HTTP/Basics_of_HTTP/MIME_types/Common_types
Ctype ctypemap[] = {
".htm", "text/html;charset=utf-8",
".html", "text/html;charset=utf-8",
".txt", "text/plain;charset=utf-8",
".md", "text/markdown;charset=utf-8",
".css", "text/css;charset=utf-8",
".aac", "audio/aac",
".avif", "image/avif",
".avi", "video/x-msvideo",
".azw", "application/vnd.amazon.ebook",
".bin", "application/octet-stream",
".bmp", "image/bmp",
".bz", "application/x-bzip",
".bz2", "application/x-bzip2",
".cda", "application/x-cdf",
".csh", "application/x-csh",
".csv", "text/csv",
".doc", "application/msword",
".docx", "application/vnd.openxmlformats-officedocument.wordprocessingml.document",
".eot", "application/vnd.ms-fontobject",
".epub", "application/epub+zip",
".gz", "application/gzip",
".gif", "image/gif",
".ico", "image/vnd.microsoft.icon",
".ics", "text/calendar",
".jar", "application/java-archive",
".jpeg", "image/jpeg",
".jpg", "image/jpeg",
".js", "text/javascript",
".json", "application/json",
".jsonld", "application/ld+json",
".mid", "audio/midi",
".midi", "audio/midi",
".mjs", "text/javascript",
".mp3", "audio/mpeg",
".mp4", "video/mp4",
".mpeg", "video/mpeg",
".odp", "application/vnd.oasis.opendocument.presentation",
".ods", "application/vnd.oasis.opendocument.spreadsheet",
".odt", "application/vnd.oasis.opendocument.text",
".oga", "audio/ogg",
".ogg", "audio/ogg",
".ogv", "video/ogg",
".ogx", "application/ogg",
".opus", "audio/opus",
".otf", "font/otf",
".png", "image/png",
".pdf", "application/pdf",
".ppt", "application/vnd.ms-powerpoint",
".pptx", "application/vnd.openxmlformats-officedocument.presentationml.presentation",
".rar", "application/vnd.rar",
".rtf", "application/rtf",
".sh", "application/x-sh",
".svg", "image/svg+xml",
".tar", "application/x-tar",
".tif", "image/tiff",
".tiff", "image/tiff",
".ts", "video/mp2t",
".ttf", "font/ttf",
".vsd", "application/vnd.visio",
".wav", "audio/wav",
".weba", "audio/webm",
".webm", "video/webm",
".webp", "image/webp",
".woff", "font/woff",
".woff2", "font/woff2",
".xhtml", "application/xhtml+xml",
".xls", "application/vnd.ms-excel",
".xlsx", "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet",
".xml", "application/xml",
".xul", "application/vnd.mozilla.xul+xml",
".zip", "application/zip",
".3gp", "video/3gpp",
".3g2", "video/3gpp2",
".7z", "application/x-7z-compressed",
};
struct HResponse {
int code;
const char *message;
};
// RFC 2616 responses
HResponse responsemap[] = {
100, "Continue",
101, "Switching Protocols",
200, "OK",
201, "Created",
202, "Accepted",
203, "Non-Authoritative Information",
204, "No Content",
205, "Reset Content",
206, "Partial Content",
300, "Multiple Choices",
301, "Moved Permanently",
302, "Found",
303, "See Other",
304, "Not Modified",
305, "Use Proxy",
307, "Temporary Request",
400, "Bad Request",
401, "Unauthorized",
402, "Payment Required",
403, "Forbidden",
404, "Not Found",
405, "Method Not Allowed",
406, "Not Acceptable",
407, "Proxy Authentication Required",
408, "Request Time-out",
409, "Conflict",
410, "Gone",
411, "Length Required",
412, "Precondition Failed",
413, "Request Entity Too Large",
414, "Request-URI Too Large",
415, "Unsupported Media Type",
416, "Requested range not satisfiable",
417, "Expectation Failed",
500, "Internal Server Error",
501, "Not Implemented",
502, "Bad Gateway",
503, "Service Unavailable",
504, "Gateway Time-out",
505, "HTTP Version not supported",
};
void createenv(char *env, char *data);
int dircmp(Dir *a, Dir *b);
int dispatch(void);
void dispatchrule(char *cmd);
Pair *findhdr(Pair *h, char *key);
char *findrule(char *rulesfile, char *path);
char *fullurl(char *host, char *path, char *name, char *query);
void getresponse(char *dst, int bufsz, int code);
long hdate(char *s);
void headers(char *path, Dir *d);
int isleap(int year);
void main(int argc, char **argv);
char *nstrcpy(char *d, char *s, int n);
int parsequery(void);
int redirerr(int status, Dir *d);
void respond(char *status);
char *token(char *s, char *delim, char **pe);
char *urldec(char *d, char *s, int n);
char *urlenc(char *d, char *s, int n);
void
getresponse(char *dst, int bufsz, int code)
{
int i;
for(i = 0; i < nelem(responsemap); i++){
if(responsemap[i].code == code){
seprint(dst, dst + bufsz, "%d %s", responsemap[i].code,
responsemap[i].message);
return;
}
}
getresponse(dst, bufsz, 500);
}
char *
findrule(char *rulesfile, char *path)
{
Biobuf *bio;
char *s, *p, *d, *r;
Reprog *re;
Resub m[16];
if((bio = Bopen(rulesfile, OREAD)) == nil)
sysfatal("open: %r");
while(s = Brdstr(bio, '\n', 1)){
p = s;
while(strchr("\t ", *p)) p++;
d = nil;
if(*p != '#'){
if(d = strchr(p, '\t'))
*d++ = 0;
else if(d = strchr(p, ' '))
*d++ = 0;
}
if(d == nil){
free(s);
continue;
}
while(strchr("\t ", *d)) d++;
if(re = regcomp(p)){
memset(m, 0, sizeof(m));
if(regexec(re, path, m, nelem(m))){
r = malloc(1024);
regsub(d, r, 1024, m, nelem(m));
free(s);
Bterm(bio);
return r;
}
}
free(s);
}
Bterm(bio);
return nil;
}
void
createenv(char *env, char *data)
{
static char statbuf[32];
int fd;
char *path = "/env/";
int plen = strlen(path);
int elen = strlen(env);
int flen = plen + elen;
int dlen = strlen(data);
char *filename;
if((filename = malloc(plen + elen + 1)) == nil){
getresponse(statbuf, 32, 500);
respond(statbuf);
sysfatal("malloc");
}
nstrcpy(filename, path, flen);
strncat(filename, env, elen);
if((fd = create(filename, OWRITE, 0644)) < 0){
getresponse(statbuf, 32, 500);
respond(statbuf);
sysfatal("create");
}
if(write(fd, data, dlen) != dlen){
getresponse(statbuf, 32, 500);
respond(statbuf);
sysfatal("write");
}
close(fd);
free(filename);
return;
}
void
dispatchrule(char *cmd)
{
static char statbuf[32];
if(rfork(RFPROC | RFNOWAIT | RFFDG | RFREND | RFENVG) == 0){
if(cistrcmp(cmd, "cgi") == 0){
char *query = strchr(location, '?');
if(query != nil){
query[0] = 0;
query++;
}
createenv("GATEWAY_INTERFACE", "CGI/1.1");
createenv("QUERY_STRING", query ? query : "");
createenv("REMOTE_ADDR", remote);
createenv("REQUEST_METHOD", method);
createenv("REQUEST_URI", location);
createenv("SCRIPT_NAME", location);
Pair *host = findhdr(nil, "Host");
if(host != nil){
createenv("SERVER_NAME", host->val);
}else{
createenv("SERVER_NAME", "localhost");
}
// This is a nasty lie. It could be any port, but we don't actually know
createenv("SERVER_PORT", "80");
createenv("SERVER_PROTOCOL", "HTTP");
createenv("SERVER_SOFTWARE", "tcp80");
chdir("/usr/web/bin");
const char* base = "/usr/web";
const int blen = strlen(base);
const int llen = strlen(location);
char *newloc = malloc(blen+llen+1);
nstrcpy(newloc, base, blen+llen+1);
strncat(newloc, location, blen+llen+1);
newloc[blen+llen] = 0;
execl("/bin/rc", "rc", "-c", newloc, nil);
getresponse(statbuf, 32, 500);
respond(statbuf);
sysfatal("exec");
}
execl("/bin/rc", "rc", "-c", cmd, nil);
getresponse(statbuf, 32, 500);
respond(statbuf);
sysfatal("exec");
}
exits(nil);
}
Pair *
findhdr(Pair *h, char *key)
{
if(h == nil)
h = header;
else
h = h->next;
for(; h; h = h->next)
if(cistrcmp(h->key, key) == 0)
break;
return h;
}
char *
nstrcpy(char *d, char *s, int n)
{
d[n - 1] = 0;
return strecpy(d, d + n, s);
}
char hex[] = "0123456789ABCDEF";
char *
urldec(char *d, char *s, int n)
{
int c, x;
char *r;
r = d;
x = 0;
while(n > 1 && (c = *s++)){
if(x){
char *p;
if((p = strchr(hex, toupper(c))) == nil)
continue;
*d <<= 4;
*d |= p - hex;
if(--x)
continue;
}else{
if(c == '%'){
x = 2;
continue;
}
*d = c;
}
d++;
n--;
}
*d = 0;
return r;
}
char *
urlenc(char *d, char *s, int n)
{
char *r;
int c;
r = d;
while(n > 1 && (c = *s++)){
if(isalnum(c) || strchr("$-_.+!*'(),", c) || strchr("/:;=@", c)){
*d++ = c;
n--;
}else{
if(n <= 3)
break;
*d++ = '%';
*d++ = hex[(c >> 4) & 15];
*d++ = hex[c & 15];
n -= 3;
}
}
*d = 0;
return r;
}
int
isleap(int year)
{
return year % 4 == 0 && (year % 100 != 0 || year % 400 == 0);
}
long
hdate(char *s)
{
int i;
Tm tm;
static int mday[2][12] = {
31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31,
31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31,
};
static char *wday[] = {
"Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday",
};
static char *mon[] = {
"Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec",
};
/* Sunday, */
for(i = 0; i < nelem(wday); i++){
if(cistrncmp(s, wday[i], strlen(wday[i])) == 0){
s += strlen(wday[i]);
break;
}
if(cistrncmp(s, wday[i], 3) == 0){
s += 3;
break;
}
}
if(*s == ',')
s++;
if(*s == ' ')
s++;
/* 25- */
if(!isdigit(s[0]) || !isdigit(s[1]) || (s[2] != '-' && s[2] != ' '))
return -1;
tm.mday = strtol(s, 0, 10);
s += 3;
/* Jan- */
for(i = 0; i < nelem(mon); i++)
if(cistrncmp(s, mon[i], 3) == 0){
tm.mon = i;
s += 3;
break;
}
if(i == nelem(mon))
return -1;
if(s[0] != '-' && s[0] != ' ')
return -1;
s++;
/* 2002 */
if(!isdigit(s[0]) || !isdigit(s[1]))
return -1;
tm.year = strtol(s, 0, 10);
s += 2;
if(isdigit(s[0]) && isdigit(s[1]))
s += 2;
else{
if(tm.year <= 68)
tm.year += 2000;
else
tm.year += 1900;
}
if(tm.mday == 0 || tm.mday > mday[isleap(tm.year)][tm.mon])
return -1;
tm.year -= 1900;
if(*s++ != ' ')
return -1;
if(!isdigit(s[0]) || !isdigit(s[1]) || s[2] != ':' || !isdigit(s[3]) || !isdigit(s[4]) ||
s[5] != ':' || !isdigit(s[6]) || !isdigit(s[7]) || s[8] != ' ')
return -1;
tm.hour = atoi(s);
tm.min = atoi(s + 3);
tm.sec = atoi(s + 6);
if(tm.hour >= 24 || tm.min >= 60 || tm.sec >= 60)
return -1;
s += 9;
if(cistrcmp(s, "GMT") != 0)
return -1;
nstrcpy(tm.zone, s, sizeof(tm.zone));
tm.yday = 0;
return tm2sec(&tm);
}
void
headers(char *path, Dir *d)
{
char buf[1024], *f[6];
int isdir;
Tm *tm;
if(tm = localtime(time(0))){
nstrcpy(buf, asctime(tm), sizeof(buf));
if(tokenize(buf, f, 6) == 6)
print("Date: %s, %.2d %s %s %s %s\r\n", f[0], tm->mday, f[1], f[5], f[3],
f[4]);
}
if(d && d->mtime != 0 && (tm = localtime(d->mtime))){
nstrcpy(buf, asctime(tm), sizeof(buf));
if(tokenize(buf, f, 6) == 6)
print("Last-Modified: %s, %.2d %s %s %s %s\r\n", f[0], tm->mday, f[1], f[5],
f[3], f[4]);
}else if(d && d->mtime == 0 && (tm = localtime(time(0)))){
nstrcpy(buf, asctime(tm), sizeof(buf));
if(tokenize(buf, f, 6) == 6)
print("Last-Modified: %s, %.2d %s %s %s %s\r\n", f[0], tm->mday, f[1], f[5],
f[3], f[4]);
}
isdir = d && (d->qid.type & QTDIR);
if(isdir){
print("Content-Type: text/html; charset=utf-8\r\n");
}else{
int i;
for(i = 0; i < nelem(ctypemap); i++){
int offset = strlen(path) - strlen(ctypemap[i].suffix);
if(offset <= 0)
break;
if(cistrcmp(path + offset, ctypemap[i].suffix) == 0){
print("Content-Type: %s\r\n", ctypemap[i].type);
break;
}
}
}
if(*path == '/')
print("Content-Location: %s%s\r\n", urlenc(buf, path, sizeof(buf)),
isdir ? "/" : "");
}
int
dircmp(Dir *a, Dir *b)
{
return strcmp(a->name, b->name);
}
char *
fullurl(char *host, char *path, char *name, char *query)
{
static char buf[1024];
snprint(buf, sizeof(buf), "%s%s%s%s%s%s", host ? "/" : "", host ? host : "",
path ? path : "/", name ? name : "", query ? "?" : "", query ? query : "");
return buf;
}
void
respond(char *status)
{
syslog(0, "tcp80", "%s %s %s %s", remote, method, location, status);
print("HTTP/1.1 %s\r\n", status);
}
int
redirerr(int status, Dir *d)
{
static char buf[8192], tmp[1024], statbuf[32];
int i;
for(i = 0; i < nelem(redir_errno); i++){
if(status == redir_errno[i]){
getresponse(statbuf, 32, 303);
respond(statbuf);
headers(buf, d);
snprint(buf, sizeof(buf), "/%d%s", status, location);
print("Location: %s\r\n\r\n", buf);
return 1;
}
}
return 0;
}
int
dispatch(void)
{
static char buf[8192], tmp[1024], statbuf[32];
char *p, *s;
int i, n, fd, badmeth, nobody, noindex, noslash;
int status = 0;
Pair *h;
Dir *d;
nobody = !cistrcmp(method, "HEAD");
badmeth = !nobody && cistrcmp(method, "GET");
if(badmeth){
werrstr("%s method unsupported", method);
status = 405;
Error:
if(redirerr(status, d))
goto Out;
getresponse(statbuf, 32, status);
if(!nobody)
n = snprint(buf, sizeof(buf),
"<html><head><title>%s</title></head>\n"
"<body><h1>%s</h1><pre>%r</pre></body></html>\n",
statbuf, statbuf);
else
n = 0;
respond(statbuf);
headers(".html", nil);
print("Content-Length: %d\r\n\r\n%*s", n, n, buf);
return -badmeth;
}
s = location;
if(cistrncmp(s, "http:", 5) == 0)
s += 5;
else if(cistrncmp(s, "https:", 6) == 0)
s += 6;
if(s[0] == '/' && s[1] == '/')
s = strchr(s + 2, '/');
if(s == nil || *s == 0)
s = "/";
nstrcpy(tmp, s, sizeof(tmp));
if(s = strchr(tmp, '#'))
*s = 0;
noindex = 0;
if(s = strchr(tmp, '?')){
*s++ = 0;
noindex = !cistrcmp(s, "noindex");
}
urldec(buf, tmp, sizeof(buf));
noslash = 1;
if(s = strrchr(buf, '/'))
if(s[1] == 0)
noslash = 0;
cleanname(buf);
if((fd = open(buf, OREAD)) < 0){
rerrstr(buf, sizeof(buf));
if(strstr(buf, "permission denied")){
status = 403;
goto Error;
}
status = 404;
goto Error;
}
if((d = dirfstat(fd)) == nil){
close(fd);
status = 500;
goto Error;
}
if(d->qid.type & QTDIR){
int fd2;
Dir *d2;
if(noslash){
getresponse(statbuf, 32, 301);
respond(statbuf);
headers(buf, d);
h = findhdr(nil, "Host");
p = strchr(location, '?');
s = fullurl(h ? h->val : nil, urlenc(tmp, buf, sizeof(tmp)), "/",
p ? p + 1 : nil);
if(!nobody)
n = snprint(buf, sizeof(buf),
"<html><head><title>%s</title></head>\n"
"<body><h1>%s</h1><pre>Moved to <a "
"href=\"%s\">%s</a></pre></body></html>\n",
statbuf, statbuf, s, s);
else
n = 0;
print("Location: %s\r\nContent-Length: %d\r\n\r\n%*s", s, n, n, buf);
goto Out;
}
if(!noindex){
snprint(tmp, sizeof(tmp), "%s/index.html", buf);
cleanname(tmp);
if((fd2 = open(tmp, OREAD)) >= 0){
if(d2 = dirfstat(fd2)){
if((d2->qid.type & QTDIR) == 0){
nstrcpy(buf, tmp, sizeof(buf));
close(fd);
fd = fd2;
free(d);
d = d2;
goto Filecont;
}
free(d2);
}
close(fd2);
}
}
getresponse(statbuf, 32, 200);
respond(statbuf);
headers(buf, d);
print("\r\n");
if(nobody)
goto Out;
print(
"<html><head><title>%s</title></head><body>"
"<pre>\n<a href=\"/%s\">/</a>",
buf, noindex ? "?noindex" : "");
for(p = buf + 1; *p; p = s + 1){
if(s = strchr(p, '/'))
*s = 0;
print("<a href=\"%s/%s\">%s</a>/", urlenc(tmp, buf, sizeof(tmp)),
noindex ? "?noindex" : "", p);
if(s == nil)
break;
*s = '/';
}
print("<hr>");
free(d);
d = nil;
if((n = dirreadall(fd, &d)) > 0){
qsort(d, n, sizeof d[0], (int (*)(void *, void *))dircmp);
for(i = 0; i < n; i++)
print("<a href=\"%s%s\">%s</a>%s\n",
urlenc(tmp, d[i].name, sizeof(tmp)),
(d[i].qid.type & QTDIR) ? (noindex ? "/?noindex" : "/") : "",
d[i].name, (d[i].qid.type & QTDIR) ? "/" : "");
free(d);
}
print("</pre></body></html>\n");
return 1;
}else{
vlong start, end;
Filecont:
h = findhdr(nil, "If-Modified-Since");
if(h && !nobody){
long t;
if((t = hdate(h->val)) != -1){
if(d->mtime <= t){
getresponse(statbuf, 32, 304);
respond(statbuf);
headers(buf, d);
print("\r\n");
goto Out;
}
}
}
h = findhdr(nil, "Range");
while(h){
if(findhdr(h, "Range"))
break;
if(s = strchr(h->val, '='))
s++;
else
s = h->val;
start = strtoll(s, &s, 10);
if(*s++ != '-')
break;
if(*s == 0)
end = d->length;
else
end = strtoll(s, &s, 10) + 1;
if(*s != 0 || (end <= start))
break;
getresponse(statbuf, 32, 206);
respond(statbuf);
print("Content-Range: bytes %lld-%lld/%lld\r\n", start, end - 1, d->length);
goto Content;
}
start = 0;
end = d->length;
getresponse(statbuf, 32, 200);
respond(statbuf);
Content:
headers(buf, d);
if(end > start){
print("Content-Length: %lld\r\n\r\n", end - start);
if(nobody)
goto Out;
while(start < end){
n = sizeof(buf);
if((end - start) < n)
n = end - start;
if((n = pread(fd, buf, n, start)) <= 0)
return -1;
if(write(1, buf, n) != n)
return -1;
start += n;
}
}else{
print("\r\n");
if(nobody)
goto Out;
while((n = read(fd, buf, sizeof(buf))) > 0)
if(write(1, buf, n) != n)
return -1;
return 1;
}
}
Out:
close(fd);
free(d);
return 0;
}
char *
token(char *s, char *delim, char **pe)
{
char *e;
int d;
d = 0;
while(*s == ' ' || *s == '\t') s++;
for(e = s; *e; e++){
if(*e == '(')
d++;
if(d > 0){
if(*e == ')')
d--;
s = e + 1;
continue;
}
if(strchr(delim, *e)){
*e++ = 0;
break;
}
}
if(pe)
*pe = e;
while(s < e && *s == ' ' || *s == '\t') s++;
while(--e >= s){
if(*e != ' ' && *e != '\t')
break;
*e = 0;
}
return s;
}
int
parsequery(void)
{
static char buf[1024], line[1024];
char *p, *e, *k, *x, *s;
int lineno, n;
Pair *h;
naheader = 0;
lineno = 0;
*line = 0;
p = buf;
e = buf + sizeof(buf);
while((n = read(0, p, e - p)) > 0){
p += n;
while((p > buf) && (e = memchr(buf, '\n', p - buf))){
if((e > buf) && (e[-1] == '\r'))
e[-1] = 0;
*e++ = 0;
if(*buf != ' ' && *buf != '\t' && *line){
if(lineno++ == 0){
nstrcpy(method, token(line, "\t ", &s), sizeof(method));
nstrcpy(location, token(s, "\t ", nil), sizeof(location));
}else{
if(lineno > 100)
return -1;
k = token(line, ":", &s);
while(*s){
if(naheader >= nelem(aheader))
return -1;
x = token(s, ",", &s);
h = aheader + naheader++;
nstrcpy(h->key, k, sizeof(h->key));
nstrcpy(h->val, x, sizeof(h->val));
if(x = strchr(h->val, ';')){
*x++ = 0;
x = token(x, ";", nil);
}
h->att = x;
h->next = header;
header = h;
}
}
}
nstrcpy(line, buf, sizeof(line));
p -= e - buf;
if(p > buf)
memmove(buf, e, p - buf);
if(*line == 0){
if(method[0] == 0)
return -1;
return 0;
}
}
e = buf + sizeof(buf);
}
return -1;
}
void
main(int argc, char **argv)
{
static char buf[1024], line[1024], statbuf[32];
Pair *host;
char *hosts;
char *r, *c;
int i = 0;
int n;
r = nil;
ARGBEGIN
{
case 'e':
redir_errno[i] = strtol(ARGF(), 0, 0);
i++;
break;
case 'r': r = ARGF(); break;
case 't': trusted++; break;
case 'h': hosts = ARGF(); break;
}
ARGEND
time(0);
if(argc){
int fd;
snprint(buf, sizeof(buf), "%s/remote", argv[argc - 1]);
if((fd = open(buf, OREAD)) >= 0){
if((n = read(fd, remote, sizeof(remote) - 1)) >= 0){
while(n > 0 && remote[n - 1] == '\n') n--;
remote[n] = 0;
}
close(fd);
}
}
if(remote[0] == 0)
strecpy(remote, remote + sizeof remote, "-");
if(parsequery() < 0){
getresponse(statbuf, 32, 400);
respond(statbuf);
return;
}
if(hosts){
host = findhdr(nil, "Host");
c = findrule(hosts, host->val);
if(c){
if(bind(c, "/mnt/web", MREPL) < 0)
return;
if(bind("/mnt/web", "/usr/web", MREPL) < 0)
return;
}
}
if(r){
char *loc;
if(addns("none", "/lib/namespace.httpd") < 0)
return;
if(cistrcmp(location, "/") == 0){
loc = "/index.html";
}else{
loc = location;
}
c = findrule(r, loc);
if(c){
Dir fakedir = {0};
fakedir.mode = 0644;
fakedir.name = "unrealfile";
fakedir.uid = "none";
fakedir.gid = "none";
fakedir.muid = "none";
if(cistrcmp(method, "GET") != 0)
if(redirerr(405, &fakedir))
goto rOut;
if(cistrcmp(c, "cgi") != 0){
getresponse(statbuf, 32, 200);
respond(statbuf);
headers(loc, &fakedir);
}
dispatchrule(c);
rOut:
free(c);
return;
}
}
if(!trusted){
if(addns("none", "/lib/namespace.httpd") < 0)
return;
if(bind("/usr/web", "/", MREPL) < 0)
return;
if(rfork(RFNOMNT) < 0)
return;
}
dispatch();
return;
}