feat(http1): Add http1_writev(bool) to client and server Builders
Restore a way to force queue writing strategy. Closes #2676
This commit is contained in:
@@ -1022,6 +1022,23 @@ impl Builder {
|
|||||||
self
|
self
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Set whether HTTP/1 connections should try to use vectored writes,
|
||||||
|
/// or always flatten into a single buffer.
|
||||||
|
///
|
||||||
|
/// Note that setting this to false may mean more copies of body data,
|
||||||
|
/// but may also improve performance when an IO transport doesn't
|
||||||
|
/// support vectored writes well, such as most TLS implementations.
|
||||||
|
///
|
||||||
|
/// Setting this to true will force hyper to use queued strategy
|
||||||
|
/// which may eliminate unnecessary cloning on some TLS backends
|
||||||
|
///
|
||||||
|
/// Default is `auto`. In this mode hyper will try to guess which
|
||||||
|
/// mode to use
|
||||||
|
pub fn http1_writev(&mut self, enabled: bool) -> &mut Builder {
|
||||||
|
self.conn_builder.http1_writev(enabled);
|
||||||
|
self
|
||||||
|
}
|
||||||
|
|
||||||
/// Set whether HTTP/1 connections will write header names as title case at
|
/// Set whether HTTP/1 connections will write header names as title case at
|
||||||
/// the socket level.
|
/// the socket level.
|
||||||
///
|
///
|
||||||
|
|||||||
@@ -153,6 +153,7 @@ pub struct Builder {
|
|||||||
pub(super) exec: Exec,
|
pub(super) exec: Exec,
|
||||||
h09_responses: bool,
|
h09_responses: bool,
|
||||||
h1_parser_config: ParserConfig,
|
h1_parser_config: ParserConfig,
|
||||||
|
h1_writev: Option<bool>,
|
||||||
h1_title_case_headers: bool,
|
h1_title_case_headers: bool,
|
||||||
h1_preserve_header_case: bool,
|
h1_preserve_header_case: bool,
|
||||||
h1_read_buf_exact_size: Option<usize>,
|
h1_read_buf_exact_size: Option<usize>,
|
||||||
@@ -535,6 +536,7 @@ impl Builder {
|
|||||||
Builder {
|
Builder {
|
||||||
exec: Exec::Default,
|
exec: Exec::Default,
|
||||||
h09_responses: false,
|
h09_responses: false,
|
||||||
|
h1_writev: None,
|
||||||
h1_read_buf_exact_size: None,
|
h1_read_buf_exact_size: None,
|
||||||
h1_parser_config: Default::default(),
|
h1_parser_config: Default::default(),
|
||||||
h1_title_case_headers: false,
|
h1_title_case_headers: false,
|
||||||
@@ -596,6 +598,23 @@ impl Builder {
|
|||||||
self
|
self
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Set whether HTTP/1 connections should try to use vectored writes,
|
||||||
|
/// or always flatten into a single buffer.
|
||||||
|
///
|
||||||
|
/// Note that setting this to false may mean more copies of body data,
|
||||||
|
/// but may also improve performance when an IO transport doesn't
|
||||||
|
/// support vectored writes well, such as most TLS implementations.
|
||||||
|
///
|
||||||
|
/// Setting this to true will force hyper to use queued strategy
|
||||||
|
/// which may eliminate unnecessary cloning on some TLS backends
|
||||||
|
///
|
||||||
|
/// Default is `auto`. In this mode hyper will try to guess which
|
||||||
|
/// mode to use
|
||||||
|
pub fn http1_writev(&mut self, enabled: bool) -> &mut Builder {
|
||||||
|
self.h1_writev = Some(enabled);
|
||||||
|
self
|
||||||
|
}
|
||||||
|
|
||||||
/// Set whether HTTP/1 connections will write header names as title case at
|
/// Set whether HTTP/1 connections will write header names as title case at
|
||||||
/// the socket level.
|
/// the socket level.
|
||||||
///
|
///
|
||||||
@@ -837,6 +856,13 @@ impl Builder {
|
|||||||
Proto::Http1 => {
|
Proto::Http1 => {
|
||||||
let mut conn = proto::Conn::new(io);
|
let mut conn = proto::Conn::new(io);
|
||||||
conn.set_h1_parser_config(opts.h1_parser_config);
|
conn.set_h1_parser_config(opts.h1_parser_config);
|
||||||
|
if let Some(writev) = opts.h1_writev {
|
||||||
|
if writev {
|
||||||
|
conn.set_write_strategy_queue();
|
||||||
|
} else {
|
||||||
|
conn.set_write_strategy_flatten();
|
||||||
|
}
|
||||||
|
}
|
||||||
if opts.h1_title_case_headers {
|
if opts.h1_title_case_headers {
|
||||||
conn.set_title_case_headers();
|
conn.set_title_case_headers();
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -71,7 +71,6 @@ where
|
|||||||
self.io.set_flush_pipeline(enabled);
|
self.io.set_flush_pipeline(enabled);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(test)]
|
|
||||||
pub(crate) fn set_write_strategy_queue(&mut self) {
|
pub(crate) fn set_write_strategy_queue(&mut self) {
|
||||||
self.io.set_write_strategy_queue();
|
self.io.set_write_strategy_queue();
|
||||||
}
|
}
|
||||||
@@ -85,6 +84,10 @@ where
|
|||||||
self.io.set_read_buf_exact_size(sz);
|
self.io.set_read_buf_exact_size(sz);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub(crate) fn set_write_strategy_flatten(&mut self) {
|
||||||
|
self.io.set_write_strategy_flatten();
|
||||||
|
}
|
||||||
|
|
||||||
#[cfg(feature = "client")]
|
#[cfg(feature = "client")]
|
||||||
pub(crate) fn set_h1_parser_config(&mut self, parser_config: ParserConfig) {
|
pub(crate) fn set_h1_parser_config(&mut self, parser_config: ParserConfig) {
|
||||||
self.state.h1_parser_config = parser_config;
|
self.state.h1_parser_config = parser_config;
|
||||||
|
|||||||
@@ -97,16 +97,17 @@ where
|
|||||||
self.read_buf_strategy = ReadStrategy::Exact(sz);
|
self.read_buf_strategy = ReadStrategy::Exact(sz);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(feature = "server")]
|
pub(crate) fn set_write_strategy_flatten(&mut self) {
|
||||||
fn set_write_strategy_flatten(&mut self) {
|
|
||||||
// this should always be called only at construction time,
|
// this should always be called only at construction time,
|
||||||
// so this assert is here to catch myself
|
// so this assert is here to catch myself
|
||||||
debug_assert!(self.write_buf.queue.bufs_cnt() == 0);
|
debug_assert!(self.write_buf.queue.bufs_cnt() == 0);
|
||||||
self.write_buf.set_strategy(WriteStrategy::Flatten);
|
self.write_buf.set_strategy(WriteStrategy::Flatten);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(test)]
|
|
||||||
pub(crate) fn set_write_strategy_queue(&mut self) {
|
pub(crate) fn set_write_strategy_queue(&mut self) {
|
||||||
|
// this should always be called only at construction time,
|
||||||
|
// so this assert is here to catch myself
|
||||||
|
debug_assert!(self.write_buf.queue.bufs_cnt() == 0);
|
||||||
self.write_buf.set_strategy(WriteStrategy::Queue);
|
self.write_buf.set_strategy(WriteStrategy::Queue);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -520,7 +521,6 @@ impl<B> WriteBuf<B>
|
|||||||
where
|
where
|
||||||
B: Buf,
|
B: Buf,
|
||||||
{
|
{
|
||||||
#[cfg(feature = "server")]
|
|
||||||
fn set_strategy(&mut self, strategy: WriteStrategy) {
|
fn set_strategy(&mut self, strategy: WriteStrategy) {
|
||||||
self.strategy = strategy;
|
self.strategy = strategy;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -103,6 +103,7 @@ pub struct Http<E = Exec> {
|
|||||||
h1_keep_alive: bool,
|
h1_keep_alive: bool,
|
||||||
h1_title_case_headers: bool,
|
h1_title_case_headers: bool,
|
||||||
h1_preserve_header_case: bool,
|
h1_preserve_header_case: bool,
|
||||||
|
h1_writev: Option<bool>,
|
||||||
#[cfg(feature = "http2")]
|
#[cfg(feature = "http2")]
|
||||||
h2_builder: proto::h2::server::Config,
|
h2_builder: proto::h2::server::Config,
|
||||||
mode: ConnectionMode,
|
mode: ConnectionMode,
|
||||||
@@ -284,6 +285,7 @@ impl Http {
|
|||||||
h1_keep_alive: true,
|
h1_keep_alive: true,
|
||||||
h1_title_case_headers: false,
|
h1_title_case_headers: false,
|
||||||
h1_preserve_header_case: false,
|
h1_preserve_header_case: false,
|
||||||
|
h1_writev: None,
|
||||||
#[cfg(feature = "http2")]
|
#[cfg(feature = "http2")]
|
||||||
h2_builder: Default::default(),
|
h2_builder: Default::default(),
|
||||||
mode: ConnectionMode::default(),
|
mode: ConnectionMode::default(),
|
||||||
@@ -363,6 +365,26 @@ impl<E> Http<E> {
|
|||||||
self
|
self
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Set whether HTTP/1 connections should try to use vectored writes,
|
||||||
|
/// or always flatten into a single buffer.
|
||||||
|
///
|
||||||
|
/// Note that setting this to false may mean more copies of body data,
|
||||||
|
/// but may also improve performance when an IO transport doesn't
|
||||||
|
/// support vectored writes well, such as most TLS implementations.
|
||||||
|
///
|
||||||
|
/// Setting this to true will force hyper to use queued strategy
|
||||||
|
/// which may eliminate unnecessary cloning on some TLS backends
|
||||||
|
///
|
||||||
|
/// Default is `auto`. In this mode hyper will try to guess which
|
||||||
|
/// mode to use
|
||||||
|
#[inline]
|
||||||
|
#[cfg(feature = "http1")]
|
||||||
|
#[cfg_attr(docsrs, doc(cfg(feature = "http1")))]
|
||||||
|
pub fn http1_writev(&mut self, val: bool) -> &mut Self {
|
||||||
|
self.h1_writev = Some(val);
|
||||||
|
self
|
||||||
|
}
|
||||||
|
|
||||||
/// Sets whether HTTP2 is required.
|
/// Sets whether HTTP2 is required.
|
||||||
///
|
///
|
||||||
/// Default is false
|
/// Default is false
|
||||||
@@ -538,6 +560,7 @@ impl<E> Http<E> {
|
|||||||
h1_keep_alive: self.h1_keep_alive,
|
h1_keep_alive: self.h1_keep_alive,
|
||||||
h1_title_case_headers: self.h1_title_case_headers,
|
h1_title_case_headers: self.h1_title_case_headers,
|
||||||
h1_preserve_header_case: self.h1_preserve_header_case,
|
h1_preserve_header_case: self.h1_preserve_header_case,
|
||||||
|
h1_writev: self.h1_writev,
|
||||||
#[cfg(feature = "http2")]
|
#[cfg(feature = "http2")]
|
||||||
h2_builder: self.h2_builder,
|
h2_builder: self.h2_builder,
|
||||||
mode: self.mode,
|
mode: self.mode,
|
||||||
@@ -599,6 +622,13 @@ impl<E> Http<E> {
|
|||||||
if self.h1_preserve_header_case {
|
if self.h1_preserve_header_case {
|
||||||
conn.set_preserve_header_case();
|
conn.set_preserve_header_case();
|
||||||
}
|
}
|
||||||
|
if let Some(writev) = self.h1_writev {
|
||||||
|
if writev {
|
||||||
|
conn.set_write_strategy_queue();
|
||||||
|
} else {
|
||||||
|
conn.set_write_strategy_flatten();
|
||||||
|
}
|
||||||
|
}
|
||||||
conn.set_flush_pipeline(self.pipeline_flush);
|
conn.set_flush_pipeline(self.pipeline_flush);
|
||||||
if let Some(max) = self.max_buf_size {
|
if let Some(max) = self.max_buf_size {
|
||||||
conn.set_max_buf_size(max);
|
conn.set_max_buf_size(max);
|
||||||
|
|||||||
@@ -258,6 +258,24 @@ impl<I, E> Builder<I, E> {
|
|||||||
self
|
self
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Set whether HTTP/1 connections should try to use vectored writes,
|
||||||
|
/// or always flatten into a single buffer.
|
||||||
|
///
|
||||||
|
/// Note that setting this to false may mean more copies of body data,
|
||||||
|
/// but may also improve performance when an IO transport doesn't
|
||||||
|
/// support vectored writes well, such as most TLS implementations.
|
||||||
|
///
|
||||||
|
/// Setting this to true will force hyper to use queued strategy
|
||||||
|
/// which may eliminate unnecessary cloning on some TLS backends
|
||||||
|
///
|
||||||
|
/// Default is `auto`. In this mode hyper will try to guess which
|
||||||
|
/// mode to use
|
||||||
|
#[cfg(feature = "http1")]
|
||||||
|
pub fn http1_writev(mut self, enabled: bool) -> Self {
|
||||||
|
self.protocol.http1_writev(enabled);
|
||||||
|
self
|
||||||
|
}
|
||||||
|
|
||||||
/// Set whether HTTP/1 connections will write header names as title case at
|
/// Set whether HTTP/1 connections will write header names as title case at
|
||||||
/// the socket level.
|
/// the socket level.
|
||||||
///
|
///
|
||||||
|
|||||||
Reference in New Issue
Block a user