diff --git a/Cargo.toml b/Cargo.toml index 6d3e6825..0c2c929c 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -51,6 +51,7 @@ serde_derive = "1.0" serde_json = "1.0" tokio = { version = "0.2.2", features = ["fs", "macros", "io-std", "rt-util", "sync", "time", "test-util"] } tokio-test = "0.2" +tokio-util = { version = "0.3", features = ["codec"] } tower-util = "0.3" url = "1.0" diff --git a/examples/README.md b/examples/README.md index a8308993..012e2bb0 100644 --- a/examples/README.md +++ b/examples/README.md @@ -39,7 +39,7 @@ pretty_env_logger = "0.4" * [`params`](params.rs) - A webserver that accept a form, with a name and a number, checks the parameters are presents and validates the input. -* [`send_file`](send_file.rs) - A server that sends back content of files using tokio_fs to read the files asynchronously. +* [`send_file`](send_file.rs) - A server that sends back content of files using tokio-util to read the files asynchronously. * [`single_threaded`](single_threaded.rs) - A server only running on 1 thread, so it can make use of `!Send` app state (like an `Rc` counter). diff --git a/examples/send_file.rs b/examples/send_file.rs index b98b1468..3f660abf 100644 --- a/examples/send_file.rs +++ b/examples/send_file.rs @@ -1,13 +1,13 @@ #![deny(warnings)] use tokio::fs::File; -use tokio::io::AsyncReadExt; + +use tokio_util::codec::{BytesCodec, FramedRead}; use hyper::service::{make_service_fn, service_fn}; use hyper::{Body, Method, Request, Response, Result, Server, StatusCode}; static INDEX: &str = "examples/send_file_index.html"; -static INTERNAL_SERVER_ERROR: &[u8] = b"Internal Server Error"; static NOTFOUND: &[u8] = b"Not Found"; #[tokio::main] @@ -30,9 +30,7 @@ async fn main() { async fn response_examples(req: Request) -> Result> { match (req.method(), req.uri().path()) { - (&Method::GET, "/") | (&Method::GET, "/index.html") | (&Method::GET, "/big_file.html") => { - simple_file_send(INDEX).await - } + (&Method::GET, "/") | (&Method::GET, "/index.html") => simple_file_send(INDEX).await, (&Method::GET, "/no_file.html") => { // Test what happens when file cannot be be found simple_file_send("this_file_should_not_exist.html").await @@ -49,26 +47,13 @@ fn not_found() -> Response { .unwrap() } -/// HTTP status code 500 -fn internal_server_error() -> Response { - Response::builder() - .status(StatusCode::INTERNAL_SERVER_ERROR) - .body(INTERNAL_SERVER_ERROR.into()) - .unwrap() -} - async fn simple_file_send(filename: &str) -> Result> { - // Serve a file by asynchronously reading it entirely into memory. - // Uses tokio_fs to open file asynchronously, then tokio::io::AsyncReadExt - // to read into memory asynchronously. + // Serve a file by asynchronously reading it by chunks using tokio-util crate. - if let Ok(mut file) = File::open(filename).await { - let mut buf = Vec::new(); - if let Ok(_) = file.read_to_end(&mut buf).await { - return Ok(Response::new(buf.into())); - } - - return Ok(internal_server_error()); + if let Ok(file) = File::open(filename).await { + let stream = FramedRead::new(file, BytesCodec::new()); + let body = Body::wrap_stream(stream); + return Ok(Response::new(body)); } Ok(not_found()) diff --git a/examples/send_file_index.html b/examples/send_file_index.html index 9153a809..da0f3282 100644 --- a/examples/send_file_index.html +++ b/examples/send_file_index.html @@ -3,9 +3,8 @@ Hyper responding example -

Hyper responding example

+

Hyper responding example, streamed in chunks

index.html Top Level
- big_file.html This page, streamed in chunks
no_file.html A 404 test, the requested file does not exist