@@ -77,40 +77,11 @@ fn serve(req: Request) -> Result<Response> {
7777 . map ( |h| h. to_str ( ) )
7878 . unwrap_or ( Ok ( "" ) ) ?;
7979
80- let path = match path {
81- "/" => "index.html" ,
82- _ => path,
83- } ;
84-
85- // read from the fallback path if the variable exists
86- let body = match FileServer :: read ( path, & enc) {
87- // requested file was found
88- Ok ( b) => Some ( b) ,
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 site 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- let directory_fallback = PathBuf :: from ( path) . join ( DIRECTORY_FALLBACK_PATH ) ;
96- if e. to_string ( ) . contains ( "Is a directory" ) && directory_fallback. exists ( ) {
97- let directory_fallback = directory_fallback
98- . to_str ( )
99- . context ( "cannot convert path to string" ) ?;
100- eprintln ! ( "Attempting directory fallback {directory_fallback}" ) ;
101- FileServer :: read ( directory_fallback, & enc) . ok ( )
102- } else {
103- match std:: env:: var ( FALLBACK_PATH_ENV ) {
104- // try to read the fallback path
105- Ok ( fallback_path) => FileServer :: read ( fallback_path. as_str ( ) , & enc) . ok ( ) ,
106- // fallback path config not found
107- Err ( _) => {
108- eprintln ! ( "Cannot read file: {e:?}" ) ;
109- None
110- }
111- }
112- }
113- }
80+ // resolve the requested path and then try to read the file
81+ // None should indicate that the file does not exist after attempting fallback paths
82+ let body = match FileServer :: resolve ( path) {
83+ Some ( path) => FileServer :: read ( path. as_str ( ) , & enc) . ok ( ) ,
84+ None => None ,
11485 } ;
11586
11687 let etag = FileServer :: get_etag ( body. clone ( ) ) ;
@@ -119,6 +90,36 @@ fn serve(req: Request) -> Result<Response> {
11990
12091struct FileServer ;
12192impl FileServer {
93+ /// Resolve the request path to a file path.
94+ /// Returns `None` if the path does not exist.
95+ fn resolve ( req_path : & str ) -> Option < String > {
96+ // fallback to index.html if the path is empty
97+ let mut path = if req_path. is_empty ( ) {
98+ PathBuf :: from ( DIRECTORY_FALLBACK_PATH )
99+ } else {
100+ PathBuf :: from ( req_path)
101+ } ;
102+
103+ // if the path is a directory, try to read the fallback file relative to the directory
104+ if path. is_dir ( ) {
105+ path. push ( DIRECTORY_FALLBACK_PATH ) ;
106+ }
107+
108+ // still haven't found a file, override with the user-configured fallback path
109+ if !path. exists ( ) {
110+ if let Ok ( fallback_path) = std:: env:: var ( FALLBACK_PATH_ENV ) {
111+ path = PathBuf :: from ( fallback_path) ;
112+ }
113+ }
114+
115+ // return the path if it exists
116+ if path. exists ( ) {
117+ Some ( path. to_str ( ) . unwrap ( ) . to_string ( ) )
118+ } else {
119+ None
120+ }
121+ }
122+
122123 /// Open the file given its path and return its content and content type header.
123124 fn read ( path : & str , encoding : & ContentEncoding ) -> Result < Bytes > {
124125 let mut file = File :: open ( path) . with_context ( || anyhow ! ( "cannot open {}" , path) ) ?;
@@ -318,10 +319,22 @@ mod tests {
318319
319320 #[ test]
320321 fn test_serve_index ( ) {
322+ // Test against path with trailing slash
323+ let req = spin_http:: Request {
324+ method : spin_http:: Method :: Get ,
325+ uri : "http://thisistest.com" . to_string ( ) ,
326+ headers : vec ! [ ( PATH_INFO_HEADER . to_string( ) , "./" . to_string( ) ) ] ,
327+ params : vec ! [ ] ,
328+ body : None ,
329+ } ;
330+ let rsp = <super :: SpinHttp as spin_http:: SpinHttp >:: handle_http_request ( req) ;
331+ assert_eq ! ( rsp. status, 200 ) ;
332+
333+ // Test against empty path
321334 let req = spin_http:: Request {
322335 method : spin_http:: Method :: Get ,
323336 uri : "http://thisistest.com" . to_string ( ) ,
324- headers : vec ! [ ( PATH_INFO_HEADER . to_string( ) , "/ " . to_string( ) ) ] ,
337+ headers : vec ! [ ( PATH_INFO_HEADER . to_string( ) , "" . to_string( ) ) ] ,
325338 params : vec ! [ ] ,
326339 body : None ,
327340 } ;
0 commit comments