123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102 |
- #!/usr/bin/env python
- # Based on http/server.py from Python
- from argparse import ArgumentParser
- import contextlib
- from http.server import SimpleHTTPRequestHandler
- from http.server import ThreadingHTTPServer
- import os
- import socket
- class MyHTTPRequestHandler(SimpleHTTPRequestHandler):
- extensions_map = {
- ".manifest": "text/cache-manifest",
- ".html": "text/html",
- ".png": "image/png",
- ".jpg": "image/jpg",
- ".svg": "image/svg+xml",
- ".css": "text/css",
- ".js": "application/x-javascript",
- ".wasm": "application/wasm",
- "": "application/octet-stream",
- }
- def __init__(self, *args, maps=None, **kwargs):
- self.maps = maps or []
- SimpleHTTPRequestHandler.__init__(self, *args, **kwargs)
- def end_headers(self):
- self.send_my_headers()
- SimpleHTTPRequestHandler.end_headers(self)
- def send_my_headers(self):
- self.send_header("Cache-Control", "no-cache, no-store, must-revalidate")
- self.send_header("Pragma", "no-cache")
- self.send_header("Expires", "0")
- def translate_path(self, path):
- for map_path, map_prefix in self.maps:
- if path.startswith(map_prefix):
- res = os.path.join(map_path, path.removeprefix(map_prefix).lstrip("/"))
- break
- else:
- res = super().translate_path(path)
- return res
- def serve_forever(port: int, ServerClass):
- handler = MyHTTPRequestHandler
- addr = ("0.0.0.0", port)
- with ServerClass(addr, handler) as httpd:
- host, port = httpd.socket.getsockname()[:2]
- url_host = f"[{host}]" if ":" in host else host
- print(f"Serving HTTP on {host} port {port} (http://{url_host}:{port}/) ...")
- try:
- httpd.serve_forever()
- except KeyboardInterrupt:
- print("\nKeyboard interrupt received, exiting.")
- return 0
- def main():
- parser = ArgumentParser(allow_abbrev=False)
- parser.add_argument("port", nargs="?", type=int, default=8080)
- parser.add_argument("-d", dest="directory", type=str, default=None)
- parser.add_argument("--map", dest="maps", nargs="+", type=str, help="Mappings, used as e.g. \"$HOME/projects/SDL:/sdl\"")
- args = parser.parse_args()
- maps = []
- for m in args.maps:
- try:
- path, uri = m.split(":", 1)
- except ValueError:
- parser.error(f"Invalid mapping: \"{m}\"")
- maps.append((path, uri))
- class DualStackServer(ThreadingHTTPServer):
- def server_bind(self):
- # suppress exception when protocol is IPv4
- with contextlib.suppress(Exception):
- self.socket.setsockopt(socket.IPPROTO_IPV6, socket.IPV6_V6ONLY, 0)
- return super().server_bind()
- def finish_request(self, request, client_address):
- self.RequestHandlerClass(
- request,
- client_address,
- self,
- directory=args.directory,
- maps=maps,
- )
- return serve_forever(
- port=args.port,
- ServerClass=DualStackServer,
- )
- if __name__ == "__main__":
- raise SystemExit(main())
|