shithub: tcp80

Download patch

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;
 	}