馃悕馃悕馃悕
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()