diff --git a/src/client/conn.rs b/src/client/conn.rs index f2e2ef99..61ffe63b 100644 --- a/src/client/conn.rs +++ b/src/client/conn.rs @@ -1,4 +1,8 @@ -//! todo +//! Tower layers and services for HTTP/1 and HTTP/2 client connections. +//! +//! This module provides Tower-compatible layers that wrap Hyper's low-level +//! HTTP client connection types, making them easier to compose with other +//! middleware and connection pooling strategies. use std::future::Future; use std::marker::PhantomData; @@ -12,14 +16,39 @@ use crate::common::future::poll_fn; type BoxError = Box; -/// todo +/// A Tower [`Layer`](tower_layer::Layer) for creating HTTP/1 client connections. +/// +/// This layer wraps a connection service (typically a TCP or TLS connector) and +/// performs the HTTP/1 handshake, producing an [`Http1ClientService`] that can +/// send requests. +/// +/// Use [`http1()`] to create a layer with default settings, or construct from +/// a [`hyper::client::conn::http1::Builder`] for custom configuration. +/// +/// # Example +/// +/// ```ignore +/// use hyper_util::client::conn::http1; +/// use hyper::{client::connect::HttpConnector, body::Bytes}; +/// use tower:: ServiceBuilder; +/// use http_body_util::Empty; +/// +/// let connector = HttpConnector::new(); +/// let layer: Http1Layer> = http1(); +/// let client = ServiceBuilder::new() +/// .layer(layer) +/// .service(connector); +/// ``` #[cfg(feature = "http1")] pub struct Http1Layer { builder: hyper::client::conn::http1::Builder, _body: PhantomData, } -/// todo +/// Creates an [`Http1Layer`] with default HTTP/1 settings. +/// +/// For custom settings, construct an [`Http1Layer`] from a +/// [`hyper::client::conn::http1::Builder`] using `.into()`. #[cfg(feature = "http1")] pub fn http1() -> Http1Layer { Http1Layer { @@ -60,7 +89,11 @@ impl From for Http1Layer { } } -/// todo +/// A Tower [`Service`] that establishes HTTP/1 connections. +/// +/// This service wraps an underlying connection service (e.g., TCP or TLS) and +/// performs the HTTP/1 handshake when called. The resulting service can be used +/// to send HTTP requests over the established connection. #[cfg(feature = "http1")] pub struct Http1Connect { inner: M, @@ -118,21 +151,56 @@ impl Clone for Http1Connect { } } -/// todo +/// A Tower [`Layer`](tower_layer::Layer) for creating HTTP/2 client connections. +/// +/// This layer wraps a connection service (typically a TCP or TLS connector) and +/// performs the HTTP/2 handshake, producing an [`Http2ClientService`] that can +/// send requests. +/// +/// Use [`http2()`] to create a layer with a specific executor, or construct from +/// a [`hyper::client::conn::http2::Builder`] for custom configuration. +/// +/// # Example +/// +/// ```ignore +/// use hyper_util::client::conn::http2; +/// use hyper::{client::connect::HttpConnector, body::Bytes}; +/// use tower:: ServiceBuilder; +/// use http_body_util::Empty; +/// +/// let connector = HttpConnector::new(); +/// let layer: Http2Layer> = http2(); +/// let client = ServiceBuilder::new() +/// .layer(layer) +/// .service(connector); +/// ``` #[cfg(feature = "http2")] -pub struct Http2Layer { +pub struct Http2Layer { + builder: hyper::client::conn::http2::Builder, _body: PhantomData, } -/// todo +/// Creates an [`Http2Layer`] with default HTTP/1 settings. +/// +/// For custom settings, construct an [`Http2Layer`] from a +/// [`hyper::client::conn::http2::Builder`] using `.into()`. #[cfg(feature = "http2")] -pub fn http2() -> Http2Layer { - Http2Layer { _body: PhantomData } +pub fn http2(executor: E) -> Http2Layer +where + E: Clone, +{ + Http2Layer { + builder: hyper::client::conn::http2::Builder::new(executor), + _body: PhantomData, + } } #[cfg(feature = "http2")] -impl tower_layer::Layer for Http2Layer { - type Service = Http2Connect; +impl tower_layer::Layer for Http2Layer +where + E: Clone, +{ + type Service = Http2Connect; fn layer(&self, inner: M) -> Self::Service { Http2Connect { inner, @@ -143,25 +211,40 @@ impl tower_layer::Layer for Http2Layer { } #[cfg(feature = "http2")] -impl Clone for Http2Layer { +impl Clone for Http2Layer { fn clone(&self) -> Self { Self { + builder: self.builder.clone(), _body: self._body.clone(), } } } -/// todo +#[cfg(feature = "http2")] +impl From> for Http2Layer { + fn from(builder: hyper::client::conn::http2::Builder) -> Self { + Self { + builder, + _body: PhantomData, + } + } +} + +/// A Tower [`Service`] that establishes HTTP/2 connections. +/// +/// This service wraps an underlying connection service (e.g., TCP or TLS) and +/// performs the HTTP/2 handshake when called. The resulting service can be used +/// to send HTTP requests over the established connection. #[cfg(feature = "http2")] #[derive(Debug)] -pub struct Http2Connect { +pub struct Http2Connect { inner: M, - builder: hyper::client::conn::http2::Builder, + builder: hyper::client::conn::http2::Builder, _body: PhantomData, } #[cfg(feature = "http2")] -impl Service for Http2Connect +impl Service for Http2Connect where M: Service, M::Future: Send + 'static, @@ -170,6 +253,7 @@ where B: hyper::body::Body + Unpin + Send + 'static, B::Data: Send + 'static, B::Error: Into, + E: hyper::rt::bounds::Http2ClientConnExec + Unpin + Clone + Send + 'static, { type Response = Http2ClientService; type Error = BoxError; @@ -199,7 +283,7 @@ where } #[cfg(feature = "http2")] -impl Clone for Http2Connect { +impl Clone for Http2Connect { fn clone(&self) -> Self { Self { inner: self.inner.clone(), @@ -209,7 +293,14 @@ impl Clone for Http2Connect { } } -/// A thin adapter over hyper HTTP/1 client SendRequest. +/// A Tower [`Service`] that sends HTTP/1 requests over an established connection. +/// +/// This is a thin wrapper around [`hyper::client::conn::http1::SendRequest`] that implements +/// the Tower `Service` trait, making it composable with other Tower middleware. +/// +/// The service maintains a single HTTP/1 connection and can be used to send multiple +/// sequential requests. For concurrent requests or connection pooling, wrap this service +/// with appropriate middleware. #[cfg(feature = "http1")] #[derive(Debug)] pub struct Http1ClientService { @@ -218,7 +309,10 @@ pub struct Http1ClientService { #[cfg(feature = "http1")] impl Http1ClientService { - /// todo + /// Constructs a new HTTP/1 client service from a Hyper `SendRequest`. + /// + /// Typically you won't call this directly; instead, use [`Http1Connect`] to + /// establish connections and produce this service. pub fn new(tx: hyper::client::conn::http1::SendRequest) -> Self { Self { tx } } @@ -248,7 +342,14 @@ where } } -/// todo +/// A Tower [`Service`] that sends HTTP/2 requests over an established connection. +/// +/// This is a thin wrapper around [`hyper::client::conn::http2::SendRequest`] that implements +/// the Tower `Service` trait, making it composable with other Tower middleware. +/// +/// The service maintains a single HTTP/2 connection and supports multiplexing multiple +/// concurrent requests over that connection. The service can be cloned to send requests +/// concurrently, or used with the [`Singleton`](crate::client::pool::singleton::Singleton) pool service. #[cfg(feature = "http2")] #[derive(Debug)] pub struct Http2ClientService { @@ -257,7 +358,10 @@ pub struct Http2ClientService { #[cfg(feature = "http2")] impl Http2ClientService { - /// todo + /// Constructs a new HTTP/2 client service from a Hyper `SendRequest`. + /// + /// Typically you won't call this directly; instead, use [`Http2Connect`] to + /// establish connections and produce this service. pub fn new(tx: hyper::client::conn::http2::SendRequest) -> Self { Self { tx } } diff --git a/src/client/pool/map.rs b/src/client/pool/map.rs index 83b56480..8ff4179d 100644 --- a/src/client/pool/map.rs +++ b/src/client/pool/map.rs @@ -48,7 +48,7 @@ where // impl Map impl Map { - /// Create a [`Builder`] to configure a new `Map`. + /// Create a `Builder` to configure a new `Map`. pub fn builder() -> builder::Builder { builder::Builder::new()