Last active
January 31, 2025 18:18
-
-
Save a5ync/7e76bfc95f87273c83c273c5de9fe990 to your computer and use it in GitHub Desktop.
Static file server with automatic decompression for *.html.gz files.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| import http.server | |
| import os | |
| import gzip | |
| import argparse | |
| # Default Constants | |
| DEFAULT_PORT = 8123 | |
| DEFAULT_BASE_DIR = "./snapshot" | |
| DEFAULT_ROUTE = "/snapshot-fast" | |
| # Allow overriding via command-line arguments | |
| parser = argparse.ArgumentParser( | |
| description="Start a simple HTTP server with gzip handling.", add_help=True | |
| ) | |
| parser.add_argument( | |
| "--port", | |
| type=int, | |
| help=f"Port number (default: {DEFAULT_PORT})", | |
| default=DEFAULT_PORT, | |
| ) | |
| parser.add_argument( | |
| "--base-dir", | |
| type=str, | |
| help=f"Base directory for serving files (default: {DEFAULT_BASE_DIR})", | |
| default=DEFAULT_BASE_DIR, | |
| ) | |
| parser.add_argument( | |
| "--route", | |
| type=str, | |
| help=f"Route prefix (default: {DEFAULT_ROUTE})", | |
| default=DEFAULT_ROUTE, | |
| ) | |
| args = parser.parse_args() | |
| PORT = args.port | |
| BASE_DIR = args.base_dir.rstrip("/") # Ensure no trailing slash | |
| ROUTE = args.route | |
| print( | |
| f"Starting server on port {PORT} with base directory {BASE_DIR} and route {ROUTE}" | |
| ) | |
| class CustomHandler(http.server.SimpleHTTPRequestHandler): | |
| def translate_path(self, path): | |
| """Remap /route to base_dir and enforce directory restrictions.""" | |
| if not path.startswith(ROUTE): | |
| self.send_error(403, "Access denied") | |
| return None | |
| if path.startswith(ROUTE): | |
| path = path[len(ROUTE) :] | |
| # Convert to absolute path | |
| full_path = os.path.abspath(os.path.join(BASE_DIR, path.lstrip("/"))) | |
| realpath = os.path.realpath(full_path) | |
| # Ensure the requested path is within ROOT_DIRECTORY | |
| if not realpath.startswith(BASE_DIR): | |
| self.send_error(403, "Access denied") | |
| return None | |
| return full_path | |
| def do_GET(self): | |
| """Intercept .gz files, decompress, and serve as HTML securely.""" | |
| file_path = self.translate_path(self.path) | |
| if file_path is None: | |
| return # Access was denied in translate_path | |
| if self.path.endswith(".gz") and os.path.exists(file_path): | |
| self.send_response(200) | |
| self.send_header("Content-Type", "text/html") | |
| self.send_header( | |
| "Content-Disposition", "inline" | |
| ) # Force display in browser | |
| self.end_headers() | |
| # Read and decompress .gz file | |
| with gzip.open(file_path, "rb") as f: | |
| self.wfile.write(f.read()) # Send decompressed content | |
| return | |
| # Default handling for other files | |
| super().do_GET() | |
| # PORT = 8123 | |
| if __name__ == "__main__": | |
| server_address = ("", PORT) | |
| httpd = http.server.HTTPServer(server_address, CustomHandler) | |
| print(f"Serving HTTP on port {PORT} (http://0.0.0.0:{PORT}{ROUTE}/...)") | |
| httpd.serve_forever() |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment