Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
23 changes: 18 additions & 5 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -20,36 +20,49 @@ targets = ["x86_64-unknown-linux-gnu"]
[features]
default = ["webpki-roots", "charset", "system-proxy"]

websocket = ["dep:tokio-tungstenite"]

# Enable support for decoding text.
charset = ["dep:encoding_rs", "dep:mime"]

# Enable cookies store support.
cookies = ["dep:cookie_crate", "dep:cookie_store"]

# Enable gzip compression support.
gzip = ["tower-http/decompression-gzip"]

# Enable Brotli compression support.
brotli = ["tower-http/decompression-br"]

# Enable Zstandard compression support.
zstd = ["tower-http/decompression-zstd"]

# Enable deflate compression support.
deflate = ["tower-http/decompression-deflate"]

# Enable JSON support.
json = ["dep:serde_json"]

# Enable multipart/form-data support.
multipart = ["dep:mime_guess"]

# Enable hickory DNS resolver.
hickory-dns = ["dep:hickory-resolver"]

# Enable streaming support.
stream = ["tokio/fs", "dep:tokio-util"]

# Enable SOCKS proxy support.
socks = ["dep:tokio-socks"]

# Enable WebSocket support.
ws = ["dep:tokio-tungstenite"]

# Enable webpki-roots for TLS certificate validation.
webpki-roots = ["dep:webpki-root-certs"]

# Use the system's proxy configuration.
system-proxy = ["dep:system-configuration", "dep:windows-registry"]

# Optional enable tracing
# Enable tracing logging.
tracing = ["http2/tracing", "dep:tracing"]

[dependencies]
Expand Down Expand Up @@ -273,12 +286,12 @@ required-features = ["tracing"]
[[example]]
name = "http1_websocket"
path = "examples/http1_websocket.rs"
required-features = ["websocket", "futures-util/std", "tracing"]
required-features = ["ws", "futures-util/std", "tracing"]

[[example]]
name = "http2_websocket"
path = "examples/http2_websocket.rs"
required-features = ["websocket", "futures-util/std", "tracing"]
required-features = ["ws", "futures-util/std", "tracing"]

[[example]]
name = "keylog"
Expand Down
10 changes: 6 additions & 4 deletions src/client/http/aliases.rs
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ use crate::{
},
core::body::Incoming,
error::BoxError,
redirect::RedirectPolicy,
redirect::FollowRedirectPolicy,
};

#[cfg(not(feature = "cookies"))]
Expand Down Expand Up @@ -54,8 +54,10 @@ pub type ResponseBody = TimeoutBody<tower_http::decompression::DecompressionBody
)))]
pub type ResponseBody = TimeoutBody<Incoming>;

pub type RedirectLayer =
FollowRedirect<CookieLayer<ResponseBodyTimeout<Decompression<ClientService>>>, RedirectPolicy>;
pub type RedirectLayer = FollowRedirect<
CookieLayer<ResponseBodyTimeout<Decompression<ClientService>>>,
FollowRedirectPolicy,
>;

pub type CoreResponseFuture = crate::core::client::ResponseFuture;

Expand All @@ -65,7 +67,7 @@ pub type GenericClientService =
pub type BoxedClientService =
BoxCloneSyncService<HttpRequest<Body>, HttpResponse<ResponseBody>, BoxError>;

pub type BoxedClientServiceLayer = BoxCloneSyncServiceLayer<
pub type BoxedClientLayer = BoxCloneSyncServiceLayer<
BoxedClientService,
HttpRequest<Body>,
HttpResponse<ResponseBody>,
Expand Down
87 changes: 45 additions & 42 deletions src/client/http/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ use std::{
time::Duration,
};

