mirror of
https://github.com/actix/actix-web.git
synced 2024-12-16 21:26:34 +00:00
feat(awc): split connector config with connect config, allow to configure connect config per request
This commit is contained in:
parent
0915879267
commit
610dd616ef
11 changed files with 261 additions and 57 deletions
|
@ -3,29 +3,33 @@ use std::{net::IpAddr, time::Duration};
|
|||
const DEFAULT_H2_CONN_WINDOW: u32 = 1024 * 1024 * 2; // 2MB
|
||||
const DEFAULT_H2_STREAM_WINDOW: u32 = 1024 * 1024; // 1MB
|
||||
|
||||
/// Connector configuration
|
||||
#[derive(Clone)]
|
||||
pub(crate) struct ConnectorConfig {
|
||||
/// Connect configuration
|
||||
#[derive(Clone, Hash, Eq, PartialEq)]
|
||||
pub struct ConnectConfig {
|
||||
pub(crate) timeout: Duration,
|
||||
pub(crate) handshake_timeout: Duration,
|
||||
pub(crate) conn_lifetime: Duration,
|
||||
pub(crate) conn_keep_alive: Duration,
|
||||
pub(crate) disconnect_timeout: Option<Duration>,
|
||||
pub(crate) limit: usize,
|
||||
pub(crate) conn_window_size: u32,
|
||||
pub(crate) stream_window_size: u32,
|
||||
pub(crate) local_address: Option<IpAddr>,
|
||||
}
|
||||
|
||||
impl Default for ConnectorConfig {
|
||||
/// Connector configuration
|
||||
#[derive(Clone)]
|
||||
pub struct ConnectorConfig {
|
||||
pub(crate) default_connect_config: ConnectConfig,
|
||||
pub(crate) disconnect_timeout: Option<Duration>,
|
||||
pub(crate) limit: usize,
|
||||
}
|
||||
|
||||
impl Default for ConnectConfig {
|
||||
fn default() -> Self {
|
||||
Self {
|
||||
timeout: Duration::from_secs(5),
|
||||
handshake_timeout: Duration::from_secs(5),
|
||||
conn_lifetime: Duration::from_secs(75),
|
||||
conn_keep_alive: Duration::from_secs(15),
|
||||
disconnect_timeout: Some(Duration::from_millis(3000)),
|
||||
limit: 100,
|
||||
conn_window_size: DEFAULT_H2_CONN_WINDOW,
|
||||
stream_window_size: DEFAULT_H2_STREAM_WINDOW,
|
||||
local_address: None,
|
||||
|
@ -33,10 +37,88 @@ impl Default for ConnectorConfig {
|
|||
}
|
||||
}
|
||||
|
||||
impl Default for ConnectorConfig {
|
||||
fn default() -> Self {
|
||||
Self {
|
||||
default_connect_config: ConnectConfig::default(),
|
||||
disconnect_timeout: Some(Duration::from_millis(3000)),
|
||||
limit: 100,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl ConnectorConfig {
|
||||
pub(crate) fn no_disconnect_timeout(&self) -> Self {
|
||||
pub fn no_disconnect_timeout(&self) -> Self {
|
||||
let mut res = self.clone();
|
||||
res.disconnect_timeout = None;
|
||||
res
|
||||
}
|
||||
}
|
||||
|
||||
impl ConnectConfig {
|
||||
/// Sets TCP connection timeout.
|
||||
///
|
||||
/// This is the max time allowed to connect to remote host, including DNS name resolution.
|
||||
///
|
||||
/// By default, the timeout is 5 seconds.
|
||||
pub fn timeout(mut self, timeout: Duration) -> Self {
|
||||
self.timeout = timeout;
|
||||
self
|
||||
}
|
||||
|
||||
/// Sets TLS handshake timeout.
|
||||
///
|
||||
/// This is the max time allowed to perform the TLS handshake with remote host after TCP
|
||||
/// connection is established.
|
||||
///
|
||||
/// By default, the timeout is 5 seconds.
|
||||
pub fn handshake_timeout(mut self, timeout: Duration) -> Self {
|
||||
self.handshake_timeout = timeout;
|
||||
self
|
||||
}
|
||||
|
||||
/// Sets the initial window size (in bytes) for HTTP/2 stream-level flow control for received
|
||||
/// data.
|
||||
///
|
||||
/// The default value is 65,535 and is good for APIs, but not for big objects.
|
||||
pub fn initial_window_size(mut self, size: u32) -> Self {
|
||||
self.stream_window_size = size;
|
||||
self
|
||||
}
|
||||
|
||||
/// Sets the initial window size (in bytes) for HTTP/2 connection-level flow control for
|
||||
/// received data.
|
||||
///
|
||||
/// The default value is 65,535 and is good for APIs, but not for big objects.
|
||||
pub fn initial_connection_window_size(mut self, size: u32) -> Self {
|
||||
self.conn_window_size = size;
|
||||
self
|
||||
}
|
||||
|
||||
/// Set keep-alive period for opened connection.
|
||||
///
|
||||
/// Keep-alive period is the period between connection usage. If
|
||||
/// the delay between repeated usages of the same connection
|
||||
/// exceeds this period, the connection is closed.
|
||||
/// Default keep-alive period is 15 seconds.
|
||||
pub fn conn_keep_alive(mut self, dur: Duration) -> Self {
|
||||
self.conn_keep_alive = dur;
|
||||
self
|
||||
}
|
||||
|
||||
/// Set max lifetime period for connection.
|
||||
///
|
||||
/// Connection lifetime is max lifetime of any opened connection
|
||||
/// until it is closed regardless of keep-alive period.
|
||||
/// Default lifetime period is 75 seconds.
|
||||
pub fn conn_lifetime(mut self, dur: Duration) -> Self {
|
||||
self.conn_lifetime = dur;
|
||||
self
|
||||
}
|
||||
|
||||
/// Set local IP Address the connector would use for establishing connection.
|
||||
pub fn local_address(mut self, addr: IpAddr) -> Self {
|
||||
self.local_address = Some(addr);
|
||||
self
|
||||
}
|
||||
}
|
||||
|
|
|
@ -282,7 +282,7 @@ where
|
|||
///
|
||||
/// By default, the timeout is 5 seconds.
|
||||
pub fn timeout(mut self, timeout: Duration) -> Self {
|
||||
self.config.timeout = timeout;
|
||||
self.config.default_connect_config.timeout = timeout;
|
||||
self
|
||||
}
|
||||
|
||||
|
@ -293,7 +293,7 @@ where
|
|||
///
|
||||
/// By default, the timeout is 5 seconds.
|
||||
pub fn handshake_timeout(mut self, timeout: Duration) -> Self {
|
||||
self.config.handshake_timeout = timeout;
|
||||
self.config.default_connect_config.handshake_timeout = timeout;
|
||||
self
|
||||
}
|
||||
|
||||
|
@ -387,7 +387,7 @@ where
|
|||
///
|
||||
/// The default value is 65,535 and is good for APIs, but not for big objects.
|
||||
pub fn initial_window_size(mut self, size: u32) -> Self {
|
||||
self.config.stream_window_size = size;
|
||||
self.config.default_connect_config.stream_window_size = size;
|
||||
self
|
||||
}
|
||||
|
||||
|
@ -396,7 +396,7 @@ where
|
|||
///
|
||||
/// The default value is 65,535 and is good for APIs, but not for big objects.
|
||||
pub fn initial_connection_window_size(mut self, size: u32) -> Self {
|
||||
self.config.conn_window_size = size;
|
||||
self.config.default_connect_config.conn_window_size = size;
|
||||
self
|
||||
}
|
||||
|
||||
|
@ -422,7 +422,7 @@ where
|
|||
/// exceeds this period, the connection is closed.
|
||||
/// Default keep-alive period is 15 seconds.
|
||||
pub fn conn_keep_alive(mut self, dur: Duration) -> Self {
|
||||
self.config.conn_keep_alive = dur;
|
||||
self.config.default_connect_config.conn_keep_alive = dur;
|
||||
self
|
||||
}
|
||||
|
||||
|
@ -432,7 +432,7 @@ where
|
|||
/// until it is closed regardless of keep-alive period.
|
||||
/// Default lifetime period is 75 seconds.
|
||||
pub fn conn_lifetime(mut self, dur: Duration) -> Self {
|
||||
self.config.conn_lifetime = dur;
|
||||
self.config.default_connect_config.conn_lifetime = dur;
|
||||
self
|
||||
}
|
||||
|
||||
|
@ -451,7 +451,7 @@ where
|
|||
|
||||
/// Set local IP Address the connector would use for establishing connection.
|
||||
pub fn local_address(mut self, addr: IpAddr) -> Self {
|
||||
self.config.local_address = Some(addr);
|
||||
self.config.default_connect_config.local_address = Some(addr);
|
||||
self
|
||||
}
|
||||
|
||||
|
@ -459,8 +459,8 @@ where
|
|||
///
|
||||
/// The `Connector` builder always concludes by calling `finish()` last in its combinator chain.
|
||||
pub fn finish(self) -> ConnectorService<S, IO> {
|
||||
let local_address = self.config.local_address;
|
||||
let timeout = self.config.timeout;
|
||||
let local_address = self.config.default_connect_config.local_address;
|
||||
let timeout = self.config.default_connect_config.timeout;
|
||||
|
||||
let tcp_service_inner =
|
||||
TcpConnectorInnerService::new(self.connector, timeout, local_address);
|
||||
|
@ -523,7 +523,7 @@ where
|
|||
}
|
||||
}
|
||||
|
||||
let handshake_timeout = self.config.handshake_timeout;
|
||||
let handshake_timeout = self.config.default_connect_config.handshake_timeout;
|
||||
|
||||
let tls_service = TlsConnectorService {
|
||||
tcp_service: tcp_service_inner,
|
||||
|
@ -557,7 +557,7 @@ where
|
|||
}
|
||||
}
|
||||
|
||||
let handshake_timeout = self.config.handshake_timeout;
|
||||
let handshake_timeout = self.config.default_connect_config.handshake_timeout;
|
||||
|
||||
let tls_service = TlsConnectorService {
|
||||
tcp_service: tcp_service_inner,
|
||||
|
@ -596,7 +596,7 @@ where
|
|||
}
|
||||
}
|
||||
|
||||
let handshake_timeout = self.config.handshake_timeout;
|
||||
let handshake_timeout = self.config.default_connect_config.handshake_timeout;
|
||||
|
||||
let tls_service = TlsConnectorService {
|
||||
tcp_service: tcp_service_inner,
|
||||
|
@ -630,7 +630,7 @@ where
|
|||
}
|
||||
}
|
||||
|
||||
let handshake_timeout = self.config.handshake_timeout;
|
||||
let handshake_timeout = self.config.default_connect_config.handshake_timeout;
|
||||
|
||||
let tls_service = TlsConnectorService {
|
||||
tcp_service: tcp_service_inner,
|
||||
|
@ -667,7 +667,7 @@ where
|
|||
}
|
||||
}
|
||||
|
||||
let handshake_timeout = self.config.handshake_timeout;
|
||||
let handshake_timeout = self.config.default_connect_config.handshake_timeout;
|
||||
|
||||
let tls_service = TlsConnectorService {
|
||||
tcp_service: tcp_service_inner,
|
||||
|
@ -701,7 +701,7 @@ where
|
|||
}
|
||||
}
|
||||
|
||||
let handshake_timeout = self.config.handshake_timeout;
|
||||
let handshake_timeout = self.config.default_connect_config.handshake_timeout;
|
||||
|
||||
let tls_service = TlsConnectorService {
|
||||
tcp_service: tcp_service_inner,
|
||||
|
@ -824,9 +824,13 @@ where
|
|||
}
|
||||
|
||||
fn call(&self, req: Connect) -> Self::Future {
|
||||
let timeout = req
|
||||
.config
|
||||
.clone()
|
||||
.map(|c| c.handshake_timeout)
|
||||
.unwrap_or(self.timeout);
|
||||
let fut = self.tcp_service.call(req);
|
||||
let tls_service = self.tls_service.clone();
|
||||
let timeout = self.timeout;
|
||||
|
||||
TlsConnectorFuture::TcpConnect {
|
||||
fut,
|
||||
|
@ -935,6 +939,7 @@ where
|
|||
actix_service::forward_ready!(service);
|
||||
|
||||
fn call(&self, req: Connect) -> Self::Future {
|
||||
let timeout = req.config.map(|c| c.timeout).unwrap_or(self.timeout);
|
||||
let mut req = ConnectInfo::new(HostnameWithSni::ForTcp(
|
||||
req.hostname,
|
||||
req.port,
|
||||
|
@ -949,7 +954,7 @@ where
|
|||
|
||||
TcpConnectorInnerFuture {
|
||||
fut: self.service.call(req),
|
||||
timeout: sleep(self.timeout),
|
||||
timeout: sleep(timeout),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -19,7 +19,6 @@ use http::{
|
|||
use log::trace;
|
||||
|
||||
use super::{
|
||||
config::ConnectorConfig,
|
||||
connection::{ConnectionIo, H2Connection},
|
||||
error::SendRequestError,
|
||||
};
|
||||
|
@ -186,12 +185,13 @@ where
|
|||
|
||||
pub(crate) fn handshake<Io: ConnectionIo>(
|
||||
io: Io,
|
||||
config: &ConnectorConfig,
|
||||
stream_window_size: u32,
|
||||
conn_window_size: u32,
|
||||
) -> impl Future<Output = Result<(SendRequest<Bytes>, Connection<Io, Bytes>), h2::Error>> {
|
||||
let mut builder = Builder::new();
|
||||
builder
|
||||
.initial_window_size(config.stream_window_size)
|
||||
.initial_connection_window_size(config.conn_window_size)
|
||||
.initial_window_size(stream_window_size)
|
||||
.initial_connection_window_size(conn_window_size)
|
||||
.enable_push(false);
|
||||
builder.handshake(io)
|
||||
}
|
||||
|
|
|
@ -20,6 +20,7 @@ mod h2proto;
|
|||
mod pool;
|
||||
|
||||
pub use self::{
|
||||
config::ConnectConfig,
|
||||
connection::{Connection, ConnectionIo},
|
||||
connector::{Connector, ConnectorService, HostnameWithSni},
|
||||
error::{ConnectError, FreezeRequestError, InvalidUrl, SendRequestError},
|
||||
|
@ -49,6 +50,7 @@ pub struct Connect {
|
|||
pub port: u16,
|
||||
pub tls: bool,
|
||||
pub addr: Option<std::net::SocketAddr>,
|
||||
pub config: Option<Rc<ConnectConfig>>,
|
||||
}
|
||||
|
||||
/// An asynchronous HTTP and WebSocket client.
|
||||
|
|
|
@ -190,7 +190,11 @@ where
|
|||
let now = Instant::now();
|
||||
|
||||
while let Some(mut c) = conns.pop_front() {
|
||||
let config = &inner.config;
|
||||
let config = req
|
||||
.config
|
||||
.as_ref()
|
||||
.map(|c| c.as_ref())
|
||||
.unwrap_or(&inner.config.default_connect_config);
|
||||
let idle_dur = now - c.used;
|
||||
let age = now - c.created;
|
||||
let conn_ineligible =
|
||||
|
@ -225,6 +229,17 @@ where
|
|||
conn
|
||||
};
|
||||
|
||||
let stream_window_size = req
|
||||
.config
|
||||
.as_ref()
|
||||
.map(|c| c.stream_window_size)
|
||||
.unwrap_or(inner.config.default_connect_config.stream_window_size);
|
||||
let conn_window_size = req
|
||||
.config
|
||||
.as_ref()
|
||||
.map(|c| c.conn_window_size)
|
||||
.unwrap_or(inner.config.default_connect_config.conn_window_size);
|
||||
|
||||
// construct acquired. It's used to put Io type back to pool/ close the Io type.
|
||||
// permit is carried with the whole lifecycle of Acquired.
|
||||
let acquired = Acquired {
|
||||
|
@ -245,8 +260,8 @@ where
|
|||
if proto == Protocol::Http1 {
|
||||
Ok(ConnectionType::from_h1(io, Instant::now(), acquired))
|
||||
} else {
|
||||
let config = &acquired.inner.config;
|
||||
let (sender, connection) = handshake(io, config).await?;
|
||||
let (sender, connection) =
|
||||
handshake(io, stream_window_size, conn_window_size).await?;
|
||||
let inner = H2ConnectionInner::new(sender, connection);
|
||||
Ok(ConnectionType::from_h2(inner, Instant::now(), acquired))
|
||||
}
|
||||
|
@ -381,6 +396,7 @@ mod test {
|
|||
use std::cell::Cell;
|
||||
|
||||
use super::*;
|
||||
use crate::client::ConnectConfig;
|
||||
|
||||
/// A stream type that always returns pending on async read.
|
||||
///
|
||||
|
@ -469,6 +485,7 @@ mod test {
|
|||
tls: false,
|
||||
sni_host: None,
|
||||
addr: None,
|
||||
config: None,
|
||||
};
|
||||
|
||||
let conn = pool.call(req.clone()).await.unwrap();
|
||||
|
@ -500,7 +517,10 @@ mod test {
|
|||
let connector = TestPoolConnector { generated };
|
||||
|
||||
let config = ConnectorConfig {
|
||||
conn_keep_alive: Duration::from_secs(1),
|
||||
default_connect_config: ConnectConfig {
|
||||
conn_keep_alive: Duration::from_secs(1),
|
||||
..Default::default()
|
||||
},
|
||||
..Default::default()
|
||||
};
|
||||
|
||||
|
@ -512,6 +532,7 @@ mod test {
|
|||
tls: false,
|
||||
sni_host: None,
|
||||
addr: None,
|
||||
config: None,
|
||||
};
|
||||
|
||||
let conn = pool.call(req.clone()).await.unwrap();
|
||||
|
@ -545,7 +566,10 @@ mod test {
|
|||
let connector = TestPoolConnector { generated };
|
||||
|
||||
let config = ConnectorConfig {
|
||||
conn_lifetime: Duration::from_secs(1),
|
||||
default_connect_config: ConnectConfig {
|
||||
conn_lifetime: Duration::from_secs(1),
|
||||
..Default::default()
|
||||
},
|
||||
..Default::default()
|
||||
};
|
||||
|
||||
|
@ -557,6 +581,7 @@ mod test {
|
|||
tls: false,
|
||||
sni_host: None,
|
||||
addr: None,
|
||||
config: None,
|
||||
};
|
||||
|
||||
let conn = pool.call(req.clone()).await.unwrap();
|
||||
|
@ -599,6 +624,7 @@ mod test {
|
|||
tls: true,
|
||||
sni_host: None,
|
||||
addr: None,
|
||||
config: None,
|
||||
};
|
||||
|
||||
let conn = pool.call(req.clone()).await.unwrap();
|
||||
|
@ -615,6 +641,7 @@ mod test {
|
|||
tls: true,
|
||||
sni_host: None,
|
||||
addr: None,
|
||||
config: None,
|
||||
};
|
||||
|
||||
let conn = pool.call(req.clone()).await.unwrap();
|
||||
|
@ -642,6 +669,7 @@ mod test {
|
|||
tls: true,
|
||||
sni_host: None,
|
||||
addr: None,
|
||||
config: None,
|
||||
};
|
||||
|
||||
let conn = pool.call(req.clone()).await.unwrap();
|
||||
|
@ -654,6 +682,7 @@ mod test {
|
|||
tls: true,
|
||||
sni_host: None,
|
||||
addr: None,
|
||||
config: None,
|
||||
};
|
||||
let conn = pool.call(req.clone()).await.unwrap();
|
||||
assert_eq!(2, generated_clone.get());
|
||||
|
|
|
@ -14,8 +14,8 @@ use futures_core::{future::LocalBoxFuture, ready};
|
|||
use crate::{
|
||||
any_body::AnyBody,
|
||||
client::{
|
||||
Connect as ClientConnect, ConnectError, Connection, ConnectionIo, SendRequestError,
|
||||
ServerName,
|
||||
Connect as ClientConnect, ConnectConfig, ConnectError, Connection, ConnectionIo,
|
||||
SendRequestError, ServerName,
|
||||
},
|
||||
ClientResponse,
|
||||
};
|
||||
|
@ -41,12 +41,18 @@ pub enum ConnectRequest {
|
|||
AnyBody,
|
||||
Option<net::SocketAddr>,
|
||||
Option<ServerName>,
|
||||
Option<Rc<ConnectConfig>>,
|
||||
),
|
||||
|
||||
/// Tunnel used by WebSocket connection requests.
|
||||
///
|
||||
/// Contains the request head, optional pre-resolved socket address and optional sni host.
|
||||
Tunnel(RequestHead, Option<net::SocketAddr>, Option<ServerName>),
|
||||
Tunnel(
|
||||
RequestHead,
|
||||
Option<net::SocketAddr>,
|
||||
Option<ServerName>,
|
||||
Option<Rc<ConnectConfig>>,
|
||||
),
|
||||
}
|
||||
|
||||
/// Combined HTTP response & WebSocket tunnel type returned from connection service.
|
||||
|
@ -111,11 +117,13 @@ where
|
|||
|
||||
fn call(&self, req: ConnectRequest) -> Self::Future {
|
||||
// connect to the host
|
||||
let (head, addr, sni_host) = match req {
|
||||
ConnectRequest::Client(ref head, .., addr, ref sni_host) => {
|
||||
(head.as_ref(), addr, sni_host.clone())
|
||||
let (head, addr, sni_host, config) = match req {
|
||||
ConnectRequest::Client(ref head, .., addr, ref sni_host, ref config) => {
|
||||
(head.as_ref(), addr, sni_host.clone(), config.clone())
|
||||
}
|
||||
ConnectRequest::Tunnel(ref head, addr, ref sni_host, ref config) => {
|
||||
(head, addr, sni_host.clone(), config.clone())
|
||||
}
|
||||
ConnectRequest::Tunnel(ref head, addr, ref sni_host) => (head, addr, sni_host.clone()),
|
||||
};
|
||||
|
||||
let authority = if let Some(authority) = head.uri.authority() {
|
||||
|
@ -144,6 +152,7 @@ where
|
|||
tls,
|
||||
sni_host,
|
||||
addr,
|
||||
config,
|
||||
});
|
||||
|
||||
ConnectRequestFuture::Connection {
|
||||
|
|
|
@ -11,7 +11,7 @@ use futures_core::Stream;
|
|||
use serde::Serialize;
|
||||
|
||||
use crate::{
|
||||
client::{ClientConfig, ServerName},
|
||||
client::{ClientConfig, ConnectConfig, ServerName},
|
||||
sender::{RequestSender, SendClientRequest},
|
||||
BoxError,
|
||||
};
|
||||
|
@ -27,6 +27,7 @@ pub struct FrozenClientRequest {
|
|||
pub(crate) timeout: Option<Duration>,
|
||||
pub(crate) config: ClientConfig,
|
||||
pub(crate) sni_host: Option<ServerName>,
|
||||
pub(crate) connect_config: Option<Rc<ConnectConfig>>,
|
||||
}
|
||||
|
||||
impl FrozenClientRequest {
|
||||
|
@ -56,6 +57,7 @@ impl FrozenClientRequest {
|
|||
self.timeout,
|
||||
&self.config,
|
||||
self.sni_host.clone(),
|
||||
self.connect_config.clone(),
|
||||
body,
|
||||
)
|
||||
}
|
||||
|
@ -68,6 +70,7 @@ impl FrozenClientRequest {
|
|||
self.timeout,
|
||||
&self.config,
|
||||
self.sni_host.clone(),
|
||||
self.connect_config.clone(),
|
||||
value,
|
||||
)
|
||||
}
|
||||
|
@ -80,6 +83,7 @@ impl FrozenClientRequest {
|
|||
self.timeout,
|
||||
&self.config,
|
||||
self.sni_host.clone(),
|
||||
self.connect_config.clone(),
|
||||
value,
|
||||
)
|
||||
}
|
||||
|
@ -96,6 +100,7 @@ impl FrozenClientRequest {
|
|||
self.timeout,
|
||||
&self.config,
|
||||
self.sni_host.clone(),
|
||||
self.connect_config.clone(),
|
||||
stream,
|
||||
)
|
||||
}
|
||||
|
@ -108,6 +113,7 @@ impl FrozenClientRequest {
|
|||
self.timeout,
|
||||
&self.config,
|
||||
self.sni_host.clone(),
|
||||
self.connect_config.clone(),
|
||||
)
|
||||
}
|
||||
|
||||
|
@ -163,6 +169,7 @@ impl FrozenSendBuilder {
|
|||
self.req.timeout,
|
||||
&self.req.config,
|
||||
self.req.sni_host.clone(),
|
||||
self.req.connect_config,
|
||||
body,
|
||||
)
|
||||
}
|
||||
|
@ -179,6 +186,7 @@ impl FrozenSendBuilder {
|
|||
self.req.timeout,
|
||||
&self.req.config,
|
||||
self.req.sni_host.clone(),
|
||||
self.req.connect_config,
|
||||
value,
|
||||
)
|
||||
}
|
||||
|
@ -195,6 +203,7 @@ impl FrozenSendBuilder {
|
|||
self.req.timeout,
|
||||
&self.req.config,
|
||||
self.req.sni_host.clone(),
|
||||
self.req.connect_config,
|
||||
value,
|
||||
)
|
||||
}
|
||||
|
@ -215,6 +224,7 @@ impl FrozenSendBuilder {
|
|||
self.req.timeout,
|
||||
&self.req.config,
|
||||
self.req.sni_host.clone(),
|
||||
self.req.connect_config,
|
||||
stream,
|
||||
)
|
||||
}
|
||||
|
@ -231,6 +241,7 @@ impl FrozenSendBuilder {
|
|||
self.req.timeout,
|
||||
&self.req.config,
|
||||
self.req.sni_host.clone(),
|
||||
self.req.connect_config,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -73,13 +73,13 @@ where
|
|||
|
||||
fn call(&self, req: ConnectRequest) -> Self::Future {
|
||||
match req {
|
||||
ConnectRequest::Tunnel(head, addr, sni_host) => {
|
||||
ConnectRequest::Tunnel(head, addr, sni_host, config) => {
|
||||
let fut = self
|
||||
.connector
|
||||
.call(ConnectRequest::Tunnel(head, addr, sni_host));
|
||||
.call(ConnectRequest::Tunnel(head, addr, sni_host, config));
|
||||
RedirectServiceFuture::Tunnel { fut }
|
||||
}
|
||||
ConnectRequest::Client(head, body, addr, sni_host) => {
|
||||
ConnectRequest::Client(head, body, addr, sni_host, config) => {
|
||||
let connector = Rc::clone(&self.connector);
|
||||
let max_redirect_times = self.max_redirect_times;
|
||||
|
||||
|
@ -98,7 +98,8 @@ where
|
|||
_ => None,
|
||||
};
|
||||
|
||||
let fut = connector.call(ConnectRequest::Client(head, body, addr, sni_host));
|
||||
let fut =
|
||||
connector.call(ConnectRequest::Client(head, body, addr, sni_host, config));
|
||||
|
||||
RedirectServiceFuture::Client {
|
||||
fut,
|
||||
|
@ -223,8 +224,8 @@ where
|
|||
let fut = connector
|
||||
.as_ref()
|
||||
.unwrap()
|
||||
// @TODO find a way to get sni host
|
||||
.call(ConnectRequest::Client(head, body_new, addr, None));
|
||||
// @TODO find a way to get sni host and config
|
||||
.call(ConnectRequest::Client(head, body_new, addr, None, None));
|
||||
|
||||
self.set(RedirectServiceFuture::Client {
|
||||
fut,
|
||||
|
|
|
@ -14,7 +14,7 @@ use serde::Serialize;
|
|||
#[cfg(feature = "cookies")]
|
||||
use crate::cookie::{Cookie, CookieJar};
|
||||
use crate::{
|
||||
client::{ClientConfig, ServerName},
|
||||
client::{ClientConfig, ConnectConfig, ServerName},
|
||||
error::{FreezeRequestError, InvalidUrl},
|
||||
frozen::FrozenClientRequest,
|
||||
sender::{PrepForSendingError, RequestSender, SendClientRequest},
|
||||
|
@ -49,6 +49,7 @@ pub struct ClientRequest {
|
|||
timeout: Option<Duration>,
|
||||
config: ClientConfig,
|
||||
sni_host: Option<ServerName>,
|
||||
connect_config: Option<ConnectConfig>,
|
||||
|
||||
#[cfg(feature = "cookies")]
|
||||
cookies: Option<CookieJar>,
|
||||
|
@ -71,6 +72,7 @@ impl ClientRequest {
|
|||
timeout: None,
|
||||
response_decompress: true,
|
||||
sni_host: None,
|
||||
connect_config: None,
|
||||
}
|
||||
.method(method)
|
||||
.uri(uri)
|
||||
|
@ -281,6 +283,15 @@ impl ClientRequest {
|
|||
self
|
||||
}
|
||||
|
||||
/// Set specific connector configuration for this request.
|
||||
///
|
||||
/// Not all config may be applied to the request, it depends on the connector and also
|
||||
/// if there is already a connection established.
|
||||
pub fn connect_config(mut self, config: ConnectConfig) -> Self {
|
||||
self.connect_config = Some(config);
|
||||
self
|
||||
}
|
||||
|
||||
/// Set request timeout. Overrides client wide timeout setting.
|
||||
///
|
||||
/// Request timeout is the total time before a response must be received.
|
||||
|
@ -332,6 +343,7 @@ impl ClientRequest {
|
|||
ServerName::Borrowed(r) => ServerName::Borrowed(r),
|
||||
ServerName::Owned(o) => ServerName::Borrowed(Rc::new(o)),
|
||||
}),
|
||||
connect_config: slf.connect_config.map(Rc::new),
|
||||
};
|
||||
|
||||
Ok(request)
|
||||
|
@ -353,6 +365,7 @@ impl ClientRequest {
|
|||
slf.timeout,
|
||||
&slf.config,
|
||||
slf.sni_host,
|
||||
slf.connect_config.map(Rc::new),
|
||||
body,
|
||||
)
|
||||
}
|
||||
|
@ -370,6 +383,7 @@ impl ClientRequest {
|
|||
slf.timeout,
|
||||
&slf.config,
|
||||
slf.sni_host,
|
||||
slf.connect_config.map(Rc::new),
|
||||
value,
|
||||
)
|
||||
}
|
||||
|
@ -389,6 +403,7 @@ impl ClientRequest {
|
|||
slf.timeout,
|
||||
&slf.config,
|
||||
slf.sni_host,
|
||||
slf.connect_config.map(Rc::new),
|
||||
value,
|
||||
)
|
||||
}
|
||||
|
@ -410,6 +425,7 @@ impl ClientRequest {
|
|||
slf.timeout,
|
||||
&slf.config,
|
||||
slf.sni_host,
|
||||
slf.connect_config.map(Rc::new),
|
||||
stream,
|
||||
)
|
||||
}
|
||||
|
@ -427,6 +443,7 @@ impl ClientRequest {
|
|||
slf.timeout,
|
||||
&slf.config,
|
||||
slf.sni_host,
|
||||
slf.connect_config.map(Rc::new),
|
||||
)
|
||||
}
|
||||
|
||||
|
|
|
@ -23,7 +23,7 @@ use serde::Serialize;
|
|||
|
||||
use crate::{
|
||||
any_body::AnyBody,
|
||||
client::{ClientConfig, ServerName},
|
||||
client::{ClientConfig, ConnectConfig, ServerName},
|
||||
error::{FreezeRequestError, InvalidUrl, SendRequestError},
|
||||
BoxError, ClientResponse, ConnectRequest, ConnectResponse,
|
||||
};
|
||||
|
@ -187,6 +187,7 @@ impl RequestSender {
|
|||
timeout: Option<Duration>,
|
||||
config: &ClientConfig,
|
||||
sni_host: Option<ServerName>,
|
||||
connect_config: Option<Rc<ConnectConfig>>,
|
||||
body: impl MessageBody + 'static,
|
||||
) -> SendClientRequest {
|
||||
let req = match self {
|
||||
|
@ -195,12 +196,14 @@ impl RequestSender {
|
|||
AnyBody::from_message_body(body).into_boxed(),
|
||||
addr,
|
||||
sni_host,
|
||||
connect_config,
|
||||
),
|
||||
RequestSender::Rc(head, extra_headers) => ConnectRequest::Client(
|
||||
RequestHeadType::Rc(head, extra_headers),
|
||||
AnyBody::from_message_body(body).into_boxed(),
|
||||
addr,
|
||||
sni_host,
|
||||
connect_config,
|
||||
),
|
||||
};
|
||||
|
||||
|
@ -216,6 +219,7 @@ impl RequestSender {
|
|||
timeout: Option<Duration>,
|
||||
config: &ClientConfig,
|
||||
sni_host: Option<ServerName>,
|
||||
connector_config: Option<Rc<ConnectConfig>>,
|
||||
value: impl Serialize,
|
||||
) -> SendClientRequest {
|
||||
let body = match serde_json::to_string(&value) {
|
||||
|
@ -227,7 +231,15 @@ impl RequestSender {
|
|||
return err.into();
|
||||
}
|
||||
|
||||
self.send_body(addr, response_decompress, timeout, config, sni_host, body)
|
||||
self.send_body(
|
||||
addr,
|
||||
response_decompress,
|
||||
timeout,
|
||||
config,
|
||||
sni_host,
|
||||
connector_config,
|
||||
body,
|
||||
)
|
||||
}
|
||||
|
||||
pub(crate) fn send_form(
|
||||
|
@ -237,6 +249,7 @@ impl RequestSender {
|
|||
timeout: Option<Duration>,
|
||||
config: &ClientConfig,
|
||||
sni_host: Option<ServerName>,
|
||||
connector_config: Option<Rc<ConnectConfig>>,
|
||||
value: impl Serialize,
|
||||
) -> SendClientRequest {
|
||||
let body = match serde_urlencoded::to_string(value) {
|
||||
|
@ -251,7 +264,15 @@ impl RequestSender {
|
|||
return err.into();
|
||||
}
|
||||
|
||||
self.send_body(addr, response_decompress, timeout, config, sni_host, body)
|
||||
self.send_body(
|
||||
addr,
|
||||
response_decompress,
|
||||
timeout,
|
||||
config,
|
||||
sni_host,
|
||||
connector_config,
|
||||
body,
|
||||
)
|
||||
}
|
||||
|
||||
pub(crate) fn send_stream<S, E>(
|
||||
|
@ -261,6 +282,7 @@ impl RequestSender {
|
|||
timeout: Option<Duration>,
|
||||
config: &ClientConfig,
|
||||
sni_host: Option<ServerName>,
|
||||
connector_config: Option<Rc<ConnectConfig>>,
|
||||
stream: S,
|
||||
) -> SendClientRequest
|
||||
where
|
||||
|
@ -273,6 +295,7 @@ impl RequestSender {
|
|||
timeout,
|
||||
config,
|
||||
sni_host,
|
||||
connector_config,
|
||||
BodyStream::new(stream),
|
||||
)
|
||||
}
|
||||
|
@ -284,8 +307,17 @@ impl RequestSender {
|
|||
timeout: Option<Duration>,
|
||||
config: &ClientConfig,
|
||||
sni_host: Option<ServerName>,
|
||||
connector_config: Option<Rc<ConnectConfig>>,
|
||||
) -> SendClientRequest {
|
||||
self.send_body(addr, response_decompress, timeout, config, sni_host, ())
|
||||
self.send_body(
|
||||
addr,
|
||||
response_decompress,
|
||||
timeout,
|
||||
config,
|
||||
sni_host,
|
||||
connector_config,
|
||||
(),
|
||||
)
|
||||
}
|
||||
|
||||
fn set_header_if_none<V>(&mut self, key: HeaderName, value: V) -> Result<(), HttpError>
|
||||
|
|
|
@ -26,7 +26,7 @@
|
|||
//! }
|
||||
//! ```
|
||||
|
||||
use std::{fmt, net::SocketAddr, str};
|
||||
use std::{fmt, net::SocketAddr, rc::Rc, str};
|
||||
|
||||
use actix_codec::Framed;
|
||||
pub use actix_http::ws::{CloseCode, CloseReason, Codec, Frame, Message};
|
||||
|
@ -38,7 +38,7 @@ use base64::prelude::*;
|
|||
#[cfg(feature = "cookies")]
|
||||
use crate::cookie::{Cookie, CookieJar};
|
||||
use crate::{
|
||||
client::{ClientConfig, ServerName},
|
||||
client::{ClientConfig, ConnectConfig, ServerName},
|
||||
connect::{BoxedSocket, ConnectRequest},
|
||||
error::{HttpError, InvalidUrl, SendRequestError, WsClientError},
|
||||
http::{
|
||||
|
@ -59,6 +59,7 @@ pub struct WebsocketsRequest {
|
|||
server_mode: bool,
|
||||
config: ClientConfig,
|
||||
sni_host: Option<ServerName>,
|
||||
connect_config: Option<ConnectConfig>,
|
||||
|
||||
#[cfg(feature = "cookies")]
|
||||
cookies: Option<CookieJar>,
|
||||
|
@ -98,6 +99,7 @@ impl WebsocketsRequest {
|
|||
#[cfg(feature = "cookies")]
|
||||
cookies: None,
|
||||
sni_host: None,
|
||||
connect_config: None,
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -110,6 +112,15 @@ impl WebsocketsRequest {
|
|||
self
|
||||
}
|
||||
|
||||
/// Set specific connector configuration for this request.
|
||||
///
|
||||
/// Not all config may be applied to the request, it depends on the connector and also
|
||||
/// if there is already a connection established.
|
||||
pub fn connector_config(mut self, config: ConnectConfig) -> Self {
|
||||
self.connect_config = Some(config);
|
||||
self
|
||||
}
|
||||
|
||||
/// Set supported WebSocket protocols
|
||||
pub fn protocols<U, V>(mut self, protos: U) -> Self
|
||||
where
|
||||
|
@ -346,7 +357,12 @@ impl WebsocketsRequest {
|
|||
let max_size = self.max_size;
|
||||
let server_mode = self.server_mode;
|
||||
|
||||
let req = ConnectRequest::Tunnel(head, self.addr, self.sni_host);
|
||||
let req = ConnectRequest::Tunnel(
|
||||
head,
|
||||
self.addr,
|
||||
self.sni_host,
|
||||
self.connect_config.map(Rc::new),
|
||||
);
|
||||
|
||||
let fut = self.config.connector.call(req);
|
||||
|
||||
|
|
Loading…
Reference in a new issue