diff --git a/.github/workflows/linting.yml b/.github/workflows/linting.yml index cf09865..11d3225 100644 --- a/.github/workflows/linting.yml +++ b/.github/workflows/linting.yml @@ -2,7 +2,7 @@ name: Linting on: push: - branches: dev + branches: '**' pull_request: branches: dev, main diff --git a/README.md b/README.md index 1dda6d2..c5f19e9 100644 --- a/README.md +++ b/README.md @@ -8,15 +8,18 @@ No additional dependencies required. One-file bundled executable can be downloaded from the **Releases** section. +Tested on Windows 10/11, Ubuntu 22.04. + ## Usage ```txt -bphs [-h] [-p] [-d] [-l] +bphs [-h] [-p PORT] [-d PATH] [-l] [--cors] --h, --help show help message and exit --p, --port port to use [8080] --d, --dir directory to serve [current directory] --l, --listing enable directory listing +-h, --help show help message and exit +-p PORT, --port PORT port to use [8080] +-d PATH, --dir PATH directory to serve [current directory] +-l, --listing enable directory listing +--cors enable CORS headers ``` [1]: https://github.com/python/cpython/blob/3.12/Lib/http/server.py diff --git a/VERSION b/VERSION index 3eefcb9..9084fa2 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -1.0.0 +1.1.0 diff --git a/src/main.py b/src/main.py index 955b5d8..a5db42f 100644 --- a/src/main.py +++ b/src/main.py @@ -32,9 +32,16 @@ class BasicHTTPRequestHandler(SimpleHTTPRequestHandler): def __init__(self, *handler_args, **handler_kwargs) -> None: self.dir_listing = handler_kwargs.pop('dir_listing', False) + self.enable_cors = handler_kwargs.pop('enable_cors', False) super().__init__(*handler_args, **handler_kwargs) self.follow_symlinks = False + def end_headers(self): + """ Allow requests from any origin """ + if self.enable_cors: + self.send_header('Access-Control-Allow-Origin', '*') + super().end_headers() + # https://en.wikipedia.org/wiki/List_of_Unicode_characters#Control_codes _control_char_table = str.maketrans({c: fr'\x{c:02x}' for c in itertools.chain(range(0x20), range(0x7f, 0xa0))}) @@ -55,7 +62,7 @@ def list_directory(self, path: str | os.PathLike[str]) -> BytesIO | None: return super().list_directory(path) -def basic_http_server(port: int, public_dir: Path, dir_listing: bool) -> None: +def basic_http_server(port: int, public_dir: Path, dir_listing: bool, cors: bool) -> None: """ Starts a basic HTTP server """ if not public_dir.exists() or not public_dir.is_dir(): logging.error("Directory \"%s\" doesn't exist", public_dir) @@ -64,7 +71,8 @@ def basic_http_server(port: int, public_dir: Path, dir_listing: bool) -> None: logging.info("Initializing Basic HTTP Server") try: httpd = ThreadingBasicServer(("", port), partial( - BasicHTTPRequestHandler, directory=public_dir, dir_listing=dir_listing)) + BasicHTTPRequestHandler, directory=public_dir, + dir_listing=dir_listing, enable_cors=cors)) logging.info("Available on port %s", port) httpd.serve_forever() @@ -79,14 +87,16 @@ def parse_arguments() -> argparse.Namespace: formatter_class=CustomHelpFormatter ) - parser.add_argument("-p", "--port", metavar="", + parser.add_argument("-p", "--port", default=8080, type=int, help="port to use [8080]") - parser.add_argument("-d", "--dir", metavar="", + parser.add_argument("-d", "--dir", metavar="PATH", default=Path(os.getcwd()), type=Path, help="directory to serve [current directory]") parser.add_argument("-l", "--listing", action="store_true", help="enable directory listing") + parser.add_argument("--cors", action="store_true", + help="enable CORS headers") return parser.parse_args() @@ -94,6 +104,6 @@ def parse_arguments() -> argparse.Namespace: args = parse_arguments() try: - basic_http_server(args.port, args.dir, args.listing) + basic_http_server(args.port, args.dir, args.listing, args.cors) except KeyboardInterrupt: logging.info("Basic HTTP Server stopped")