Atlas - server.py
Home / ext / SDL / test / emscripten Lines: 2 | Size: 3206 bytes [Download] [Show on GitHub] [Search similar files] [Raw] [Raw (proxy)][FILE BEGIN]1#!/usr/bin/env python 2 3# Based on http/server.py from Python 4 5from argparse import ArgumentParser 6import contextlib 7from http.server import SimpleHTTPRequestHandler 8from http.server import ThreadingHTTPServer 9import os 10import socket 11 12 13class 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 49def 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 64def 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 101if __name__ == "__main__": 102 raise SystemExit(main()) 103[FILE END](C) 2025 0x4248 (C) 2025 4248 Media and 4248 Systems, All part of 0x4248 See LICENCE files for more information. Not all files are by 0x4248 always check Licencing.