2

I want Warp to serve the current working directory. Here is the entire main.rs:

#[tokio::main]
async fn main() {
    let current_dir = std::env::current_dir().expect("failed to read current directory");
    warp::serve(warp::fs::dir(current_dir))
        .run(([127, 0, 0, 1], 3030))
        .await;
}

With the following dependencies:

[dependencies]
tokio = { version = "1.5", features = ["full"] }
warp = "0.3"

Then I run it on directory www with the following structure:

www
├── foo
|   └── index.html
|   └── style.css
└── bar
    └── index.html
    └── style.css

The HTML pages are served, but their referenced CSS files are not. The HTML pages reference their respective CSS file using <link rel="stylesheet" href="style.css">

I have this working using node.js express, but with Warp it attempts to load www/style.css, rather than www/foo/style.css and www/bar/style.css.

It works if I change the href to "foo/style.css" and "bar/style.css", but I would like to avoid that if possible. Is there something I can change on Warp's end to fix this?

Edit: I learned that the pages render with the CSS properly if the URL contains a trailing slash.

So this doesn't work:

http://localhost:3030/foo
http://localhost:3030/bar

But this does:

http://localhost:3030/foo/
http://localhost:3030/bar/
  • It's hard to answer your question because it doesn't include a [MRE]. We can't tell what crates (and their versions), types, traits, fields, etc. are present in the code. It would make it easier for us to help you if you try to reproduce your error on the [Rust Playground](https://play.rust-lang.org) if possible, otherwise in a brand new Cargo project, then [edit] your question to include the additional info. There are [Rust-specific MRE tips](https://stackoverflow.com/tags/rust/info) you can use to reduce your original code for posting here. Thanks! – Shepmaster May 11 '21 at 15:04
  • 1
    Does your HTML structure work with any other web server? E.g. if you use something like Python's simple HTTP server in that directory. – Shepmaster May 11 '21 at 15:05
  • @Shepmaster Yes, it works as intended with node.js express. I'll add additional details now. –  May 11 '21 at 15:24
  • I think this is a duplicate of [this question](https://stackoverflow.com/questions/59808298/serve-static-files-using-warp-in-rust) – michaelgrigoryan25 May 12 '21 at 18:48
  • @michael.grigoryan Thanks, but I think this is different because a) I am using the absolute path and b) I have no issues accessing the CSS files directly using ```http://localhost:3030/{site}/style.css```. –  May 12 '21 at 20:15
  • For me both versions of the URL don't work. My stylesheet is also accessible and I served it using `warp::serve()`. The stylesheet is not even loaded (network tab), but there is also no error and it is available under the given href... – frankenapps Jun 05 '21 at 11:52

1 Answers1

1

Thanks to @Kitsu's comment for a similar question, I learned that this is currently an open issue.

I ended up using a slightly modified version of kolektiv's solution from that discussion. It gets the path using warp::path::full(), then redirects with the trailing slash if needed. Here is code working as intended for my example.

cargo.toml's dependencies:

[dependencies]
tokio = { version = "1.5", features = ["full"] }
warp = "0.3"

main.rs:

use std::str::FromStr;
use warp::{filters::BoxedFilter, http::Uri, path::FullPath, redirect, Filter, Reply};

#[tokio::main]
async fn main() {
    let current_dir = std::env::current_dir().expect("failed to read current directory");

    let routes = root_redirect().or(warp::fs::dir(current_dir));

    warp::serve(routes).run(([127, 0, 0, 1], 3030)).await;
}

fn root_redirect() -> BoxedFilter<(impl Reply,)> {
    warp::path::full()
        .and_then(move |path: FullPath| async move {
            let path = path.as_str();

            // do not redirect if the path ends in a trailing slash
            // or contains a period (indicating a specific file, e.g. style.css)
            if path.ends_with("/") || path.contains(".") {
                return Err(warp::reject());
            }

            Ok(redirect::redirect(
                Uri::from_str(&[path, "/"].concat()).unwrap(),
            ))
        })
        .boxed()
}