From c6b2fe1f404789feca0ef9d9982720bba193b112 Mon Sep 17 00:00:00 2001 From: Alan Somers Date: Sat, 16 Oct 2021 14:36:28 -0600 Subject: [PATCH] Fix relative links if the user omits "/index.html" in his request cargo-docserver can't simply pretend that the user meant to fetch "FOO/index.html" if he requests "FOO" and retrieve the file accordingly. Doing that breaks relative links. Instead, cargo-docserver must send a 302 redirect in such cases. Fixes #10 --- src/main.rs | 78 ++++++++++++++++++++++++++--------------------------- 1 file changed, 39 insertions(+), 39 deletions(-) diff --git a/src/main.rs b/src/main.rs index 614538a..9db4e41 100644 --- a/src/main.rs +++ b/src/main.rs @@ -65,22 +65,6 @@ fn test_make_relative() { assert_eq!("foo/bar/baz", make_relative("///foo/bar/baz")); } -#[test] -fn test_make_root_document() { - assert_eq!("/foo/hello/index.html", make_index("/foo/hello")); - assert_eq!("/foo/hello/index.html", make_index("/foo/hello/")); - assert_eq!("/foo/hello.foo", make_index("/foo/hello.foo")); -} - -fn make_index(path: &str) -> String { - let sanitized_path = path.trim_end_matches("/"); - if sanitized_path.contains(".") { - sanitized_path.to_string() - } else { - format!("{}/index.html", sanitized_path) - } -} - fn make_relative(path: &str) -> String { path.trim_start_matches("/").to_string() } @@ -96,34 +80,50 @@ fn serve_docs(req: Request) -> ResponseFuture { .unwrap(), )), (&Method::GET, path) => { - let full_path = info.doc_path.join(&make_index(&make_relative(path))); - let mime_type = format!("{}", mime_guess::guess_mime_type(&full_path)); + let relpath = make_relative(path); + let full_path = info.doc_path.join(&relpath); + let full_path2 = full_path.clone(); Box::new( - tokio_fs::file::File::open(full_path) - .and_then(|file| { - let buf: Vec = Vec::new(); - tokio_io::io::read_to_end(file, buf) - .and_then(move |item| { - Ok(Response::builder() - .status(200) - .header("Content-Type", mime_type.as_str()) - .body(item.1.into()) - .unwrap()) + tokio_fs::metadata(full_path) + .and_then(move |metadata| { + if metadata.is_dir() { + Box::new(future::ok( + Response::builder() + .status(302) + .header("Location", format!("/{}/index.html", relpath)) + .body(Body::empty()) + .unwrap() + )) as Box + Send> + } else { + let mime_type = format!("{}", mime_guess::guess_mime_type(&full_path2)); + Box::new( + tokio_fs::file::File::open(full_path2) + .and_then(|file| { + let buf: Vec = Vec::new(); + tokio_io::io::read_to_end(file, buf) + .and_then(move |item| { + Ok(Response::builder() + .status(200) + .header("Content-Type", mime_type.as_str()) + .body(item.1.into()) + .unwrap()) + }) + .or_else(|_| { + Ok(Response::builder() + .status(StatusCode::INTERNAL_SERVER_ERROR) + .body(Body::empty()) + .unwrap()) + }) }) .or_else(|_| { Ok(Response::builder() - .status(StatusCode::INTERNAL_SERVER_ERROR) - .body(Body::empty()) + .status(StatusCode::NOT_FOUND) + .body("not found".into()) .unwrap()) - }) - }) - .or_else(|_| { - Ok(Response::builder() - .status(StatusCode::NOT_FOUND) - .body("not found".into()) - .unwrap()) - }), - ) + }), + ) as Box + Send> + } + })) } _ => not_found(),