warp
warp copied to clipboard
`warp::filters::fs::dir` handles `index.html` redirection incorrectly
When I run the following program:
use std::{io, path};
use warp::Filter;
#[tokio::main]
async fn main() -> io::Result<()> {
let cwd = path::Path::new(".").canonicalize()?;
warp::serve(warp::path("static").and(warp::fs::dir(cwd)))
.run(([0, 0, 0, 0], 3030))
.await;
Ok(())
}
in a directory containing files index.html
and index.css
with the contents:
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<link rel="stylesheet" href="index.css">
</head>
<body>
<h1>Hi!</h1>
</body>
</html>
and
h1 {
background: blue;
}
and then visit localhost:3030/static
in a web browser, I'm shipped the content of index.html
, but it cannot find its index.css
file. The header "Hi!" should appear in blue, but it does not.
This is because the page's document base url is set incorrectly: it is localhost:3030/static
, when it should be localhost:3030/static/
(note the trailing slash). This leads the web browser to request http://akatsuki:3030/index.css
instead of the correct http://akatsuki:3030/static/index.css
. If I instead visit the url localhost:3030/static/
, then the web browser is able to generate the correct relative URL for index.css
.
The problem is in the way warp::fs::dir
handles requests to directories. If the path refers to a directory, dir
simply adds index.html
to the end:
if is_dir {
tracing::debug!("dir: appending index.html to directory path");
buf.push("index.html");
}
If you look at the way other servers handle requests for URLs whose paths lack a trailing slash, you'll see that it first sends a 302 FOUND
response with a Location
response header that adds the slash. For URLs whose paths do have a trailing slash, they ship out index.html
.
Note that the warp::path("static")
is essential to the problem, since browsers automatically request /
when the URL's path is empty (that is, requesting localhost:3030
always sends GET / HTTP/1.1
), so the document base URL is set correctly.
If you look at the way other servers handle requests for URLs whose paths lack a trailing slash, you'll see that they first send a
302 FOUND
response with a Location response header that adds the slash.
The Python 3 http.server
module (i.e., python -m http.server 8000
) sends a 301 MOVED PERMANENTLY
redirect for this. So I guess it's not fixed exactly what response should be produced.