serve.py 2.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566
  1. #!/usr/bin/env python3
  2. import argparse
  3. import contextlib
  4. import os
  5. import socket
  6. import subprocess
  7. import sys
  8. from http.server import HTTPServer, SimpleHTTPRequestHandler, test # type: ignore
  9. from pathlib import Path
  10. # See cpython GH-17851 and GH-17864.
  11. class DualStackServer(HTTPServer):
  12. def server_bind(self):
  13. # Suppress exception when protocol is IPv4.
  14. with contextlib.suppress(Exception):
  15. self.socket.setsockopt(socket.IPPROTO_IPV6, socket.IPV6_V6ONLY, 0)
  16. return super().server_bind()
  17. class CORSRequestHandler(SimpleHTTPRequestHandler):
  18. def end_headers(self):
  19. self.send_header("Cross-Origin-Opener-Policy", "same-origin")
  20. self.send_header("Cross-Origin-Embedder-Policy", "require-corp")
  21. self.send_header("Access-Control-Allow-Origin", "*")
  22. super().end_headers()
  23. def shell_open(url):
  24. if sys.platform == "win32":
  25. os.startfile(url)
  26. else:
  27. opener = "open" if sys.platform == "darwin" else "xdg-open"
  28. subprocess.call([opener, url])
  29. def serve(root, port, run_browser):
  30. os.chdir(root)
  31. if run_browser:
  32. # Open the served page in the user's default browser.
  33. print("Opening the served URL in the default browser (use `--no-browser` or `-n` to disable this).")
  34. shell_open(f"http://127.0.0.1:{port}")
  35. test(CORSRequestHandler, DualStackServer, port=port)
  36. if __name__ == "__main__":
  37. parser = argparse.ArgumentParser()
  38. parser.add_argument("-p", "--port", help="port to listen on", default=8060, type=int)
  39. parser.add_argument(
  40. "-r", "--root", help="path to serve as root (relative to `platform/web/`)", default="../../bin", type=Path
  41. )
  42. browser_parser = parser.add_mutually_exclusive_group(required=False)
  43. browser_parser.add_argument(
  44. "-n", "--no-browser", help="don't open default web browser automatically", dest="browser", action="store_false"
  45. )
  46. parser.set_defaults(browser=True)
  47. args = parser.parse_args()
  48. # Change to the directory where the script is located,
  49. # so that the script can be run from any location.
  50. os.chdir(Path(__file__).resolve().parent)
  51. serve(args.root, args.port, args.browser)