diff --git a/Cargo.lock b/Cargo.lock index 9ddd3ae..2554a07 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -89,6 +89,7 @@ dependencies = [ "serde", "thiserror", "tokio", + "tokio-util", "toml", "tracing", "tracing-subscriber", diff --git a/Cargo.toml b/Cargo.toml index 6b6e89b..d32c2ab 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -23,6 +23,7 @@ toml = "0.8.12" tracing = "0.1.40" tracing-subscriber = { version = "0.3.18", features = ["env-filter"] } futures-util = "0.3.30" +tokio-util = "0.7.10" [profile.release] lto = true diff --git a/src/service.rs b/src/service.rs index b1f0861..5c2770d 100644 --- a/src/service.rs +++ b/src/service.rs @@ -1,16 +1,17 @@ use std::pin::Pin; use crate::error::{Error, Result}; -use futures_util::Future; -use http_body_util::Full; +use futures_util::{Future, TryStreamExt}; +use http_body_util::{combinators::BoxBody, BodyExt, Full, StreamBody}; use hyper::{ - body::{Bytes, Incoming as IncomingBody}, + body::{Bytes, Frame, Incoming as IncomingBody}, server::conn::http1, service::Service, - Request, Response, + Request, Response, StatusCode, }; use hyper_util::rt::TokioIo; -use tokio::net::TcpListener; +use tokio::{fs::File, net::TcpListener}; +use tokio_util::io::ReaderStream; use tracing::error; use crate::config::SettingHost; @@ -39,7 +40,7 @@ impl SettingHost { } impl Service> for SettingHost { - type Response = Response>; + type Response = Response>; type Error = Error; type Future = Pin> + Send>>; @@ -48,15 +49,52 @@ impl Service> for SettingHost { } } -pub async fn mk_response(req: Request) -> Result>> { +pub async fn mk_response(req: Request) -> Result>> { // let route = &self.route; let req_path = req.uri().path(); - let res = match req_path { + let req_method = req.method(); + + let res = match (req_method, req_path) { // Return the 404 Not Found for other routes. - _ => "404", + _ => not_found(), }; - let res = Response::builder().body(Full::new(Bytes::from(res)))?; Ok(res) } + +type Test = BoxBody; +async fn handle_file(path: &str) -> Result>> { + // Open file for reading + let file = File::open(path).await; + let file = match file { + Ok(f) => f, + Err(err) => { + error!("Unable to open file {err}"); + return Ok(not_found()); + } + }; + + // Wrap to a tokio_util::io::ReaderStream + let reader_stream = ReaderStream::new(file); + // Convert to http_body_util::BoxBody + let stream_body = StreamBody::new(reader_stream.map_ok(Frame::data)); + // let boxed_body = stream_body.map_err(|e| Error::IoError(e)).boxed(); + let boxed_body = BodyExt::map_err(stream_body, Error::IoError).boxed(); + + // Send response + let response = Response::builder() + .status(StatusCode::OK) + .body(boxed_body)?; + + Ok(response) +} + +// HTTP status code 404 +static NOT_FOUND: &[u8] = b"Not Found"; +fn not_found() -> Response> { + Response::builder() + .status(StatusCode::NOT_FOUND) + .body(Full::new(NOT_FOUND.into()).map_err(|e| match e {}).boxed()) + .unwrap() +}