From d3afd4d08c2f7ffab9532b96f8ad0a2f5bae77af Mon Sep 17 00:00:00 2001 From: Ansaf Ahmed Date: Mon, 27 Oct 2025 15:08:57 +1100 Subject: [PATCH 1/3] support providing a custom chunk size --- src/http/mod.rs | 42 +++++++++++++++++++++++++----------------- 1 file changed, 25 insertions(+), 17 deletions(-) diff --git a/src/http/mod.rs b/src/http/mod.rs index 119c467..2ede3a8 100644 --- a/src/http/mod.rs +++ b/src/http/mod.rs @@ -96,14 +96,14 @@ impl<'a> Headers<'a> { } /// A generic HTTP client that uses a pooled connection strategy. -pub struct HttpClient { +pub struct HttpClient, const CHUNK_SIZE: usize = 1024> { connection_pool: Rc>, headers: Headers<'static>, } -impl HttpClient { +impl, const CHUNK_SIZE: usize> HttpClient { /// Create a new HTTP client from the provided pool. - pub fn new(connection_pool: C) -> HttpClient { + pub fn new(connection_pool: C) -> HttpClient { Self { connection_pool: Rc::new(RefCell::new(connection_pool)), headers: Headers { @@ -138,7 +138,7 @@ impl HttpClient { path: impl AsRef, body: Option<&[u8]>, builder: F, - ) -> io::Result> + ) -> io::Result> where F: FnOnce(&mut Headers), { @@ -173,18 +173,21 @@ impl HttpClient { method: Method, path: impl AsRef, body: Option<&[u8]>, - ) -> io::Result> { + ) -> io::Result> { self.new_request_with_headers(method, path, body, |_| {}) } } /// Trait defining a pool of reusable connections. -pub trait ConnectionPool: Sized { +pub trait ConnectionPool: Sized { /// Underlying stream type. type Stream: Read + Write; /// Turn this connection pool into http client. - fn into_http_client(self) -> HttpClient { + fn into_http_client(self) -> HttpClient + where + Self: ConnectionPool, + { HttpClient::new(self) } @@ -192,10 +195,10 @@ pub trait ConnectionPool: Sized { fn host(&self) -> &str; /// Acquire next free connection, if available. - fn acquire(&mut self) -> io::Result>>; + fn acquire(&mut self) -> io::Result>>; /// Release a connection back into the pool. - fn release(&mut self, stream: Option>); + fn release(&mut self, stream: Option>); } /// A single-connection pool over TLS, reconnecting on demand. @@ -258,8 +261,8 @@ impl ConnectionPool for SingleTlsConnectionPool { } /// Represents an in-flight HTTP exchange. -pub struct HttpRequest { - conn: Option>, +pub struct HttpRequest, const CHUNK_SIZE: usize = 1024> { + conn: Option>, pool: Rc>, state: State, } @@ -278,15 +281,15 @@ enum State { }, } -impl HttpRequest { +impl, const CHUNK_SIZE: usize> HttpRequest { fn new( method: Method, path: impl AsRef, body: Option<&[u8]>, headers: &Headers, - mut conn: Connection, + mut conn: Connection, pool: Rc>, - ) -> io::Result> { + ) -> io::Result> { conn.write_all(method.as_str().as_bytes())?; conn.write_all(b" ")?; conn.write_all(path.as_ref().as_bytes())?; @@ -440,7 +443,7 @@ impl HttpRequest { } } -impl Drop for HttpRequest { +impl, const CHUNK_SIZE: usize> Drop for HttpRequest { fn drop(&mut self) { if let Some(conn) = self.conn.as_mut() { conn.buffer.clear(); @@ -480,7 +483,7 @@ impl Connection { } } -impl Write for Connection { +impl Write for Connection { #[inline] fn write(&mut self, buf: &[u8]) -> io::Result { self.stream.write(buf) @@ -494,7 +497,7 @@ impl Write for Connection { impl Connection { #[inline] - fn new(stream: S) -> Self { + pub fn new(stream: S) -> Self { Self { stream, buffer: Vec::with_capacity(CHUNK_SIZE), @@ -502,6 +505,11 @@ impl Connection { header_finder: Finder::new(b"\r\n\r\n"), } } + + #[inline] + pub fn is_disconnected(&self) -> bool { + self.disconnected + } } #[cfg(test)] From d8b88bbae5ceb5bb94628a78aa88f32d37ffbe96 Mon Sep 17 00:00:00 2001 From: Ansaf Ahmed Date: Thu, 30 Oct 2025 11:19:13 +1100 Subject: [PATCH 2/3] add crate private default chunk size for http stream reads + document Connection fns --- src/http/mod.rs | 33 ++++++++++++++++++++++++++++----- 1 file changed, 28 insertions(+), 5 deletions(-) diff --git a/src/http/mod.rs b/src/http/mod.rs index 2ede3a8..3aadb10 100644 --- a/src/http/mod.rs +++ b/src/http/mod.rs @@ -40,6 +40,10 @@ use std::rc::Rc; pub use http::Method; use smallvec::SmallVec; +/// Default capacity of the buffer when reading chunks of bytes from the stream +/// On OSX if chunk_size > bytes_available_on_stream, the read operation will block +pub(crate) const DEFAULT_CHUNK_SIZE: usize = 1024; + type HttpTlsConnection = Connection>>; /// Re-usable container to store headers @@ -96,7 +100,7 @@ impl<'a> Headers<'a> { } /// A generic HTTP client that uses a pooled connection strategy. -pub struct HttpClient, const CHUNK_SIZE: usize = 1024> { +pub struct HttpClient, const CHUNK_SIZE: usize = DEFAULT_CHUNK_SIZE> { connection_pool: Rc>, headers: Headers<'static>, } @@ -179,7 +183,7 @@ impl, const CHUNK_SIZE: usize> HttpClient: Sized { +pub trait ConnectionPool: Sized { /// Underlying stream type. type Stream: Read + Write; @@ -261,7 +265,7 @@ impl ConnectionPool for SingleTlsConnectionPool { } /// Represents an in-flight HTTP exchange. -pub struct HttpRequest, const CHUNK_SIZE: usize = 1024> { +pub struct HttpRequest, const CHUNK_SIZE: usize = DEFAULT_CHUNK_SIZE> { conn: Option>, pool: Rc>, state: State, @@ -454,7 +458,7 @@ impl, const CHUNK_SIZE: usize> Drop for HttpReques /// Connection managed by the `ConnectionPool`. Binds underlying stream together with buffer used /// for reading data. The reading is performed in chunks with default size of 1024 bytes. -pub struct Connection { +pub struct Connection { stream: S, buffer: Vec, disconnected: bool, @@ -496,6 +500,24 @@ impl Write for Connection { } impl Connection { + /// Creates a new connection wrapper around the provided stream. + /// + /// Initializes a read buffer with capacity equal to `CHUNK_SIZE` and sets up + /// the HTTP header boundary finder for parsing responses. + /// + /// # Arguments + /// + /// * `stream` - The underlying I/O stream to wrap + /// + /// # Examples + /// + /// ```no_run + /// use boomnet::http::Connection; + /// use boomnet::stream::tcp::TcpStream; + /// + /// let tls = TcpStream::try_from(("127.0.0.1", 4222)).unwrap(); + /// let connection = Connection::new(tcp_stream); + /// ``` #[inline] pub fn new(stream: S) -> Self { Self { @@ -506,8 +528,9 @@ impl Connection { } } + /// Returns whether the connection has been marked as disconnected. #[inline] - pub fn is_disconnected(&self) -> bool { + pub const fn is_disconnected(&self) -> bool { self.disconnected } } From acbfaa6fbcf97f27f5f54fd5c28663e01dcc8021 Mon Sep 17 00:00:00 2001 From: Ansaf Ahmed Date: Mon, 3 Nov 2025 11:45:31 +1100 Subject: [PATCH 3/3] fix docs + change default chunk size visibility --- src/http/mod.rs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/http/mod.rs b/src/http/mod.rs index 3aadb10..7b71f7e 100644 --- a/src/http/mod.rs +++ b/src/http/mod.rs @@ -42,7 +42,7 @@ use smallvec::SmallVec; /// Default capacity of the buffer when reading chunks of bytes from the stream /// On OSX if chunk_size > bytes_available_on_stream, the read operation will block -pub(crate) const DEFAULT_CHUNK_SIZE: usize = 1024; +pub const DEFAULT_CHUNK_SIZE: usize = 1024; type HttpTlsConnection = Connection>>; @@ -515,8 +515,8 @@ impl Connection { /// use boomnet::http::Connection; /// use boomnet::stream::tcp::TcpStream; /// - /// let tls = TcpStream::try_from(("127.0.0.1", 4222)).unwrap(); - /// let connection = Connection::new(tcp_stream); + /// let tcp = TcpStream::try_from(("127.0.0.1", 4222)).unwrap(); + /// let connection = Connection::<_, 1024>::new(tcp); /// ``` #[inline] pub fn new(stream: S) -> Self {