14
14
15
15
def get_folder_based_http_request_handler (
16
16
folder : Path ,
17
+ default_file : Path = None ,
17
18
) -> type [SimpleHTTPRequestHandler ]:
18
19
"""
19
20
Returns a FolderBasedHTTPRequestHandler with the specified directory.
@@ -36,6 +37,16 @@ def end_headers(self):
36
37
self .send_header ("Cross-Origin-Resource-Policy" , "cross-origin" )
37
38
self .send_header ("Cache-Control" , "no-cache, must-revalidate" )
38
39
SimpleHTTPRequestHandler .end_headers (self )
40
+
41
+ def do_GET (self ):
42
+ # intercept accesses to nonexistent files; replace them with the default file
43
+ # this is to service SPA use cases (see Github Issue #132)
44
+ if default_file :
45
+ path = Path (self .translate_path (self .path ))
46
+ if not path .exists ():
47
+ self .path = f'/{ default_file } '
48
+
49
+ return super ().do_GET ()
39
50
40
51
return FolderBasedHTTPRequestHandler
41
52
@@ -58,7 +69,7 @@ def split_path_and_filename(path: Path) -> tuple[Path, str]:
58
69
return abs_path , ""
59
70
60
71
61
- def start_server (path : Path , show : bool , port : int ):
72
+ def start_server (path : Path , show : bool , port : int , default_file : Path = None ):
62
73
"""
63
74
Creates a local server to run the app on the path and port specified.
64
75
@@ -76,7 +87,7 @@ def start_server(path: Path, show: bool, port: int):
76
87
socketserver .TCPServer .allow_reuse_address = True
77
88
78
89
app_folder , filename = split_path_and_filename (path )
79
- CustomHTTPRequestHandler = get_folder_based_http_request_handler (app_folder )
90
+ CustomHTTPRequestHandler = get_folder_based_http_request_handler (app_folder , default_file = default_file )
80
91
81
92
# Start the server within a context manager to make sure we clean up after
82
93
with socketserver .TCPServer (("" , port ), CustomHTTPRequestHandler ) as httpd :
@@ -110,6 +121,7 @@ def run(
110
121
),
111
122
view : bool = typer .Option (True , help = "Open the app in web browser." ),
112
123
port : int = typer .Option (8000 , help = "The port that the app will run on." ),
124
+ default_file : Path = typer .Option (None , help = "A default file to serve when a nonexistent file is accessed." ),
113
125
):
114
126
"""
115
127
Creates a local server to run the app on the path and port specified.
@@ -120,7 +132,7 @@ def run(
120
132
raise cli .Abort (f"Error: Path { str (path )} does not exist." , style = "red" )
121
133
122
134
try :
123
- start_server (path , view , port )
135
+ start_server (path , view , port , default_file = default_file )
124
136
except OSError as e :
125
137
if e .errno == 48 :
126
138
console .print (
0 commit comments