use aliases::{BoxedClientService, BoxedClientServiceLayer, GenericClientService, ResponseBody};
use aliases::{BoxedClientLayer, BoxedClientService, GenericClientService, ResponseBody};
pub use future::Pending;
use http::{
Request as HttpRequest, Response as HttpResponse,
Expand All @@ -34,7 +34,7 @@ use {super::layer::cookie::CookieManagerLayer, crate::cookie};
feature = "deflate",
))]
use super::layer::decoder::{AcceptEncoding, DecompressionLayer};
#[cfg(feature = "websocket")]
#[cfg(feature = "ws")]
use super::ws::WebSocketRequestBuilder;
use super::{
Body, EmulationFactory,
Expand All @@ -61,7 +61,7 @@ use crate::{
dns::{DnsResolverWithOverrides, DynResolver, Resolve, gai::GaiResolver},
error::{self, BoxError, Error},
proxy::Matcher as ProxyMatcher,
redirect::{self, RedirectPolicy},
redirect::{self, FollowRedirectPolicy, Policy as RedirectPolicy},
tls::{AlpnProtocol, CertStore, Identity, KeyLogPolicy, TlsConnectorBuilder, TlsVersion},
};

Expand Down Expand Up @@ -130,7 +130,7 @@ struct Config {
tcp_user_timeout: Option<Duration>,
proxies: Vec<ProxyMatcher>,
auto_sys_proxy: bool,
redirect_policy: redirect::Policy,
redirect_policy: RedirectPolicy,
referer: bool,
timeout: Option<Duration>,
read_timeout: Option<Duration>,
Expand All @@ -143,15 +143,15 @@ struct Config {
http_version_pref: HttpVersionPref,
https_only: bool,
http2_max_retry: usize,
request_layers: Option<Vec<BoxedClientServiceLayer>>,
layers: Option<Vec<BoxedClientLayer>>,
connector_layers: Option<Vec<BoxedConnectorLayer>>,
tls_keylog_policy: Option<KeyLogPolicy>,
keylog_policy: Option<KeyLogPolicy>,
tls_info: bool,
tls_sni: bool,
tls_verify_hostname: bool,
tls_identity: Option<Identity>,
tls_cert_store: CertStore,
tls_cert_verification: bool,
verify_hostname: bool,
identity: Option<Identity>,
cert_store: CertStore,
cert_verification: bool,
min_tls_version: Option<TlsVersion>,
max_tls_version: Option<TlsVersion>,
transport_options: TransportOptions,
Expand Down Expand Up @@ -197,7 +197,7 @@ impl ClientBuilder {
tcp_user_timeout: None,
proxies: Vec::new(),
auto_sys_proxy: true,
redirect_policy: redirect::Policy::none(),
redirect_policy: RedirectPolicy::none(),
referer: true,
timeout: None,
read_timeout: None,
Expand All @@ -210,15 +210,15 @@ impl ClientBuilder {
http_version_pref: HttpVersionPref::All,
https_only: false,
http2_max_retry: 2,
request_layers: None,
layers: None,
connector_layers: None,
tls_keylog_policy: None,
keylog_policy: None,
tls_info: false,
tls_sni: true,
tls_verify_hostname: true,
tls_identity: None,
tls_cert_store: CertStore::default(),
tls_cert_verification: true,
verify_hostname: true,
identity: None,
cert_store: CertStore::default(),
cert_verification: true,
min_tls_version: None,
max_tls_version: None,
// Transport options for HTTP/1/2 and TLS.
Expand Down Expand Up @@ -252,6 +252,7 @@ impl ClientBuilder {

let (tls_opts, http1_opts, http2_opts) = config.transport_options.into_parts();

// Create the TLS connector with the provided options.
let connector = {
let resolver = {
let mut resolver: Arc<dyn Resolve> = match config.dns_resolver {
Expand All @@ -272,6 +273,7 @@ impl ClientBuilder {
DynResolver::new(resolver)
};

// Apply http connector options
let http = |http: &mut HttpConnector| {
http.set_keepalive(config.tcp_keepalive);
http.set_keepalive_interval(config.tcp_keepalive_interval);
Expand All @@ -284,22 +286,22 @@ impl ClientBuilder {
http.set_tcp_user_timeout(config.tcp_user_timeout);
};

// Apply tls connector options
let tls = |tls: TlsConnectorBuilder| {
let alpn_protocol = match config.http_version_pref {
HttpVersionPref::Http1 => Some(AlpnProtocol::HTTP1),

HttpVersionPref::Http2 => Some(AlpnProtocol::HTTP2),
_ => None,
};
tls.alpn_protocol(alpn_protocol)
.max_version(config.max_tls_version)
.min_version(config.min_tls_version)
.tls_sni(config.tls_sni)
.verify_hostname(config.tls_verify_hostname)
.cert_verification(config.tls_cert_verification)
.cert_store(config.tls_cert_store)
.identity(config.tls_identity)
.keylog(config.tls_keylog_policy)
.verify_hostname(config.verify_hostname)
.cert_verification(config.cert_verification)
.cert_store(config.cert_store)
.identity(config.identity)
.keylog(config.keylog_policy)
};

Connector::builder(proxies.clone(), resolver)
Expand All @@ -311,6 +313,7 @@ impl ClientBuilder {
.build(tls_opts.unwrap_or_default(), config.connector_layers)?
};

// Create client with the configured connector
let client = {
let http2_only = matches!(config.http_version_pref, HttpVersionPref::Http2);
let mut builder = HttpClient::builder(TokioExecutor::new());
Expand All @@ -326,7 +329,8 @@ impl ClientBuilder {
builder.build(connector)
};

let service = {
// Create the client with the configured service layers
let client = {
let service = ClientService {
Comment thread
0x676e67 marked this conversation as resolved.
client,
config: Arc::new(ClientConfig {
Expand Down Expand Up @@ -362,21 +366,23 @@ impl ClientBuilder {
.layer(CookieManagerLayer::new(config.cookie_store))
.service(service);

let policy = RedirectPolicy::new(config.redirect_policy)
.with_referer(config.referer)
.with_https_only(config.https_only);
let service = {
let policy = FollowRedirectPolicy::new(config.redirect_policy)
.with_referer(config.referer)
.with_https_only(config.https_only);

let service = ServiceBuilder::new()
.layer(FollowRedirectLayer::with_policy(policy))
.service(service);
ServiceBuilder::new()
.layer(FollowRedirectLayer::with_policy(policy))
.service(service)
};

let service = ServiceBuilder::new()
.layer(RetryLayer::new(Http2RetryPolicy::new(
config.http2_max_retry,
)))
.service(service);

match config.request_layers {
match config.layers {
Some(layers) => {
let service = layers.into_iter().fold(
BoxCloneSyncService::new(service),
Expand Down Expand Up @@ -410,7 +416,7 @@ impl ClientBuilder {
};

Ok(Client {
inner: Arc::new(service),
inner: Arc::new(client),
})
}

Expand Down Expand Up @@ -1061,7 +1067,7 @@ impl ClientBuilder {
/// Sets the identity to be used for client certificate authentication.
#[inline]
pub fn identity(mut self, identity: Identity) -> ClientBuilder {
self.config.tls_identity = Some(identity);
self.config.identity = Some(identity);
self
}

Expand All @@ -1071,7 +1077,7 @@ impl ClientBuilder {
/// for TLS connections. By default, the system's verify certificate store is used.
#[inline]
pub fn cert_store(mut self, store: CertStore) -> ClientBuilder {
self.config.tls_cert_store = store;
self.config.cert_store = store;
self
}

Expand All @@ -1088,7 +1094,7 @@ impl ClientBuilder {
/// as a last resort.
#[inline]
pub fn cert_verification(mut self, cert_verification: bool) -> ClientBuilder {
self.config.tls_cert_verification = cert_verification;
self.config.cert_verification = cert_verification;
self
}

Expand All @@ -1102,7 +1108,7 @@ impl ClientBuilder {
/// introduces a significant vulnerability to man-in-the-middle attacks.
#[inline]
pub fn verify_hostname(mut self, verify_hostname: bool) -> ClientBuilder {
self.config.tls_verify_hostname = verify_hostname;
self.config.verify_hostname = verify_hostname;
self
}

Expand All @@ -1118,7 +1124,7 @@ impl ClientBuilder {
/// Configures TLS key logging policy for the client.
#[inline]
pub fn keylog(mut self, policy: KeyLogPolicy) -> ClientBuilder {
self.config.tls_keylog_policy = Some(policy);
self.config.keylog_policy = Some(policy);
self
}

Expand Down Expand Up @@ -1237,10 +1243,7 @@ impl ClientBuilder {
<L::Service as Service<HttpRequest<Body>>>::Future: Send + 'static,
{
let layer = BoxCloneSyncServiceLayer::new(layer);
self.config
.request_layers
.get_or_insert_default()
.push(layer);
self.config.layers.get_or_insert_default().push(layer);
self
}

Expand Down Expand Up @@ -1453,7 +1456,7 @@ impl Client {
/// this after you set up your request, and just before you send the
/// request.
#[inline]
#[cfg(feature = "websocket")]
#[cfg(feature = "ws")]
pub fn websocket<U: IntoUrl>(&self, url: U) -> WebSocketRequestBuilder {
WebSocketRequestBuilder::new(self.request(Method::GET, url))
}
Expand Down
26 changes: 14 additions & 12 deletions src/client/mod.rs
Original file line number Diff line number Diff line change
@@ -1,3 +1,17 @@
mod emulation;
mod http;
mod response;
mod upgrade;

pub(crate) mod layer;
pub(crate) mod request;

pub mod body;
#[cfg(feature = "multipart")]
pub mod multipart;
#[cfg(feature = "ws")]
pub mod ws;

pub use self::{
body::Body,
emulation::{Emulation, EmulationFactory},
Expand All @@ -6,15 +20,3 @@ pub use self::{
response::Response,
upgrade::Upgraded,
};

pub mod body;
mod emulation;
mod http;
pub(crate) mod layer;
#[cfg(feature = "multipart")]
pub mod multipart;
pub(crate) mod request;
mod response;
mod upgrade;
#[cfg(feature = "websocket")]
pub mod ws;
Loading
Loading