From 47640170bb07f5bff12c5d7735ce2020fd7feb30 Mon Sep 17 00:00:00 2001 From: quininer Date: Tue, 19 Mar 2019 11:56:45 +0800 Subject: [PATCH] Add tcp_nodelay for Builder --- src/async_impl/client.rs | 14 +++++++++--- src/client.rs | 5 +++++ src/connect.rs | 46 +++++++++++++++++++++++----------------- 3 files changed, 43 insertions(+), 22 deletions(-) diff --git a/src/async_impl/client.rs b/src/async_impl/client.rs index 091e891..07438cf 100644 --- a/src/async_impl/client.rs +++ b/src/async_impl/client.rs @@ -81,6 +81,7 @@ struct Config { http2_only: bool, http1_title_case_headers: bool, local_address: Option, + nodelay: bool, } impl ClientBuilder { @@ -115,6 +116,7 @@ impl ClientBuilder { http2_only: false, http1_title_case_headers: false, local_address: None, + nodelay: false }, } } @@ -146,7 +148,7 @@ impl ClientBuilder { 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")] TlsBackend::Rustls => { @@ -175,12 +177,12 @@ impl ClientBuilder { 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"))] - Connector::new(proxies.clone(), config.local_address)? + Connector::new(proxies.clone(), config.local_address, config.nodelay)? }; 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. #[cfg(feature = "default-tls")] pub fn use_default_tls(mut self) -> ClientBuilder { diff --git a/src/client.rs b/src/client.rs index f4cf031..2cfd238 100644 --- a/src/client.rs +++ b/src/client.rs @@ -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. #[cfg(feature = "default-tls")] pub fn use_default_tls(self) -> ClientBuilder { diff --git a/src/connect.rs b/src/connect.rs index 3ec2f34..f34ec33 100644 --- a/src/connect.rs +++ b/src/connect.rs @@ -31,6 +31,8 @@ pub(crate) struct Connector { inner: Inner, proxies: Arc>, timeout: Option, + #[cfg(feature = "tls")] + nodelay: bool } enum Inner { @@ -48,13 +50,14 @@ enum Inner { impl Connector { #[cfg(not(feature = "tls"))] - pub(crate) fn new(proxies: Arc>, local_addr: T) -> ::Result + pub(crate) fn new(proxies: Arc>, local_addr: T, nodelay: bool) -> ::Result where T: Into> { let mut http = http_connector()?; http.set_local_address(local_addr.into()); + http.set_nodelay(nodelay); Ok(Connector { inner: Inner::Http(http), proxies, @@ -66,7 +69,8 @@ impl Connector { pub(crate) fn new_default_tls( tls: TlsConnectorBuilder, proxies: Arc>, - local_addr: T) -> ::Result + local_addr: T, + nodelay: bool) -> ::Result where T: Into>, { @@ -80,6 +84,7 @@ impl Connector { inner: Inner::DefaultTls(http, tls), proxies, timeout: None, + nodelay }) } @@ -87,7 +92,8 @@ impl Connector { pub(crate) fn new_rustls_tls( tls: rustls::ClientConfig, proxies: Arc>, - local_addr: T) -> ::Result + local_addr: T, + nodelay: bool) -> ::Result where T: Into>, { @@ -108,6 +114,7 @@ impl Connector { inner: Inner::RustlsTls { http, tls, tls_proxy }, proxies, timeout: None, + nodelay }) } @@ -134,6 +141,9 @@ impl Connect for Connector { type Future = Connecting; fn connect(&self, dst: Destination) -> Self::Future { + #[cfg(feature = "tls")] + let nodelay = self.nodelay; + macro_rules! timeout { ($future:expr) => { if let Some(dur) = self.timeout { @@ -163,33 +173,27 @@ impl Connect for Connector { Inner::Http(http) => connect!(http, $dst, $proxy), #[cfg(feature = "default-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) }, #[cfg(feature = "rustls-tls")] Inner::RustlsTls { http, tls, .. } => { - use ::rustls::Session; - let mut http = http.clone(); // Disable Nagle's algorithm for TLS handshake // // https://www.openssl.org/docs/man1.1.1/man3/SSL_connect.html#NOTES - if $dst.scheme() == "https" { - http.set_nodelay(true); - } + http.set_nodelay(nodelay || ($dst.scheme() == "https")); let http = ::hyper_rustls::HttpsConnector::from((http, tls.clone())); - timeout!(http.connect($dst) - .and_then(|(mut io, connected)| { - if let ::hyper_rustls::MaybeHttpsStream::Https(stream) = &mut io { - let (io, session) = stream.get_mut(); + .and_then(move |(io, connected)| { + if let ::hyper_rustls::MaybeHttpsStream::Https(stream) = &io { + let (io, _) = stream.get_ref(); - // keep nodelay for h2 - // - // https://http2.github.io/faq/#will-i-need-tcp_nodelay-for-my-http2-connections - if session.get_alpn_protocol() != Some(b"h2") { + if !nodelay { io.set_nodelay(false)?; } } @@ -227,7 +231,9 @@ impl Connect for Connector { let host = dst.host().to_owned(); 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(); return timeout!(http.connect(ndst).and_then(move |(conn, connected)| { trace!("tunneling HTTPS over proxy"); @@ -247,7 +253,9 @@ impl Connect for Connector { let host = dst.host().to_owned(); 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(); return timeout!(http.connect(ndst).and_then(move |(conn, connected)| { trace!("tunneling HTTPS over proxy");