From c18343225d62d39ff33ec84e1dc1c32994e9dd11 Mon Sep 17 00:00:00 2001 From: Connor Slade Date: Sun, 20 Aug 2023 04:47:11 +0000 Subject: [PATCH 1/4] Fix Support interrupted streams in response #46 --- Cargo.lock | 2 +- Cargo.toml | 2 +- Changelog.md | 9 ++++++++- README.md | 2 +- examples/tmp.rs | 52 +++++++++++++++++++++++++++++++++++++++++++++++++ lib/response.rs | 12 +++++++----- 6 files changed, 70 insertions(+), 9 deletions(-) create mode 100644 examples/tmp.rs diff --git a/Cargo.lock b/Cargo.lock index ca74a0a..8856b03 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -4,7 +4,7 @@ version = 3 [[package]] name = "afire" -version = "2.2.0" +version = "2.2.1" dependencies = [ "afire", ] diff --git a/Cargo.toml b/Cargo.toml index 1a8826a..16eb9f0 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -2,7 +2,7 @@ authors = ["Connor Slade "] edition = "2018" name = "afire" -version = "2.2.0" +version = "2.2.1" categories = ["network-programming", "web-programming::http-server"] description = "🔥 A blazing fast web framework for Rust" diff --git a/Changelog.md b/Changelog.md index a0817b1..bd52766 100644 --- a/Changelog.md +++ b/Changelog.md @@ -1,6 +1,13 @@ +# 2.2.1 + +August 20, 2023 + +- Properly support `ErrorKind::Interrupted` on streaming responses. + Previously if a Reader returned any error, afire would just print an error and close the socket. + # 2.2.0 -July, 02, 2023 +July 02, 2023 - Use binary search on ServeStatic MMIE types (save those clock cycles) - Some optimizations throughout afire diff --git a/README.md b/README.md index dd0257e..4cbc104 100644 --- a/README.md +++ b/README.md @@ -8,7 +8,7 @@ Just add the following to your `Cargo.toml`: ```toml [dependencies] -afire = "2.2.0" +afire = "2.2.1" ``` ## 📄 Info diff --git a/examples/tmp.rs b/examples/tmp.rs new file mode 100644 index 0000000..ad497ac --- /dev/null +++ b/examples/tmp.rs @@ -0,0 +1,52 @@ +use std::{time::Instant, io::Read}; + +use afire::{Server, Response}; + +fn main() { + let mut server = Server::<()>::new([127, 0, 0, 1], 8080); + + server.route(afire::Method::GET, "/test", |_| { + Response::new().stream(TestStream::new()) + }); + + server.start().unwrap(); +} + +struct TestStream { + count: usize, + last: Instant, +} + +impl TestStream { + fn new() -> Self { + Self { + count: 0, + last: Instant::now(), + } + } +} + +impl Read for TestStream { + fn read(&mut self, buf: &mut [u8]) -> std::io::Result { + if self.count >= 10 { + return Ok(0); + } + + let elapsed = self.last.elapsed().as_secs_f64(); + if elapsed < 1.0 { + return Err(std::io::Error::new( + std::io::ErrorKind::Interrupted, + "Not enough time has elapsed.", + )); + } + + self.last = Instant::now(); + self.count += 1; + + let data = format!("{{\"count\": {}}}", self.count); + let bytes = data.as_bytes(); + let len = bytes.len().min(buf.len()); + buf[..len].copy_from_slice(&bytes[..len]); + Ok(len) + } +} \ No newline at end of file diff --git a/lib/response.rs b/lib/response.rs index 5959749..6e1b669 100644 --- a/lib/response.rs +++ b/lib/response.rs @@ -1,6 +1,6 @@ use std::cell::RefCell; use std::fmt::{self, Debug, Display, Formatter}; -use std::io::{Read, Write}; +use std::io::{ErrorKind, Read, Write}; use std::net::TcpStream; use std::sync::{Arc, Mutex}; @@ -361,10 +361,12 @@ impl ResponseBody { let data = data.get_mut(); loop { let mut chunk = vec![0; consts::CHUNK_SIZE]; - let read = data.read(&mut chunk)?; - if read == 0 { - break; - } + let read = match data.read(&mut chunk) { + Ok(0) => break, + Ok(n) => n, + Err(ref e) if e.kind() == ErrorKind::Interrupted => continue, + Err(e) => return Err(e.into()), + }; let mut section = format!("{read:X}\r\n").as_bytes().to_vec(); section.extend(&chunk[..read]); From fceaf32bb54c2c4012106e82cd48c1c13ee5bf00 Mon Sep 17 00:00:00 2001 From: Connor Slade Date: Sun, 20 Aug 2023 00:51:52 -0400 Subject: [PATCH 2/4] Test and remove tmp.rs --- examples/tmp.rs | 52 ------------------------------------------------- 1 file changed, 52 deletions(-) delete mode 100644 examples/tmp.rs diff --git a/examples/tmp.rs b/examples/tmp.rs deleted file mode 100644 index ad497ac..0000000 --- a/examples/tmp.rs +++ /dev/null @@ -1,52 +0,0 @@ -use std::{time::Instant, io::Read}; - -use afire::{Server, Response}; - -fn main() { - let mut server = Server::<()>::new([127, 0, 0, 1], 8080); - - server.route(afire::Method::GET, "/test", |_| { - Response::new().stream(TestStream::new()) - }); - - server.start().unwrap(); -} - -struct TestStream { - count: usize, - last: Instant, -} - -impl TestStream { - fn new() -> Self { - Self { - count: 0, - last: Instant::now(), - } - } -} - -impl Read for TestStream { - fn read(&mut self, buf: &mut [u8]) -> std::io::Result { - if self.count >= 10 { - return Ok(0); - } - - let elapsed = self.last.elapsed().as_secs_f64(); - if elapsed < 1.0 { - return Err(std::io::Error::new( - std::io::ErrorKind::Interrupted, - "Not enough time has elapsed.", - )); - } - - self.last = Instant::now(); - self.count += 1; - - let data = format!("{{\"count\": {}}}", self.count); - let bytes = data.as_bytes(); - let len = bytes.len().min(buf.len()); - buf[..len].copy_from_slice(&bytes[..len]); - Ok(len) - } -} \ No newline at end of file From e374c1ca91771fb047e0aa96fa47278454bff448 Mon Sep 17 00:00:00 2001 From: Connor Slade Date: Sun, 2 Jul 2023 13:29:26 -0400 Subject: [PATCH 3/4] Build extensions on docs.rs --- Cargo.toml | 2 +- Changelog.md | 3 ++- lib/internal/common.rs | 2 +- lib/lib.rs | 4 ++-- 4 files changed, 6 insertions(+), 5 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index 16eb9f0..8e6a8a0 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -29,4 +29,4 @@ tracing = [] afire = { path = ".", features = ["extensions"] } [package.metadata.docs.rs] -rustc-args = ["--cfg", "docsrs"] +all-features = true diff --git a/Changelog.md b/Changelog.md index bd52766..7dbd7ea 100644 --- a/Changelog.md +++ b/Changelog.md @@ -5,6 +5,8 @@ August 20, 2023 - Properly support `ErrorKind::Interrupted` on streaming responses. Previously if a Reader returned any error, afire would just print an error and close the socket. +- Build extension docs on docs.rs + # 2.2.0 July 02, 2023 @@ -19,7 +21,6 @@ July 02, 2023 This allows for using `HeaderType`s as well as strings to set the header. - Add a `HEAD` middleware that adds support for the HTTP HEAD method. - Update `ServeStatic` to send a Content-Length header when streaming a file. -- Build extension docs on docs.rs - Add a `TRACE` middleware that adds support for the HTTP TRACE method. - Add support for [Server-Sent Events](https://developer.mozilla.org/en-US/docs/Web/API/Server-sent_events) (SSE). - Progress on Websocket support diff --git a/lib/internal/common.rs b/lib/internal/common.rs index 26f32de..e3bccc5 100644 --- a/lib/internal/common.rs +++ b/lib/internal/common.rs @@ -112,7 +112,7 @@ pub(crate) fn any_string(any: Box) -> Cow<'static, str /// Get the current time since the Unix Epoch. /// Will panic if the system time is before the Unix Epoch. -#[cfg(any(feature = "extensions", docsrs))] +#[cfg(feature = "extensions")] pub(crate) fn epoch() -> std::time::Duration { use std::time::{SystemTime, UNIX_EPOCH}; diff --git a/lib/lib.rs b/lib/lib.rs index b7ccc6b..38bb05a 100644 --- a/lib/lib.rs +++ b/lib/lib.rs @@ -61,9 +61,9 @@ pub mod prelude { } // Extra Features -#[cfg(any(feature = "extensions", docsrs))] +#[cfg(feature = "extensions")] mod extensions; -#[cfg(any(feature = "extensions", docsrs))] +#[cfg(feature = "extensions")] pub mod extension { //! Useful extensions to the base afire. //! Includes helpful middleware like Serve Static, Rate Limit and Logger. From 7ae43c9794c61beab8884d0b12f763b18a1293b7 Mon Sep 17 00:00:00 2001 From: Connor Slade Date: Sun, 20 Aug 2023 00:58:43 -0400 Subject: [PATCH 4/4] Update Changelog --- Changelog.md | 1 - 1 file changed, 1 deletion(-) diff --git a/Changelog.md b/Changelog.md index 7dbd7ea..404f42c 100644 --- a/Changelog.md +++ b/Changelog.md @@ -4,7 +4,6 @@ August 20, 2023 - Properly support `ErrorKind::Interrupted` on streaming responses. Previously if a Reader returned any error, afire would just print an error and close the socket. - - Build extension docs on docs.rs # 2.2.0