ref: f552e6b0b45aad9f5ca62cef708dc0a591e88b1b
parent: 96a392dc08e4cfc4e23c74d061f168e55dfcea01
author: grobe0ba <grobe0ba@tcp80.org>
date: Mon Aug 1 16:10:12 EDT 2022
Allow redirecting error pages, and changing site server based on hostname.
--- /dev/null
+++ b/README.md
@@ -1,0 +1,49 @@
+# To run the shithub software:
+
+```/rc/bin/service/tcp80```:
+```
+#!/bin/rc
+
+bind /usr/web /mnt/static
+exec /bin/tcp80 -r /sys/lib/tcp80 >>[2]/sys/log/httpd/log
+```
+
+```/rc/bin/service/tcp443```:
+```
+#!/bin/rc
+
+bind /usr/web /mnt/static
+exec tlssrv -c/sys/lib/tls/cert.pem -lhttpd -r`{cat $3/remote} /bin/tcp80 -r /sys/lib/tcp80 >>[2]/sys/log/httpd/log
+```
+
+```/lib/namespace.httpd```:
+```
+bind /mnt/static /usr/web/static
+```
+
+It is possible to redirect error pages by passing ```-e error```, like
+```tcp80 -e 404 -e 403```. This will send a ```301 Moved Permanently``` to
+e.g. ```/404``` or ```/403```. It will also append the path to it:
+Attempting to access ```http://server/nopage.html``` would redirect to
+```http://server/404/nopage.html```.
+
+
+It is also possible to define a set of hostnames to change the bind mounts for
+```/usr/web``` based on the Host header. To use this feature, you pass
+```-h file``` to tcp80. The format of the file is the same as that for execfs,
+a regex for the hostname, any number of tabs, with a path to be mounted over
+```/usr/web```.
+
+```
+server1.domain.com /usr/webroot/server1
+aardvark.different.org /usr/webroot/aardvark
+```
+This does not affect execfs scripts directly, although the bind mounts happen
+prior to their execution. If you are using the same scripts for multiple
+hostnames, you can check the environment using ```ns``` to find out what is
+mounted over ```/usr/web```. If you are using shithub, or anything similar which
+hooks on ```/index.html```, it will still take precedence over any static files.
+
+You can work around this by not hooking ```/index.html```, instead hook something
+like ```/shithub.html``` and then redirect to it.
+
--- a/README.shithub.md
+++ /dev/null
@@ -1,22 +1,0 @@
-# To run the shithub software:
-
-```/rc/bin/service/tcp80```:
-```
-#!/bin/rc
-
-bind /usr/web /mnt/static
-exec /bin/tcp80 -r /sys/lib/tcp80 >>[2]/sys/log/httpd/log
-```
-
-```/rc/bin/service/tcp443```:
-```
-#!/bin/rc
-
-bind /usr/web /mnt/static
-exec tlssrv -c/sys/lib/tls/cert.pem -lhttpd -r`{cat $3/remote} /bin/tcp80 -r /sys/lib/tcp80 >>[2]/sys/log/httpd/log
-```
-
-```/lib/namespace.httpd```:
-```
-bind /mnt/static /usr/web/static
-```
--- a/tcp80.c
+++ b/tcp80.c
@@ -27,6 +27,8 @@
char method[64];
char location[1024];
+int redir_errno[64];
+
Pair *header;
int naheader;
Pair aheader[64];
@@ -402,6 +404,7 @@
static char buf[8192], tmp[1024];
char *p, *s, *status;
int i, n, fd, badmeth, nobody, noindex, noslash;
+ int istatus = 0;
Pair *h;
Dir *d;
@@ -409,8 +412,27 @@
badmeth = !nobody && cistrcmp(method, "GET");
if(badmeth){
werrstr("%s method unsupported", method);
- status = "405 Method Not Allowed";
+ istatus = 405;
+ status = "405 Method Not Allowed";
Error:
+ for(i = 0; i < nelem(redir_errno); i++){
+ if(istatus == redir_errno[i]){
+ status = "301 Moved Permanently";
+ respond(status);
+ headers(buf, d);
+
+ strncpy(buf, "/404", sizeof(buf));
+ strncat(buf, location, sizeof(buf));
+
+ h = findhdr(nil, "Host");
+ p = strchr(location, '?');
+ s = fullurl(h ? h->val : nil, urlenc(tmp, buf, sizeof(tmp)), "/",
+ p ? p + 1 : nil);
+ print("Location: %s\r\nContent-Length: %d\r\n\r\n%*s", s, n, n,
+ buf);
+ goto Out;
+ }
+ }
if(!nobody)
n = snprint(buf, sizeof(buf),
"<html><head><title>%s</title></head>\n"
@@ -452,16 +474,19 @@
if((fd = open(buf, OREAD)) < 0){
rerrstr(buf, sizeof(buf));
if(strstr(buf, "permission denied")){
- status = "403 Forbidden";
+ istatus = 403;
+ status = "403 Forbidden";
goto Error;
}
- status = "404 Not found";
+ istatus = 404;
+ status = "404 Not found";
goto Error;
}
if((d = dirfstat(fd)) == nil){
close(fd);
- status = "500 Internal Server Error";
+ istatus = 500;
+ status = "500 Internal Server Error";
goto Error;
}
@@ -713,14 +738,22 @@
main(int argc, char **argv)
{
static char buf[1024], line[1024];
+ 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
@@ -742,6 +775,18 @@
respond("400 Bad Request");
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)
@@ -764,7 +809,7 @@
fakedir.uid = "none";
fakedir.gid = "none";
fakedir.muid = "none";
- respond("200");
+ respond("200 OK");
headers(loc, &fakedir);
dispatchrule(c);
free(c);
@@ -774,8 +819,10 @@
if(!trusted){
if(addns("none", "/lib/namespace.httpd") < 0)
return;
+
if(bind("/usr/web", "/", MREPL) < 0)
return;
+
if(rfork(RFNOMNT) < 0)
return;
}