# aqserv, a proof of concept server for Aquarius # Copyright 2020 Hannu Hartikainen. AGPLv3. import os import os.path import socketserver import urllib.parse HOST = "0.0.0.0" PORT = 1970 MAX_PACKET_LENGTH = 508 CWD = os.getcwd() # monkey-patch aquarius:// support in urljoin :shrug: urllib.parse.uses_relative.append("aquarius") urllib.parse.uses_netloc.append("aquarius") class AquariusHandler(socketserver.BaseRequestHandler): def handle(self): req, socket = self.request url = urllib.parse.urlparse(req.strip()) if url.scheme != b"aquarius": content = b"59 unsupported url\r\n" else: req_path = url.path.lstrip(b"/").decode("utf-8") path = os.path.join(CWD, req_path) if os.path.commonpath([CWD, path]) != CWD: # avoid escapes like ../ content = b"59 bad request path\r\n" else: if os.path.isdir(path): path = os.path.join(path, "index.gemini") if os.path.exists(path): content = b"20 text/gemini\r\n" with open(path, 'rb') as f: content += f.read() else: content = b"51 not found\r\n" packets = [content[i:i+MAX_PACKET_LENGTH] for i in range(0, len(content), MAX_PACKET_LENGTH)] print(f"{content[0:2].decode('utf-8')} {self.client_address[0]} {req.strip().decode('utf-8')} - {len(packets)} packets") for packet in packets: socket.sendto(packet, self.client_address) if __name__ == "__main__": with socketserver.UDPServer((HOST, PORT), AquariusHandler) as server: server.serve_forever()