ruststatic-filesiron

How to serve a fallback file using Iron's staticfile when the original file is not found?


I'm using Iron to serve a React site. I'm trying to get it to serve index.html if the file or directory does not exist.

fn staticHandler(req: &mut Request) -> IronResult<Response> {
    let url = Url::parse("http://localhost:1393").unwrap();
    let getFile_result = Static::handle(&Static::new(Path::new("../html")), req);

    match getFile_result {
        Ok(_) => getFile_result,
        Err(err) => {
            Static::handle(
                // returns 404 error - ../html/index.html returns 500
                &Static::new(Path::new("localhost:1393/index.html")),
                req,
            )
        }
    }
}

If I go to localhost:1393 I get my index page if I go to localhost:1393/not-a-directory I just get an error.

Is there a way to redirect (without changing the url) or some other solution?

This is not a duplicate of How to change Iron's default 404 behaviour? because I'm trying to handle when the static asset the user requests does not exist, not when the route is not defined.


Solution

  • As discussed on staticfile issue #78 titled "Static with fallback", you can wrap the handler, check for a 404, and serve a file instead:

    struct Fallback;
    
    impl AroundMiddleware for Fallback {
        fn around(self, handler: Box<Handler>) -> Box<Handler> {
            Box::new(FallbackHandler(handler))
        }
    }
    
    struct FallbackHandler(Box<Handler>);
    
    impl Handler for FallbackHandler {
        fn handle(&self, req: &mut Request) -> IronResult<Response> {
            let resp = self.0.handle(req);
    
            match resp {
                Err(err) => {
                    match err.response.status {
                        Some(status::NotFound) => {
                            let file = File::open("/tmp/example").unwrap();
                            Ok(Response::with((status::Ok, file)))
                        }
                        _ => Err(err),
                    }
                }
                other => other
            }
        }
    }