Skip to content

Commit 8062714

Browse files
authored
feat(http1): Add http1_writev(bool) to client and server Builders
Restore a way to force queue writing strategy. Closes #2676
1 parent ab469eb commit 8062714

File tree

6 files changed

+99
-5
lines changed

6 files changed

+99
-5
lines changed

src/client/client.rs

+17
Original file line numberDiff line numberDiff line change
@@ -1022,6 +1022,23 @@ impl Builder {
10221022
self
10231023
}
10241024

1025+
/// Set whether HTTP/1 connections should try to use vectored writes,
1026+
/// or always flatten into a single buffer.
1027+
///
1028+
/// Note that setting this to false may mean more copies of body data,
1029+
/// but may also improve performance when an IO transport doesn't
1030+
/// support vectored writes well, such as most TLS implementations.
1031+
///
1032+
/// Setting this to true will force hyper to use queued strategy
1033+
/// which may eliminate unnecessary cloning on some TLS backends
1034+
///
1035+
/// Default is `auto`. In this mode hyper will try to guess which
1036+
/// mode to use
1037+
pub fn http1_writev(&mut self, enabled: bool) -> &mut Builder {
1038+
self.conn_builder.http1_writev(enabled);
1039+
self
1040+
}
1041+
10251042
/// Set whether HTTP/1 connections will write header names as title case at
10261043
/// the socket level.
10271044
///

src/client/conn.rs

