Add tcp_nodelay for Builder

This commit is contained in:
quininer
2019-03-19 11:56:45 +08:00
committed by Sean McArthur
parent f5e7e883c7
commit 47640170bb
3 changed files with 43 additions and 22 deletions

View File

@@ -81,6 +81,7 @@ struct Config {
http2_only: bool, http2_only: bool,
http1_title_case_headers: bool, http1_title_case_headers: bool,
local_address: Option<IpAddr>, local_address: Option<IpAddr>,
nodelay: bool,
} }
impl ClientBuilder { impl ClientBuilder {
@@ -115,6 +116,7 @@ impl ClientBuilder {
http2_only: false, http2_only: false,
http1_title_case_headers: false, http1_title_case_headers: false,
local_address: None, local_address: None,
nodelay: false
}, },
} }
} }
@@ -146,7 +148,7 @@ impl ClientBuilder {
id.add_to_native_tls(&mut tls)?; id.add_to_native_tls(&mut tls)?;
} }
Connector::new_default_tls(tls, proxies.clone(), config.local_address)? Connector::new_default_tls(tls, proxies.clone(), config.local_address, config.nodelay)?
}, },
#[cfg(feature = "rustls-tls")] #[cfg(feature = "rustls-tls")]
TlsBackend::Rustls => { TlsBackend::Rustls => {
@@ -175,12 +177,12 @@ impl ClientBuilder {
id.add_to_rustls(&mut tls)?; id.add_to_rustls(&mut tls)?;
} }
Connector::new_rustls_tls(tls, proxies.clone(), config.local_address)? Connector::new_rustls_tls(tls, proxies.clone(), config.local_address, config.nodelay)?
} }
} }
#[cfg(not(feature = "tls"))] #[cfg(not(feature = "tls"))]
Connector::new(proxies.clone(), config.local_address)? Connector::new(proxies.clone(), config.local_address, config.nodelay)?
}; };
connector.set_timeout(config.connect_timeout); connector.set_timeout(config.connect_timeout);
@@ -215,6 +217,12 @@ impl ClientBuilder {
}) })
} }
/// Set that all sockets have `SO_NODELAY` set to `true`.
pub fn tcp_nodelay(mut self) -> ClientBuilder {
self.config.nodelay = true;
self
}
/// Use native TLS backend. /// Use native TLS backend.
#[cfg(feature = "default-tls")] #[cfg(feature = "default-tls")]
pub fn use_default_tls(mut self) -> ClientBuilder { pub fn use_default_tls(mut self) -> ClientBuilder {

View File

@@ -84,6 +84,11 @@ impl ClientBuilder {
}) })
} }
/// Set that all sockets have `SO_NODELAY` set to `true`.
pub fn tcp_nodelay(self) -> ClientBuilder {
self.with_inner(move |inner| inner.tcp_nodelay())
}
/// Use native TLS backend. /// Use native TLS backend.
#[cfg(feature = "default-tls")] #[cfg(feature = "default-tls")]
pub fn use_default_tls(self) -> ClientBuilder { pub fn use_default_tls(self) -> ClientBuilder {

View File

@@ -31,6 +31,8 @@ pub(crate) struct Connector {
inner: Inner, inner: Inner,
proxies: Arc<Vec<Proxy>>, proxies: Arc<Vec<Proxy>>,
timeout: Option<Duration>, timeout: Option<Duration>,
#[cfg(feature = "tls")]
nodelay: bool
} }
enum Inner { enum Inner {
@@ -48,13 +50,14 @@ enum Inner {
impl Connector { impl Connector {
#[cfg(not(feature = "tls"))] #[cfg(not(feature = "tls"))]
pub(crate) fn new<T>(proxies: Arc<Vec<Proxy>>, local_addr: T) -> ::Result<Connector> pub(crate) fn new<T>(proxies: Arc<Vec<Proxy>>, local_addr: T, nodelay: bool) -> ::Result<Connector>
where where
T: Into<Option<IpAddr>> T: Into<Option<IpAddr>>
{ {
let mut http = http_connector()?; let mut http = http_connector()?;
http.set_local_address(local_addr.into()); http.set_local_address(local_addr.into());
http.set_nodelay(nodelay);
Ok(Connector { Ok(Connector {
inner: Inner::Http(http), inner: Inner::Http(http),
proxies, proxies,
@@ -66,7 +69,8 @@ impl Connector {
pub(crate) fn new_default_tls<T>( pub(crate) fn new_default_tls<T>(
tls: TlsConnectorBuilder, tls: TlsConnectorBuilder,
proxies: Arc<Vec<Proxy>>, proxies: Arc<Vec<Proxy>>,
local_addr: T) -> ::Result<Connector> local_addr: T,
nodelay: bool) -> ::Result<Connector>
where where
T: Into<Option<IpAddr>>, T: Into<Option<IpAddr>>,
{ {
@@ -80,6 +84,7 @@ impl Connector {
inner: Inner::DefaultTls(http, tls), inner: Inner::DefaultTls(http, tls),
proxies, proxies,
timeout: None, timeout: None,
nodelay
}) })
} }
@@ -87,7 +92,8 @@ impl Connector {
pub(crate) fn new_rustls_tls<T>( pub(crate) fn new_rustls_tls<T>(
tls: rustls::ClientConfig, tls: rustls::ClientConfig,
proxies: Arc<Vec<Proxy>>, proxies: Arc<Vec<Proxy>>,
local_addr: T) -> ::Result<Connector> local_addr: T,
nodelay: bool) -> ::Result<Connector>
where where
T: Into<Option<IpAddr>>, T: Into<Option<IpAddr>>,
{ {
@@ -108,6 +114,7 @@ impl Connector {
inner: Inner::RustlsTls { http, tls, tls_proxy }, inner: Inner::RustlsTls { http, tls, tls_proxy },
proxies, proxies,
timeout: None, timeout: None,
nodelay
}) })
} }
@@ -134,6 +141,9 @@ impl Connect for Connector {
type Future = Connecting; type Future = Connecting;
fn connect(&self, dst: Destination) -> Self::Future { fn connect(&self, dst: Destination) -> Self::Future {
#[cfg(feature = "tls")]
let nodelay = self.nodelay;
macro_rules! timeout { macro_rules! timeout {
($future:expr) => { ($future:expr) => {
if let Some(dur) = self.timeout { if let Some(dur) = self.timeout {
@@ -163,33 +173,27 @@ impl Connect for Connector {
Inner::Http(http) => connect!(http, $dst, $proxy), Inner::Http(http) => connect!(http, $dst, $proxy),
#[cfg(feature = "default-tls")] #[cfg(feature = "default-tls")]
Inner::DefaultTls(http, tls) => { Inner::DefaultTls(http, tls) => {
let http = ::hyper_tls::HttpsConnector::from((http.clone(), tls.clone())); let mut http = http.clone();
http.set_nodelay(nodelay);
let http = ::hyper_tls::HttpsConnector::from((http, tls.clone()));
connect!(http, $dst, $proxy) connect!(http, $dst, $proxy)
}, },
#[cfg(feature = "rustls-tls")] #[cfg(feature = "rustls-tls")]
Inner::RustlsTls { http, tls, .. } => { Inner::RustlsTls { http, tls, .. } => {
use ::rustls::Session;
let mut http = http.clone(); let mut http = http.clone();
// Disable Nagle's algorithm for TLS handshake // Disable Nagle's algorithm for TLS handshake
// //
// https://www.openssl.org/docs/man1.1.1/man3/SSL_connect.html#NOTES // https://www.openssl.org/docs/man1.1.1/man3/SSL_connect.html#NOTES
if $dst.scheme() == "https" { http.set_nodelay(nodelay || ($dst.scheme() == "https"));
http.set_nodelay(true);
}
let http = ::hyper_rustls::HttpsConnector::from((http, tls.clone())); let http = ::hyper_rustls::HttpsConnector::from((http, tls.clone()));
timeout!(http.connect($dst) timeout!(http.connect($dst)
.and_then(|(mut io, connected)| { .and_then(move |(io, connected)| {
if let ::hyper_rustls::MaybeHttpsStream::Https(stream) = &mut io { if let ::hyper_rustls::MaybeHttpsStream::Https(stream) = &io {
let (io, session) = stream.get_mut(); let (io, _) = stream.get_ref();
// keep nodelay for h2 if !nodelay {
//
// https://http2.github.io/faq/#will-i-need-tcp_nodelay-for-my-http2-connections
if session.get_alpn_protocol() != Some(b"h2") {
io.set_nodelay(false)?; io.set_nodelay(false)?;
} }
} }
@@ -227,7 +231,9 @@ impl Connect for Connector {
let host = dst.host().to_owned(); let host = dst.host().to_owned();
let port = dst.port().unwrap_or(443); let port = dst.port().unwrap_or(443);
let http = ::hyper_tls::HttpsConnector::from((http.clone(), tls.clone())); let mut http = http.clone();
http.set_nodelay(nodelay);
let http = ::hyper_tls::HttpsConnector::from((http, tls.clone()));
let tls = tls.clone(); let tls = tls.clone();
return timeout!(http.connect(ndst).and_then(move |(conn, connected)| { return timeout!(http.connect(ndst).and_then(move |(conn, connected)| {
trace!("tunneling HTTPS over proxy"); trace!("tunneling HTTPS over proxy");
@@ -247,7 +253,9 @@ impl Connect for Connector {
let host = dst.host().to_owned(); let host = dst.host().to_owned();
let port = dst.port().unwrap_or(443); let port = dst.port().unwrap_or(443);
let http = ::hyper_rustls::HttpsConnector::from((http.clone(), tls_proxy.clone())); let mut http = http.clone();
http.set_nodelay(nodelay);
let http = ::hyper_rustls::HttpsConnector::from((http, tls_proxy.clone()));
let tls = tls.clone(); let tls = tls.clone();
return timeout!(http.connect(ndst).and_then(move |(conn, connected)| { return timeout!(http.connect(ndst).and_then(move |(conn, connected)| {
trace!("tunneling HTTPS over proxy"); trace!("tunneling HTTPS over proxy");