@@ -10,6 +10,7 @@ use std::{
1010 fs:: File ,
1111 hash:: { Hash , Hasher } ,
1212 io:: Read ,
13+ path:: PathBuf ,
1314} ;
1415
1516/// The default value for the cache control header.
@@ -27,6 +28,8 @@ const BROTLI_ENCODING: &str = "br";
2728const PATH_INFO_HEADER : & str = "spin-path-info" ;
2829// Environment variable for the fallback path
2930const FALLBACK_PATH_ENV : & str = "FALLBACK_PATH" ;
31+ /// Directory fallback path (trying to map `/about/` -> `/about/index.html`).
32+ const DIRECTORY_FALLBACK_PATH : & str = "index.html" ;
3033
3134/// Common Content Encodings
3235#[ derive( Debug , Eq , PartialEq ) ]
@@ -83,15 +86,29 @@ fn serve(req: Request) -> Result<Response> {
8386 let body = match FileServer :: read ( path, & enc) {
8487 // requested file was found
8588 Ok ( b) => Some ( b) ,
86- Err ( e) => match std:: env:: var ( FALLBACK_PATH_ENV ) {
87- // try to read the fallback path
88- Ok ( fallback_path) => FileServer :: read ( fallback_path. as_str ( ) , & enc) . ok ( ) ,
89- // fallback path config not found
90- Err ( _) => {
91- eprintln ! ( "Cannot read file: {e:?}" ) ;
92- None
89+ Err ( e) => {
90+ // if the error is because the path points to a directory, attempt to read `index.html`
91+ // from the directory. This is because most static file generators will generate this
92+ // file structure (where `/about` should be mapped to `/about/index.html`).
93+ eprintln ! ( "Cannot find file {path}. Attempting fallback." ) ;
94+ // TODO: ideally, we would return better errors throughout the implementation.
95+ if e. to_string ( ) . contains ( "Is a directory" ) {
96+ let path = PathBuf :: from ( path) . join ( DIRECTORY_FALLBACK_PATH ) ;
97+ let path = path. to_str ( ) . context ( "cannot convert path to string" ) ?;
98+ eprintln ! ( "Attempting fallback {path}" ) ;
99+ FileServer :: read ( path, & enc) . ok ( )
100+ } else {
101+ match std:: env:: var ( FALLBACK_PATH_ENV ) {
102+ // try to read the fallback path
103+ Ok ( fallback_path) => FileServer :: read ( fallback_path. as_str ( ) , & enc) . ok ( ) ,
104+ // fallback path config not found
105+ Err ( _) => {
106+ eprintln ! ( "Cannot read file: {e:?}" ) ;
107+ None
108+ }
109+ }
93110 }
94- } ,
111+ }
95112 } ;
96113
97114 let etag = FileServer :: get_etag ( body. clone ( ) ) ;
0 commit comments