SDL
102 строки · 3.1 Кб
1#!/usr/bin/env python
2
3# Based on http/server.py from Python
4
5from argparse import ArgumentParser6import contextlib7from http.server import SimpleHTTPRequestHandler8from http.server import ThreadingHTTPServer9import os10import socket11
12
13class MyHTTPRequestHandler(SimpleHTTPRequestHandler):14extensions_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
26def __init__(self, *args, maps=None, **kwargs):27self.maps = maps or []28SimpleHTTPRequestHandler.__init__(self, *args, **kwargs)29
30def end_headers(self):31self.send_my_headers()32SimpleHTTPRequestHandler.end_headers(self)33
34def send_my_headers(self):35self.send_header("Cache-Control", "no-cache, no-store, must-revalidate")36self.send_header("Pragma", "no-cache")37self.send_header("Expires", "0")38
39def translate_path(self, path):40for map_path, map_prefix in self.maps:41if path.startswith(map_prefix):42res = os.path.join(map_path, path.removeprefix(map_prefix).lstrip("/"))43break44else:45res = super().translate_path(path)46return res47
48
49def serve_forever(port: int, ServerClass):50handler = MyHTTPRequestHandler51
52addr = ("0.0.0.0", port)53with ServerClass(addr, handler) as httpd:54host, port = httpd.socket.getsockname()[:2]55url_host = f"[{host}]" if ":" in host else host56print(f"Serving HTTP on {host} port {port} (http://{url_host}:{port}/) ...")57try:58httpd.serve_forever()59except KeyboardInterrupt:60print("\nKeyboard interrupt received, exiting.")61return 062
63
64def main():65parser = ArgumentParser(allow_abbrev=False)66parser.add_argument("port", nargs="?", type=int, default=8080)67parser.add_argument("-d", dest="directory", type=str, default=None)68parser.add_argument("--map", dest="maps", nargs="+", type=str, help="Mappings, used as e.g. \"$HOME/projects/SDL:/sdl\"")69args = parser.parse_args()70
71maps = []72for m in args.maps:73try:74path, uri = m.split(":", 1)75except ValueError:76parser.error(f"Invalid mapping: \"{m}\"")77maps.append((path, uri))78
79class DualStackServer(ThreadingHTTPServer):80def server_bind(self):81# suppress exception when protocol is IPv482with contextlib.suppress(Exception):83self.socket.setsockopt(socket.IPPROTO_IPV6, socket.IPV6_V6ONLY, 0)84return super().server_bind()85
86def finish_request(self, request, client_address):87self.RequestHandlerClass(88request,89client_address,90self,91directory=args.directory,92maps=maps,93)94
95return serve_forever(96port=args.port,97ServerClass=DualStackServer,98)99
100
101if __name__ == "__main__":102raise SystemExit(main())103