summary refs log tree commit diff
path: root/helld.py
diff options
context:
space:
mode:
Diffstat (limited to 'helld.py')
-rw-r--r--helld.py93
1 files changed, 93 insertions, 0 deletions
diff --git a/helld.py b/helld.py
new file mode 100644
index 0000000..68d24ac
--- /dev/null
+++ b/helld.py
@@ -0,0 +1,93 @@
+# Hellish Gemini daemon, in both behaviour and code quality.
+#
+# openssl req -newkey rsa:4096 -nodes -keyout key.pem -nodes -x509 -out cert.pem
+# python3 helld.py cert.pem key.pem
+
+import socket
+import threading
+import socketserver
+import ssl
+import sys
+import time
+import random
+from urllib.parse import urlparse
+
+handlers = []
+
+def register(addr):
+	def dec(fn):
+		handlers.append((addr, fn))
+	return dec
+
+@register('/normal')
+def normal(s, _):
+	s.sendall(b'20 text/gemini\r\n# hello\nnothing strange going on here\n')
+
+@register('/noclose')
+def noclose(s, rh):
+	s.sendall(b'20 text/gemini\r\nquick before the connection is killed i need to tell you tha')
+	close(rh.request)
+
+@register('/sleep1')
+def sleep1(s, rh):
+	s.sendall(b'20 text/gemini\r\nabout to take a nap')
+	time.sleep(120)
+
+@register('/sleep2')
+def sleep(s, rh):
+	time.sleep(120)
+	s.sendall(b'20 text/gemini\r\ntook a nap')
+
+@register('/128mb')
+def lotsofdata(s, rh):
+	s.sendall(b'20 text/gemini\r\n')
+	for n in range(128):
+		s.sendall(b'lol ' * (1024 * 1024 // 4))
+
+@register('/4mb')
+def sensibleamountofdata(s, rh):
+	buffer = b'20 text/gemini\r\n' + b'lol ' * (1024 * 1024)
+	buffer = buffer[:4*1024*1024]
+	s.sendall(buffer)
+
+@register('/over4mb')
+def nonsensibleamountofdata(s, rh):
+	buffer = b'20 text/gemini\r\n' + b'lol ' * (1024 * 1024)
+	buffer = buffer[:4*1024*1024+1]
+	s.sendall(buffer)
+
+@register('/loop')
+def loop(s, rh):
+	s.sendall(f'30 /loop/{random.randint(0, 2**32)}\r\n'.encode('utf-8'))
+
+@register('/index')
+def index(s, rh):
+	s.sendall(b'20 text/gemini\r\n')
+	for addr, _ in handlers:
+		s.sendall(f'=> {addr}\n'.encode('utf-8'))
+
+@register('')
+def toindex(s, rh):
+	s.sendall(b'30 /index\r\n')
+
+class ThreadedTCPRequestHandler(socketserver.BaseRequestHandler):
+	def handle(self):
+		s = context.wrap_socket(self.request, server_side=True)
+		req = s.read().decode('utf-8').rstrip('\r\n')
+		print(req)
+		req = urlparse(req)
+		for addr, fn in handlers:
+			if req.path.startswith(addr):
+				fn(s, self)
+				break
+
+class ThreadedTCPServer(socketserver.ThreadingMixIn, socketserver.TCPServer):
+	pass
+
+if __name__ == "__main__":
+	context = ssl.SSLContext(ssl.PROTOCOL_TLS_SERVER)
+	context.load_cert_chain(sys.argv[1], sys.argv[2])
+
+	ThreadedTCPServer.allow_reuse_address = True
+	server = ThreadedTCPServer(('0.0.0.0', 1965), ThreadedTCPRequestHandler)
+	server.serve_forever()