@@ -25,6 +25,8 @@ const BROTLI_LEVEL: u32 = 3;
2525const BROTLI_ENCODING : & str = "br" ;
2626/// The path info header.
2727const PATH_INFO_HEADER : & str = "spin-path-info" ;
28+ // Environment variable for the fallback path
29+ const FALLBACK_PATH_ENV : & str = "FALLBACK_PATH" ;
2830
2931/// Common Content Encodings
3032#[ derive( Debug , Eq , PartialEq ) ]
@@ -77,12 +79,19 @@ fn serve(req: Request) -> Result<Response> {
7779 _ => path,
7880 } ;
7981
82+ // read from the fallback path if the variable exists
8083 let body = match FileServer :: read ( path, & enc) {
84+ // requested file was found
8185 Ok ( b) => Some ( b) ,
82- Err ( e) => {
83- eprintln ! ( "Cannot read file: {:?}" , e) ;
84- return not_found ( ) ;
85- }
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
93+ }
94+ } ,
8695 } ;
8796
8897 let etag = FileServer :: get_etag ( body. clone ( ) ) ;
@@ -149,10 +158,14 @@ impl FileServer {
149158 . ok_or ( anyhow ! ( "cannot get headers for response" ) ) ?;
150159 FileServer :: append_headers ( path, enc, etag, headers) ?;
151160
152- if etag == if_none_match {
153- return Ok ( res. status ( StatusCode :: NOT_MODIFIED ) . body ( None ) ?) ;
161+ if body. is_some ( ) {
162+ if etag == if_none_match {
163+ return Ok ( res. status ( StatusCode :: NOT_MODIFIED ) . body ( None ) ?) ;
164+ }
165+ Ok ( res. status ( StatusCode :: OK ) . body ( body) ?)
166+ } else {
167+ not_found ( )
154168 }
155- Ok ( res. status ( StatusCode :: OK ) . body ( body) ?)
156169 }
157170
158171 fn get_etag ( body : Option < Bytes > ) -> String {
@@ -264,6 +277,26 @@ mod tests {
264277 assert_eq ! ( rsp. status, 404 ) ;
265278 }
266279
280+ #[ test]
281+ fn test_serve_file_not_found_with_fallback_path ( ) {
282+ //NOTE: this test must not run in parallel to other tests because of it's use of an environment variable
283+ // hence the `--test-threads=1` in the `make test` target
284+ std:: env:: set_var ( FALLBACK_PATH_ENV , "hello-test.txt" ) ;
285+ let req = spin_http:: Request {
286+ method : spin_http:: Method :: Get ,
287+ uri : "http://thisistest.com" . to_string ( ) ,
288+ headers : vec ! [ (
289+ PATH_INFO_HEADER . to_string( ) ,
290+ "not-existent-file" . to_string( ) ,
291+ ) ] ,
292+ params : vec ! [ ] ,
293+ body : None ,
294+ } ;
295+ let rsp = <super :: SpinHttp as spin_http:: SpinHttp >:: handle_http_request ( req) ;
296+ std:: env:: remove_var ( FALLBACK_PATH_ENV ) ;
297+ assert_eq ! ( rsp. status, 200 ) ;
298+ }
299+
267300 #[ test]
268301 fn test_serve_index ( ) {
269302 let req = spin_http:: Request {
0 commit comments