馃悕馃悕馃悕
at dev 124 lines 3.7 kB view raw
1import socket 2import ssl 3import os 4from pathlib import Path 5from urllib.parse import unquote, urlparse 6 7#from lib import log 8 9# TODO make it upgrade to https instead of just fucking throwing exceptions 10 11HOST = "0.0.0.0" 12PORT = 1313 13BASE_DIR = Path("./webui").resolve() 14USE_SSL = False 15 16ROUTES = { 17 "/": "content/main.html", 18} 19 20MIME_TYPES = { 21 ".html": "text/html", 22 ".css": "text/css", 23 ".js": "text/javascript", 24 ".wgsl": "text/wgsl", 25 ".png": "image/png", 26 ".orb": "text/x-orb" 27} 28 29SSL_CERT = "/home/ponder/ponder/certs/cert.pem" 30SSL_KEY = "/home/ponder/ponder/certs/key.pem" 31 32def guess_mime_type(path): 33 return MIME_TYPES.get(Path(path).suffix, "application/octet-stream") 34 35def build_response(status_code, body=b"", content_type="text/plain"): 36 reason = { 37 200: "OK", 38 400: "Bad Request", 39 404: "Not Found", 40 405: "Method Not Allowed", 41 500: "Internal Server Error" 42 }.get(status_code, "Unexpected Status") 43 return ( 44 f"HTTP/1.1 {status_code} {reason}\r\n" 45 f"Content-Type: {content_type}\r\n" 46 f"Content-Length: {len(body)}\r\n" 47 f"Connection: close\r\n" 48 f"\r\n" 49 ).encode() + body 50 51def route(req_path): 52 if req_path == "/": 53 return "content/main.html" 54 if any(req_path.endswith(x) for x in [".html", ".png"]): 55 return f"content/{req_path}" 56 if any(req_path.endswith(x) for x in [".wgsl"]): 57 return f"content/wgsl/{req_path}" 58 if any(req_path.endswith(x) for x in [".orb"]): 59 return f"content/orb/{req_path}" 60 if req_path.endswith(".js"): 61 return f"js/{req_path}" 62 return req_path[1:] 63 64def handle_request(request_data): 65 try: 66 lines = request_data.decode().split("\r\n") 67 if not lines: 68 return build_response(400, b"Malformed request") 69 70 method, raw_path, *_ = lines[0].split() 71 if method != "GET": 72 return build_response(405, b"Method Not Allowed") 73 74 req_path = urlparse(unquote(raw_path)).path 75 76 norm_path = os.path.normpath(req_path) 77 78 if ".." in norm_path: 79 return build_response(400, b"Fuck You") 80 81 file_path = route(norm_path) 82 83 if not file_path: 84 return build_response(404, b"Not Found") 85 86 full_path = BASE_DIR / file_path 87 if not full_path.exists(): 88 return build_response(404, b"File not found") 89 90 with open(full_path, "rb") as f: 91 body = f.read() 92 return build_response(200, body, guess_mime_type(file_path)) 93 94 except Exception as e: 95 return build_response(500, f"Server error: {e}".encode()) 96 97def main(): 98 ssl_ctx = ssl.SSLContext(ssl.PROTOCOL_TLS_SERVER) 99 ssl_ctx.load_cert_chain(certfile=SSL_CERT, keyfile=SSL_KEY) 100 101 with socket.socket(socket.AF_INET, socket.SOCK_STREAM) as server: 102 server.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1) 103 server.bind((HOST, PORT)) 104 server.listen() 105 print(f"Serving HTTPS on {HOST}:{PORT}") 106 while True: 107 try: 108 conn, addr = server.accept() 109 if USE_SSL: 110 with ssl_ctx.wrap_socket(conn, server_side=True) as ssl_conn: 111 request = ssl_conn.recv(4096) 112 response = handle_request(request) 113 ssl_conn.sendall(response) 114 else: 115 request = conn.recv(4096) 116 response = handle_request(request) 117 conn.sendall(response) 118 except KeyboardInterrupt: 119 raise 120 except: 121 break 122 123if __name__ == "__main__": 124 main()