diff --git a/src/http/mod.rs b/src/http/mod.rs index 502bd20..bca9b57 100644 --- a/src/http/mod.rs +++ b/src/http/mod.rs @@ -42,6 +42,7 @@ pub async fn make_server(host: SettingHost) -> anyhow::Result<()> { for host_route in &host.route { // lua script if let Some(lua_path) = &host_route.lua_script { + // papare lua script continue; } diff --git a/src/http/serve.rs b/src/http/serve.rs index d0c4c58..9059e83 100644 --- a/src/http/serve.rs +++ b/src/http/serve.rs @@ -15,7 +15,7 @@ use axum_extra::extract::Host; use dashmap::mapref::one::Ref; use http::{ HeaderMap, HeaderValue, StatusCode, Uri, - header::{CONTENT_TYPE, ETAG, IF_NONE_MATCH}, + header::{CONTENT_TYPE, ETAG, IF_NONE_MATCH, LOCATION}, }; use mime_guess::from_path; use tokio::fs::{self, File}; @@ -75,7 +75,7 @@ async fn custom_page( match stream_file(path.into(), request, Some(status)).await { Ok(res) => RouteResult::Ok(res), Err(e) => { - println!("Failed to stream file: {:?}", e); + error!("Failed to stream file: {:?}", e); RouteResult::Err(RouteError::InternalError()) } } @@ -149,7 +149,7 @@ pub async fn serve( #[allow(clippy::unnecessary_to_owned)] let path = path.to_string(); if path.contains('.') { - (root.into(), vec![format!("{}/{}", root, path)]) + (root.into(), vec![format!("{}{}", root, path)]) } else { generate_default_index(&host_route, &format!("{root}/{path}")) } @@ -157,6 +157,7 @@ pub async fn serve( generate_default_index(&host_route, root) }; debug!("request index file {:?}", path_arr); + debug!("req_path: {:?}", req_path); // Try each candidate path in order: // - Return the first successfully streamed file. // - If all fail, return a `RouteNotFound` error. @@ -172,6 +173,27 @@ pub async fn serve( let path_exists = match path_exists { Some(path_exists) => path_exists, None => { + error!("request {:?}", request); + let uri_path = uri.path(); + // 如果请求路径不以 / 结尾,则返回 301 Moved Permanently 状态码 + if !uri_path.ends_with('/') { + let mut response = Response::builder(); + let stream = empty_stream().await?; + let body = Body::from_stream(stream); + response + .headers_mut() + .with_context(|| "insert header failed")? + .insert( + LOCATION, + HeaderValue::from_str(format!("{uri_path}/").as_str()) + .with_context(|| "insert header failed")?, + ); + response = response.status(StatusCode::MOVED_PERMANENTLY); + let response = response + .body(body) + .with_context(|| "Failed to build HTTP response with body")?; + return Ok(response); + } // 生成自动目录索引 if host_route.auto_index { // HTML 中的标题路径,需要移除掉配置文件中的 root = "./html" 字段 @@ -267,16 +289,8 @@ async fn stream_file( } } - #[cfg(windows)] - let null = PathBuf::from("NUL"); - #[cfg(not(windows))] - let null = PathBuf::from("/dev/null"); - let stream = if not_modified { - let empty = File::open(null) - .await - .with_context(|| "open /dev/null failed")?; - ReaderStream::new(empty) + empty_stream().await? } else { ReaderStream::new(file) }; @@ -598,7 +612,11 @@ async fn list_dir(host_root_str: &str, path: &PathBuf) -> anyhow::Result anyhow::Result anyhow::Result anyhow::Result> { + #[cfg(windows)] + let null = PathBuf::from("NUL"); + #[cfg(not(windows))] + let null = PathBuf::from("/dev/null"); + let empty = File::open(null) + .await + .with_context(|| "open /dev/null failed")?; + Ok(ReaderStream::new(empty)) +}