diff options
| author | 3gg <3gg@shellblade.net> | 2025-12-27 12:03:39 -0800 |
|---|---|---|
| committer | 3gg <3gg@shellblade.net> | 2025-12-27 12:03:39 -0800 |
| commit | 5a079a2d114f96d4847d1ee305d5b7c16eeec50e (patch) | |
| tree | 8926ab44f168acf787d8e19608857b3af0f82758 /contrib/SDL-3.2.8/test/emscripten/server.py | |
Initial commit
Diffstat (limited to 'contrib/SDL-3.2.8/test/emscripten/server.py')
| -rwxr-xr-x | contrib/SDL-3.2.8/test/emscripten/server.py | 102 |
1 files changed, 102 insertions, 0 deletions
diff --git a/contrib/SDL-3.2.8/test/emscripten/server.py b/contrib/SDL-3.2.8/test/emscripten/server.py new file mode 100755 index 0000000..103d164 --- /dev/null +++ b/contrib/SDL-3.2.8/test/emscripten/server.py | |||
| @@ -0,0 +1,102 @@ | |||
| 1 | #!/usr/bin/env python | ||
| 2 | |||
| 3 | # Based on http/server.py from Python | ||
| 4 | |||
| 5 | from argparse import ArgumentParser | ||
| 6 | import contextlib | ||
| 7 | from http.server import SimpleHTTPRequestHandler | ||
| 8 | from http.server import ThreadingHTTPServer | ||
| 9 | import os | ||
| 10 | import socket | ||
| 11 | |||
| 12 | |||
| 13 | class MyHTTPRequestHandler(SimpleHTTPRequestHandler): | ||
| 14 | extensions_map = { | ||
| 15 | ".manifest": "text/cache-manifest", | ||
| 16 | ".html": "text/html", | ||
| 17 | ".png": "image/png", | ||
| 18 | ".jpg": "image/jpg", | ||
| 19 | ".svg": "image/svg+xml", | ||
| 20 | ".css": "text/css", | ||
| 21 | ".js": "application/x-javascript", | ||
| 22 | ".wasm": "application/wasm", | ||
| 23 | "": "application/octet-stream", | ||
| 24 | } | ||
| 25 | |||
| 26 | def __init__(self, *args, maps=None, **kwargs): | ||
| 27 | self.maps = maps or [] | ||
| 28 | SimpleHTTPRequestHandler.__init__(self, *args, **kwargs) | ||
| 29 | |||
| 30 | def end_headers(self): | ||
| 31 | self.send_my_headers() | ||
| 32 | SimpleHTTPRequestHandler.end_headers(self) | ||
| 33 | |||
| 34 | def send_my_headers(self): | ||
| 35 | self.send_header("Cache-Control", "no-cache, no-store, must-revalidate") | ||
| 36 | self.send_header("Pragma", "no-cache") | ||
| 37 | self.send_header("Expires", "0") | ||
| 38 | |||
| 39 | def translate_path(self, path): | ||
| 40 | for map_path, map_prefix in self.maps: | ||
| 41 | if path.startswith(map_prefix): | ||
| 42 | res = os.path.join(map_path, path.removeprefix(map_prefix).lstrip("/")) | ||
| 43 | break | ||
| 44 | else: | ||
| 45 | res = super().translate_path(path) | ||
| 46 | return res | ||
| 47 | |||
| 48 | |||
| 49 | def serve_forever(port: int, ServerClass): | ||
| 50 | handler = MyHTTPRequestHandler | ||
| 51 | |||
| 52 | addr = ("0.0.0.0", port) | ||
| 53 | with ServerClass(addr, handler) as httpd: | ||
| 54 | host, port = httpd.socket.getsockname()[:2] | ||
| 55 | url_host = f"[{host}]" if ":" in host else host | ||
| 56 | print(f"Serving HTTP on {host} port {port} (http://{url_host}:{port}/) ...") | ||
| 57 | try: | ||
| 58 | httpd.serve_forever() | ||
| 59 | except KeyboardInterrupt: | ||
| 60 | print("\nKeyboard interrupt received, exiting.") | ||
| 61 | return 0 | ||
| 62 | |||
| 63 | |||
| 64 | def main(): | ||
| 65 | parser = ArgumentParser(allow_abbrev=False) | ||
| 66 | parser.add_argument("port", nargs="?", type=int, default=8080) | ||
| 67 | parser.add_argument("-d", dest="directory", type=str, default=None) | ||
| 68 | parser.add_argument("--map", dest="maps", nargs="+", type=str, help="Mappings, used as e.g. \"$HOME/projects/SDL:/sdl\"") | ||
| 69 | args = parser.parse_args() | ||
| 70 | |||
| 71 | maps = [] | ||
| 72 | for m in args.maps: | ||
| 73 | try: | ||
| 74 | path, uri = m.split(":", 1) | ||
| 75 | except ValueError: | ||
| 76 | parser.error(f"Invalid mapping: \"{m}\"") | ||
| 77 | maps.append((path, uri)) | ||
| 78 | |||
| 79 | class DualStackServer(ThreadingHTTPServer): | ||
| 80 | def server_bind(self): | ||
| 81 | # suppress exception when protocol is IPv4 | ||
| 82 | with contextlib.suppress(Exception): | ||
| 83 | self.socket.setsockopt(socket.IPPROTO_IPV6, socket.IPV6_V6ONLY, 0) | ||
| 84 | return super().server_bind() | ||
| 85 | |||
| 86 | def finish_request(self, request, client_address): | ||
| 87 | self.RequestHandlerClass( | ||
| 88 | request, | ||
| 89 | client_address, | ||
| 90 | self, | ||
| 91 | directory=args.directory, | ||
| 92 | maps=maps, | ||
| 93 | ) | ||
| 94 | |||
| 95 | return serve_forever( | ||
| 96 | port=args.port, | ||
| 97 | ServerClass=DualStackServer, | ||
| 98 | ) | ||
| 99 | |||
| 100 | |||
| 101 | if __name__ == "__main__": | ||
| 102 | raise SystemExit(main()) | ||