+26
Original file line numberDiff line numberDiff line change
@@ -153,6 +153,7 @@ pub struct Builder {
153153
pub(super) exec: Exec,
154154
h09_responses: bool,
155155
h1_parser_config: ParserConfig,
156+
h1_writev: Option<bool>,
156157
h1_title_case_headers: bool,
157158
h1_preserve_header_case: bool,
158159
h1_read_buf_exact_size: Option<usize>,
@@ -535,6 +536,7 @@ impl Builder {
535536
Builder {
536537
exec: Exec::Default,
537538
h09_responses: false,
539+
h1_writev: None,
538540
h1_read_buf_exact_size: None,
539541
h1_parser_config: Default::default(),
540542
h1_title_case_headers: false,
@@ -596,6 +598,23 @@ impl Builder {
596598
self
597599
}
598600

601+
/// Set whether HTTP/1 connections should try to use vectored writes,
602+
/// or always flatten into a single buffer.
603+
///
604+
/// Note that setting this to false may mean more copies of body data,
605+
/// but may also improve performance when an IO transport doesn't
606+
/// support vectored writes well, such as most TLS implementations.
607+
///
608+
/// Setting this to true will force hyper to use queued strategy
609+
/// which may eliminate unnecessary cloning on some TLS backends
610+
///
611+
/// Default is `auto`. In this mode hyper will try to guess which
612+
/// mode to use
613+
pub fn http1_writev(&mut self, enabled: bool) -> &mut Builder {
614+
self.h1_writev = Some(enabled);
615+
self
616+
}
617+
599618
/// Set whether HTTP/1 connections will write header names as title case at
600619
/// the socket level.
601620
///
@@ -837,6 +856,13 @@ impl Builder {
837856
Proto::Http1 => {
838857
let mut conn = proto::Conn::new(io);
839858
conn.set_h1_parser_config(opts.h1_parser_config);
859+
if let Some(writev) = opts.h1_writev {
860+
if writev {
861+
conn.set_write_strategy_queue();
862+
} else {
863+
conn.set_write_strategy_flatten();
864+
}
865+
}
840866
if opts.h1_title_case_headers {
841867
conn.set_title_case_headers();
842868
}

src/proto/h1/conn.rs

+4-1
Original file line numberDiff line numberDiff line change
@@ -71,7 +71,6 @@ where
7171
self.io.set_flush_pipeline(enabled);
7272
}
7373

74-
#[cfg(test)]
7574
pub(crate) fn set_write_strategy_queue(&mut self) {
7675
self.io.set_write_strategy_queue();
7776
}
@@ -85,6 +84,10 @@ where
8584
self.io.set_read_buf_exact_size(sz);
8685
}
8786

87+
pub(crate) fn set_write_strategy_flatten(&mut self) {
88+
self.io.set_write_strategy_flatten();
89+
}
90+
8891
#[cfg(feature = "client")]
8992
pub(crate) fn set_h1_parser_config(&mut self, parser_config: ParserConfig) {
9093
self.state.h1_parser_config = parser_config;

src/proto/h1/io.rs

+4-4
Original file line numberDiff line numberDiff line change
@@ -97,16 +97,17 @@ where
9797
self.read_buf_strategy = ReadStrategy::Exact(sz);
9898
}
9999

100-
#[cfg(feature = "server")]
101-
fn set_write_strategy_flatten(&mut self) {
100+
pub(crate) fn set_write_strategy_flatten(&mut self) {
102101
// this should always be called only at construction time,
103102
// so this assert is here to catch myself
104103
debug_assert!(self.write_buf.queue.bufs_cnt() == 0);
105104
self.write_buf.set_strategy(WriteStrategy::Flatten);
106105
}
107106

108-
#[cfg(test)]
109107
pub(crate) fn set_write_strategy_queue(&mut self) {
108+
// this should always be called only at construction time,
109+
// so this assert is here to catch myself
110+
debug_assert!(self.write_buf.queue.bufs_cnt() == 0);
110111
self.write_buf.set_strategy(WriteStrategy::Queue);
111112
}
112113

@@ -520,7 +521,6 @@ impl<B> WriteBuf<B>
520521
where
521522
B: Buf,
522523
{
523-
#[cfg(feature = "server")]
524524
fn set_strategy(&mut self, strategy: WriteStrategy) {
525525
self.strategy = strategy;
526526
}

src/server/conn.rs

+30
Original file line numberDiff line numberDiff line change
@@ -103,6 +103,7 @@ pub struct Http<E = Exec> {
103103
h1_keep_alive: bool,
104104
h1_title_case_headers: bool,
105105
h1_preserve_header_case: bool,
106+
h1_writev: Option<bool>,
106107
#[cfg(feature = "http2")]
107108
h2_builder: proto::h2::server::Config,
108109
mode: ConnectionMode,
@@ -284,6 +285,7 @@ impl Http {
284285
h1_keep_alive: true,
285286
h1_title_case_headers: false,
286287
h1_preserve_header_case: false,
288+
h1_writev: None,
287289
#[cfg(feature = "http2")]
288290
h2_builder: Default::default(),
289291
mode: ConnectionMode::default(),
@@ -363,6 +365,26 @@ impl<E> Http<E> {
363365
self
364366
}
365367

368+
/// Set whether HTTP/1 connections should try to use vectored writes,
369+
/// or always flatten into a single buffer.
370+
///
371+
/// Note that setting this to false may mean more copies of body data,
372+
/// but may also improve performance when an IO transport doesn't
373+
/// support vectored writes well, such as most TLS implementations.
374+
///
375+
/// Setting this to true will force hyper to use queued strategy
376+
/// which may eliminate unnecessary cloning on some TLS backends
377+
///
378+
/// Default is `auto`. In this mode hyper will try to guess which
379+
/// mode to use
380+
#[inline]
381+
#[cfg(feature = "http1")]
382+
#[cfg_attr(docsrs, doc(cfg(feature = "http1")))]
383+
pub fn http1_writev(&mut self, val: bool) -> &mut Self {
384+
self.h1_writev = Some(val);
385+
self
386+
}
387+
366388
/// Sets whether HTTP2 is required.
367389
///
368390
/// Default is false
@@ -538,6 +560,7 @@ impl<E> Http<E> {
538560
h1_keep_alive: self.h1_keep_alive,
539561
h1_title_case_headers: self.h1_title_case_headers,
540562
h1_preserve_header_case: self.h1_preserve_header_case,
563+
h1_writev: self.h1_writev,
541564
#[cfg(feature = "http2")]
542565
h2_builder: self.h2_builder,
543566
mode: self.mode,
@@ -599,6 +622,13 @@ impl<E> Http<E> {
599622
if self.h1_preserve_header_case {
600623
conn.set_preserve_header_case();
601624
}
625+
if let Some(writev) = self.h1_writev {
626+
if writev {
627+
conn.set_write_strategy_queue();
628+
} else {
629+
conn.set_write_strategy_flatten();
630+
}
631+
}
602632
conn.set_flush_pipeline(self.pipeline_flush);
603633
if let Some(max) = self.max_buf_size {
604634
conn.set_max_buf_size(max);

src/server/server.rs

+18
Original file line numberDiff line numberDiff line change
@@ -258,6 +258,24 @@ impl<I, E> Builder<I, E> {
258258
self
259259
}
260260

261+
/// Set whether HTTP/1 connections should try to use vectored writes,
262+
/// or always flatten into a single buffer.
263+
///
264+
/// Note that setting this to false may mean more copies of body data,
265+
/// but may also improve performance when an IO transport doesn't
266+
/// support vectored writes well, such as most TLS implementations.
267+
///
268+
/// Setting this to true will force hyper to use queued strategy
269+
/// which may eliminate unnecessary cloning on some TLS backends
270+
///
271+
/// Default is `auto`. In this mode hyper will try to guess which
272+
/// mode to use
273+
#[cfg(feature = "http1")]
274+
pub fn http1_writev(mut self, enabled: bool) -> Self {
275+
self.protocol.http1_writev(enabled);
276+
self
277+
}
278+
261279
/// Set whether HTTP/1 connections will write header names as title case at
262280
/// the socket level.
263281
///

0 commit comments

Comments
 (0)