shithub: tcp80

Download patch

ref: 594e3fdedb7a4d4fc78641199d764cefd4b43a2e
parent: 782b239c64d827cd98cfd9f1deb3cdbf1d818d75
author: grobe0ba <grobe0ba@tcp80.org>
date: Mon Aug 1 16:10:12 EDT 2022

integrate phil9s tcp80x

--- a/tcp80.c
+++ b/tcp80.c
@@ -2,6 +2,8 @@
 #include <libc.h>
 #include <ctype.h>
 #include <auth.h>
+#include <bio.h>
+#include <regexp.h>
 
 typedef struct Pair Pair;
 typedef struct Ctype Ctype;
@@ -39,6 +41,53 @@
 	".css", "text/css;charset=utf-8",
 };
 
+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 dispatchrule(char *cmd) {
+  if (rfork(RFPROC | RFNOWAIT | RFFDG | RFREND) == 0) {
+    execl("/bin/rc", "rc", "-c", cmd, nil);
+    exits("exec");
+  }
+  exits(nil);
+}
+
 Pair*
 findhdr(Pair *h, char *key)
 {
@@ -260,7 +309,7 @@
 	static char buf[1024];
 
 	snprint(buf, sizeof(buf), "%s%s%s%s%s%s",
-		host ? "http://" : "", host ? host : "", 
+		host ? "http://" : "", host ? host : "",
 		path ? path : "/", name ? name : "",
 		query ? "?" : "", query ? query : "");
 	return buf;
@@ -289,7 +338,7 @@
 		status = "405 Method Not Allowed";
 Error:
 		if(!nobody)
-			n = snprint(buf, sizeof(buf), 
+			n = snprint(buf, sizeof(buf),
 			"<html><head><title>%s</title></head>\n"
 			"<body><h1>%s</h1><pre>%r</pre></body></html>\n",
 			status, status);
@@ -355,7 +404,7 @@
 			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), 
+				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",
 				status, status, s, s);
@@ -391,12 +440,12 @@
 			goto Out;
 
 		print(	"<html><head><title>%s</title></head><body>"
-			"<pre>\n<a href=\"/%s\">/</a>", 
+			"<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>/", 
+			print(	"<a href=\"%s/%s\">%s</a>/",
 				urlenc(tmp, buf, sizeof(tmp)), noindex ? "?noindex" : "", p);
 			if(s == nil)
 				break;
@@ -409,7 +458,7 @@
 		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", 
+				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,
@@ -528,18 +577,74 @@
 	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];
-	char *p, *e, *k, *x, *s;
+	char *p, *e, *k, *x, *s, *r, *c;
 	int lineno, n;
 	Pair *h;
 
+	r = nil;
 	ARGBEGIN {
-	case 't':
-		trusted++;
-		break;
+	case 'r':
+          r = ARGF();
+          break;
+        case 't':
+          trusted++;
+          break;
 	} ARGEND
 
 	time(0);
@@ -557,6 +662,25 @@
 	}
 	if(remote[0] == 0)
 		strcpy(remote, "-");
+
+	if(parsequery() < 0){
+      respond("400 Bad Request");
+      return;
+    }
+
+	if(r){
+          c = findrule(r, location);
+		  if(c){
+			if(cistrcmp(method, "GET") != 0){
+                    respond("405 Method Not Allowed");
+                    return;
+                }
+                dispatchrule(c);
+                free(c);
+                return;
+            }
+    }
+
 	if(!trusted){
 		if(addns("none", "/lib/namespace.httpd") < 0)
 			return;
@@ -565,6 +689,7 @@
 		if(rfork(RFNOMNT) < 0)
 			return;
 	}
+
 	naheader = 0;
 	lineno = 0;
 	*line = 0;