//! Connectors used by the `Client`. //! //! This module contains: //! //! - A default [`HttpConnector`][] that does DNS resolution and establishes //! connections over TCP. //! - Types to build custom connectors. //! //! # Connectors //! //! A "connector" is a [`Service`][] that takes a [`Uri`][] destination, and //! its `Response` is some type implementing [`AsyncRead`][], [`AsyncWrite`][], //! and [`Connection`][]. //! //! ## Custom Connectors //! //! A simple connector that ignores the `Uri` destination and always returns //! a TCP connection to the same address could be written like this: //! //! ```rust,ignore //! let connector = tower::service_fn(|_dst| async { //! tokio::net::TcpStream::connect("127.0.0.1:1337") //! }) //! ``` //! //! Or, fully written out: //! //! ``` //! # #[cfg(feature = "runtime")] //! # mod rt { //! use std::{future::Future, net::SocketAddr, pin::Pin, task::{self, Poll}}; //! use hyper::{service::Service, Uri}; //! use tokio::net::TcpStream; //! //! #[derive(Clone)] //! struct LocalConnector; //! //! impl Service<Uri> for LocalConnector { //! type Response = TcpStream; //! type Error = std::io::Error; //! // We can't "name" an `async` generated future. //! type Future = Pin<Box< //! dyn Future<Output = Result<Self::Response, Self::Error>> + Send //! >>; //! //! fn poll_ready(&mut self, _: &mut task::Context<'_>) -> Poll<Result<(), Self::Error>> { //! // This connector is always ready, but others might not be. //! Poll::Ready(Ok(())) //! } //! //! fn call(&mut self, _: Uri) -> Self::Future { //! Box::pin(TcpStream::connect(SocketAddr::from(([127, 0, 0, 1], 1337)))) //! } //! } //! # } //! ``` //! //! It's worth noting that for `TcpStream`s, the [`HttpConnector`][] is a //! better starting place to extend from. //! //! Using either of the above connector examples, it can be used with the //! `Client` like this: //! //! ``` //! # #[cfg(feature = "runtime")] //! # fn rt () { //! # let connector = hyper::client::HttpConnector::new(); //! // let connector = ... //! //! let client = hyper::Client::builder() //! .build::<_, hyper::Body>(connector); //! # } //! ``` //! //! //! [`HttpConnector`]: HttpConnector //! [`Service`]: crate::service::Service //! [`Uri`]: ::http::Uri //! [`AsyncRead`]: tokio::io::AsyncRead //! [`AsyncWrite`]: tokio::io::AsyncWrite //! [`Connection`]: Connection use std::fmt;
/// Describes a type returned by a connector. pubtrait Connection { /// Return metadata describing the connection. fn connected(&self) -> Connected;
}
/// Extra information about the connected transport. /// /// This can be used to inform recipients about things like if ALPN /// was used, or if connected to an HTTP proxy. #[derive(Debug)] pubstruct Connected { pub(super) alpn: Alpn, pub(super) is_proxied: bool, pub(super) extra: Option<Extra>,
}
impl Connected { /// Create new `Connected` type with empty metadata. pubfn new() -> Connected {
Connected {
alpn: Alpn::None,
is_proxied: false,
extra: None,
}
}
/// Set whether the connected transport is to an HTTP proxy. /// /// This setting will affect if HTTP/1 requests written on the transport /// will have the request-target in absolute-form or origin-form: /// /// - When `proxy(false)`: /// /// ```http /// GET /guide HTTP/1.1 /// ``` /// /// - When `proxy(true)`: /// /// ```http /// GET http://hyper.rs/guide HTTP/1.1 /// ``` /// /// Default is `false`. pubfn proxy(mutself, is_proxied: bool) -> Connected { self.is_proxied = is_proxied; self
}
/// Determines if the connected transport is to an HTTP proxy. pubfn is_proxied(&self) -> bool { self.is_proxied
}
/// Set extra connection information to be set in the extensions of every `Response`. pubfn extra<T: Clone + Send + Sync + 'static>(mut self, extra: T) -> Connected { iflet Some(prev) = self.extra { self.extra = Some(Extra(Box::new(ExtraChain(prev.0, extra))));
} else { self.extra = Some(Extra(Box::new(ExtraEnvelope(extra))));
} self
}
/// Copies the extra connection information into an `Extensions` map. pubfn get_extras(&self, extensions: &mut Extensions) { iflet Some(extra) = &self.extra {
extra.set(extensions);
}
}
/// Set that the connected transport negotiated HTTP/2 as its next protocol. pubfn negotiated_h2(mutself) -> Connected { self.alpn = Alpn::H2; self
}
/// Determines if the connected transport negotiated HTTP/2 as its next protocol. pubfn is_negotiated_h2(&self) -> bool { self.alpn == Alpn::H2
}
// Don't public expose that `Connected` is `Clone`, unsure if we want to // keep that contract... #[cfg(feature = "http2")] pub(super) fn clone(&self) -> Connected {
Connected {
alpn: self.alpn.clone(),
is_proxied: self.is_proxied,
extra: self.extra.clone(),
}
}
}
// This indirection allows the `Connected` to have a type-erased "extra" value, // while that type still knows its inner extra type. This allows the correct // TypeId to be used when inserting into `res.extensions_mut()`. #[derive(Clone)] struct ExtraEnvelope<T>(T);
/// Connect to a destination, returning an IO transport. /// /// A connector receives a [`Uri`](::http::Uri) and returns a `Future` of the /// ready connection. /// /// # Trait Alias /// /// This is really just an *alias* for the `tower::Service` trait, with /// additional bounds set for convenience *inside* hyper. You don't actually /// implement this trait, but `tower::Service<Uri>` instead. // The `Sized` bound is to prevent creating `dyn Connect`, since they cannot // fit the `Connect` bounds because of the blanket impl for `Service`. pubtrait Connect: Sealed + Sized { #[doc(hidden)] type _Svc: ConnectSvc; #[doc(hidden)] fn connect(self, internal_only: Internal, dst: Uri) -> <Self::_Svc as ConnectSvc>::Future;
}
#[test] fn test_connected_extra_chain() { // If a user composes connectors and at each stage, there's "extra" // info to attach, it shouldn't override the previous extras.
let c1 = Connected::new()
.extra(Ex1(45))
.extra(Ex2("zoom"))
.extra(Ex3("pew pew"));
// Just like extensions, inserting the same type overrides previous type. let c2 = Connected::new()
.extra(Ex1(33))
.extra(Ex2("hiccup"))
.extra(Ex1(99));
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.