commit 8b89e4cff4d264ea216968e16180dbb31195f679
parent cc63ab3d1f6bbed6ea4bae99d2327a961b8807e1
Author: Willy Goiffon <dev@z3bra.org>
Date:   Thu, 15 Oct 2020 15:50:07 +0200
Add URL shortening capabilities
Diffstat:
| M | bitreich-httpd.c | | | 148 | ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++----------------- | 
1 file changed, 116 insertions(+), 32 deletions(-)
diff --git a/bitreich-httpd.c b/bitreich-httpd.c
@@ -3,6 +3,7 @@
  * by 20h
  */
 
+#include <errno.h>
 #include <unistd.h>
 #include <stdio.h>
 #include <stdlib.h>
@@ -14,6 +15,12 @@
 #include <sys/socket.h>
 #include <netdb.h>
 
+#define WWWBASE "/var/cache/shorturl"
+#define CHARSET "abcdefghijklmnopqrstuvwxyz"
+#define NAMELEN 3
+
+char *host = "url.short";
+
 void *
 xmalloc(size_t size)
 {
@@ -27,6 +34,20 @@ xmalloc(size_t size)
 	return p;
 }
 
+char *
+randomname(int len)
+{
+	int i;
+	static char out[NAMELEN + 1];
+	static char charset[] = CHARSET;
+
+	srand((unsigned long)&i);
+	for (i = 0; i < len; i++)
+		out[i] = charset[rand() % (int)(sizeof(charset) -1)];
+
+	return out;
+}
+
 void
 print404(void)
 {
@@ -35,6 +56,13 @@ print404(void)
 }
 
 void
+print500(void)
+{
+	printf("HTTP/1.1 500 You Broke The Web\r\n");
+	printf("\r\n");
+}
+
+void
 printheaders(char *ctype)
 {
 	time_t t;
@@ -42,11 +70,7 @@ printheaders(char *ctype)
 	t = time(NULL);
 	if (t > 0)
 		printf("Date: %s", asctime(gmtime(&t)));
-	printf("X-Future: Gopher ftw!\r\n");
 	printf("Content-Type: %s\r\n", ctype);
-	printf("X-Irritate: Be irritated.\r\n");
-	printf("X-Use-Gopher: gopher://bitreich.org\r\n");
-	printf("If-By-Whiskey: Terrorist\r\n");
 	printf("Server: bitreich-httpd/2.0\r\n");
 	printf("Host: bitreich.org\r\n");
 	printf("Connection: close\r\n");
@@ -95,16 +119,80 @@ servefile(char *path, char *ctype, int sock)
 }
 
 int
+redirect(char *path)
+{
+	struct stat st;
+	char *location;
+	size_t bufsiz = BUFSIZ;
+	int len, fd;
+
+	fd = open(path, O_RDONLY);
+	if (fd < 0) {
+		print404();
+		return 1;
+	}
+
+	if (fstat(fd, &st) >= 0)
+		if ((bufsiz = st.st_blksize) < BUFSIZ)
+			bufsiz = BUFSIZ;
+
+	location = xmalloc(bufsiz);
+	len = read(fd, location, bufsiz);
+
+	location[len - 1] = '\0';
+
+	printf("HTTP/1.1 307 Moved Temporarily\r\n");
+	printheaders("text/html");
+	printf("Location: %s\r\n", location);
+	printf("\r\n");
+
+	free(location);
+
+	return 0;
+}
+
+int
+saveurl(char *wwwbase, char *location)
+{
+	int fd;
+	char *path, *name, *url;
+
+	if (!(name = randomname(NAMELEN)))
+		return 1;
+
+	asprintf(&path, "%s/%s", wwwbase, name);
+	asprintf(&url, "http://%s/%s", host, name);
+
+	if ((fd = open(path, O_WRONLY|O_CREAT, 0644)) < 0)
+		return 1;
+
+	write(fd, location, strlen(location));
+	write(fd, "\n", 1);
+	close(fd);
+
+	printf("HTTP/1.1 200 OK\r\n");
+	printheaders("text/plain");
+	printf("Content-Length: %ld\r\n", strlen(url));
+	printf("\r\n");
+	fflush(stdout);
+	printf("%s", url);
+
+	free(path);
+	free(url);
+
+	return 0;
+}
+
+int
 main(int argc, char *argv[])
 {
-	char *wwwbase, *wwwindex, request[512], *ctype, *path,
+	char *wwwbase, request[512], *path, *url,
 	     clienth[NI_MAXHOST], clientp[NI_MAXSERV];
 	int rlen;
 	struct sockaddr_storage clt;
 	socklen_t cltlen = sizeof(clt);
 
-	wwwbase = "/bitreich/www";
-	wwwindex = "index.html";
+	wwwbase = WWWBASE;
 
 	if (!getpeername(0, (struct sockaddr *)&clt, &cltlen)) {
 		if (getnameinfo((struct sockaddr *)&clt, cltlen, clienth,
@@ -124,31 +212,27 @@ main(int argc, char *argv[])
 
 	request[rlen] = '\0';
 
-	if (strncmp(request, "GET ", 4))
-		return 1;
-
-	if (strstr(request, "s/bitreich.sh")) {
-		asprintf(&path, "%s/s/bitreich.sh", wwwbase);
-		ctype = "text/plain";
-	} else if (strstr(request, "favicon.gif")) {
-		asprintf(&path, "%s/s/favicon.gif", wwwbase);
-		ctype = "image/gif";
-	} else if (strstr(request, "dickbutt")) {
-		asprintf(&path,
-			"/home/annna/bin/annna-say -c \"#bitreich-tv\" \"%s:%s cake hater appeared.\"",
-			clienth, clientp);
-		system(path);
-		free(path);
-		asprintf(&path, "%s/s/dickbutt.jpg", wwwbase);
-		ctype = "image/jpeg";
-	} else {
-		asprintf(&path, "%s/%s", wwwbase, wwwindex);
-		ctype = "text/html";
+	if (!strncmp(request, "PUT ", 4)) {
+		url = strstr(request, "\r\n\r\n") + 4;
+		if (!url || !strlen(url) || saveurl(wwwbase, url)) {
+			perror(url);
+			print500();
+			return 1;
+		}
+		return 0;
+	} else if (!strncmp(request, "GET ", 4)) {
+		if (!strncmp(request + 4, "/ ", 2) || strstr(request, "/../")) {
+			print404();
+			return 1;
+		} else {
+			char *p = strstr(request + 4, " ");
+			*p = '\0';
+			asprintf(&path, "%s%s", wwwbase, request + 4);
+			rlen = redirect(path);
+			free(path);
+			return rlen;
+		}
 	}
 
-	rlen = servefile(path, ctype, 1);
-	free(path);
-
-	return rlen;
+	return -1;
 }
-