shithub: paste

Download patch

ref: cf032667921f9b25f5b6f0b7ade743087dc64e5c
parent: c02f95fb0bb11858e16869d4f09fa5153aee7e34
author: Alex Musolino <alex@musolino.id.au>
date: Tue Jul 22 10:18:34 EDT 2025

paste.c: implement url encoding/decoding

--- a/bin/paste.c
+++ b/bin/paste.c
@@ -16,6 +16,96 @@
 	return c;
 }
 
+static char hex[] = "0123456789abcdef";
+static char Hex[] = "0123456789ABCDEF";
+
+static int
+hexdigit(int c)
+{
+	char *p;
+
+	if(c > 0){
+		if((p = strchr(Hex, c)) != 0)
+			return p - Hex;
+		if((p = strchr(hex, c)) != 0)
+			return p - hex;
+	}
+	return -1;
+}
+
+static char*
+urldecode(char *dst, int len, char *src)
+{
+	char c;
+	char *p;
+
+	p = dst;
+	while((c = *src++) != 0){
+		if(len < 2)
+			return nil;
+		if(c == '%'){
+			int c1, c2, x1, x2;
+
+			if((c1 = *src++) == 0)
+				break;
+			if((x1 = hexdigit(c1)) < 0){
+				src--;
+				*p++ = c1;
+				len--;
+				continue;
+			}
+			if((c2 = *src++) == 0)
+				break;
+			if((x2 = hexdigit(c2)) < 0){
+				if(len < 3)
+					return nil;
+				src--;
+				*p++ = c;
+				*p++ = c1;
+				len -= 2;
+				continue;
+			}
+			c = x1<<4 | x2;
+		} else if(c == '+')
+			c = ' ';
+		*p++ = c;
+		len--;
+	}
+	*p = 0;
+	return dst;
+}
+
+static char*
+urlencode(char *dst, int len, char *src)
+{
+	char c;
+	char *p;
+
+	p = dst;
+	while((c = *src++) != 0){
+		if(len < 2)
+			return nil;
+		len--;
+		if(c>0 && strchr("/$-_@.!*'(),", c)
+		|| 'a'<=c && c<='z'
+		|| 'A'<=c && c<='Z'
+		|| '0'<=c && c<='9')
+			*p++ = c;
+		else if(c == ' ')
+			*p++ = '+';
+		else {
+			*p++ = '%';
+			if(len < 3)
+				return nil;
+			len -= 2;
+			*p++ = Hex[c>>4];
+			*p++ = Hex[c&15];
+		}
+	}
+	*p = 0;
+	return dst;
+}
+
 static void
 error(int code, char *text)
 {
@@ -51,9 +141,14 @@
 static void
 permredirect(char *location)
 {
-	fprint(1, "Status: 301 Moved Permanently\r\n");
-	fprint(1, "Location: %s\r\n", location);
-	fprint(1, "\r\n");
+	char buf[1024];
+
+	if(urlencode(buf, sizeof(buf), location) != nil){
+		fprint(1, "Status: 301 Moved Permanently\r\n");
+		fprint(1, "Location: %s\r\n", buf);
+		fprint(1, "\r\n");
+	}else
+		error500();
 	exits(0);
 }
 
@@ -60,9 +155,14 @@
 static void
 postredirect(char *location)
 {
-	fprint(1, "Status: 303 See Other\r\n");
-	fprint(1, "Location: %s\r\n", location);
-	fprint(1, "\r\n");
+	char buf[1024];
+
+	if(urlencode(buf, sizeof(buf), location) != nil){
+		fprint(1, "Status: 303 See Other\r\n");
+		fprint(1, "Location: %s\r\n", buf);
+		fprint(1, "\r\n");
+	}else
+		error500();
 	exits(0);
 }
 
@@ -501,6 +601,7 @@
 static void
 dirindex(int fd)
 {
+	char url[1024];
 	long n;
 	Dir *d, *dirs;
 
@@ -519,7 +620,10 @@
 
 	d = dirs;
 	while(n-- > 0){
-			fprint(1, "<a href=\"%s\">%s</a><br>\n", d->name, d->name);
+			if(urlencode(url, sizeof(url), d->name) != nil)
+				fprint(1, "<a href=\"%s\">%s</a><br>\n", url, d->name);
+			else
+				fprint(1, "%s<br>\n", d->name);
 			d++;
 	}
 	free(dirs);
@@ -544,6 +648,8 @@
 	}
 
 	fprint(1, "Status: 200 OK\r\n");
+	if(strcmp(d->name, "text") == 0)
+		fprint(1, "Content-type: text/plain; charset=utf-8\r\n");
 	fprint(1, "Content-length: %lld\r\n", d->length);
 	fprint(1, "\r\n");
 
@@ -572,6 +678,7 @@
 void
 main(int argc, char **argv)
 {
+	char buf[1024];
 	char *requri;
 
 	ARGBEGIN{
@@ -585,6 +692,11 @@
 		fprint(2, "CGI variable REQUEST_URI not set!\n");
 		error500();
 		exits("missing REQUEST_URI");
+	}
+	requri = urldecode(buf, sizeof(buf), requri);
+	if(requri == nil){
+		error500();
+		exits(0);
 	}
 	if(strcmp(requri, "/") == 0)
 		permredirect("/index.html");
--