Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
15 changes: 15 additions & 0 deletions src/client/client.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1002,6 +1002,21 @@ impl Builder {
self
}

/// Set whether to disable keep alive for HTTP/1.0.
///
/// Currently, keep alive for HTTP/1.0 is supported if Connection: keep-alive is set for
/// either `Request` or `Response`. If this is enabled, enforcing Connection: close for
/// HTTP/1.0 `Request` or `Response` to make sure HTTP/1.0 connection drops and will not be
/// put back to H1 connection pool.
///
/// Note that this setting does not affect HTTP/2.
///
/// Default is false.
pub fn http10_disable_keep_alive(&mut self, disable: bool) -> &mut Self {
self.conn_builder.http10_disable_keep_alive(disable);
self
}

// HTTP/1 options

/// Sets the exact size of the read buffer to *always* use.
Expand Down
18 changes: 18 additions & 0 deletions src/client/conn.rs
Original file line number Diff line number Diff line change
Expand Up @@ -194,6 +194,7 @@ pub struct Builder {
h1_max_buf_size: Option<usize>,
#[cfg(feature = "ffi")]
h1_headers_raw: bool,
h10_disable_keep_alive: bool,
#[cfg(feature = "http2")]
h2_builder: proto::h2::client::Config,
version: Proto,
Expand Down Expand Up @@ -605,6 +606,7 @@ impl Builder {
h1_max_buf_size: None,
#[cfg(feature = "ffi")]
h1_headers_raw: false,
h10_disable_keep_alive: false,
#[cfg(feature = "http2")]
h2_builder: Default::default(),
#[cfg(feature = "http1")]
Expand Down Expand Up @@ -817,6 +819,21 @@ impl Builder {
self
}

/// Set whether to disable keep alive for HTTP/1.0.
///
/// Currently, keep alive for HTTP/1.0 is supported if Connection: keep-alive is set for
/// either `Request` or `Response`. If this is enabled, enforcing Connection: close for
/// HTTP/1.0 `Request` or `Response` to make sure HTTP/1.0 connection drops and will not be
/// put back to H1 connection pool.
///
/// Note that this setting does not affect HTTP/2.
///
/// Default is false.
pub fn http10_disable_keep_alive(&mut self, disable: bool) -> &mut Self {
self.h10_disable_keep_alive = disable;
self
}

/// Sets whether HTTP2 is required.
///
/// Default is false.
Expand Down Expand Up @@ -1019,6 +1036,7 @@ impl Builder {
conn.set_write_strategy_flatten();
}
}
conn.set_http10_disable_keep_alive(opts.h10_disable_keep_alive);
if opts.h1_title_case_headers {
conn.set_title_case_headers();
}
Expand Down
3 changes: 3 additions & 0 deletions src/client/conn/http1.rs
Original file line number Diff line number Diff line change
Expand Up @@ -119,6 +119,7 @@ pub struct Builder {
h1_preserve_header_order: bool,
h1_read_buf_exact_size: Option<usize>,
h1_max_buf_size: Option<usize>,
h10_disable_keep_alive: bool,
}

/// Returns a handshake future over some IO.
Expand Down Expand Up @@ -305,6 +306,7 @@ impl Builder {
#[cfg(feature = "ffi")]
h1_preserve_header_order: false,
h1_max_buf_size: None,
h10_disable_keep_alive: false,
}
}

Expand Down Expand Up @@ -508,6 +510,7 @@ impl Builder {
conn.set_write_strategy_flatten();
}
}
conn.set_http10_disable_keep_alive(opts.h10_disable_keep_alive);
if opts.h1_title_case_headers {
conn.set_title_case_headers();
}
Expand Down
15 changes: 14 additions & 1 deletion src/proto/h1/conn.rs
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,7 @@ where
cached_headers: None,
error: None,
keep_alive: KA::Busy,
h10_disable_keep_alive: false,
method: None,
h1_parser_config: ParserConfig::default(),
#[cfg(all(feature = "server", feature = "runtime"))]
Expand Down Expand Up @@ -130,6 +131,10 @@ where
self.state.h1_header_read_timeout = Some(val);
}

pub(crate) fn set_http10_disable_keep_alive(&mut self, disable: bool) {
self.state.h10_disable_keep_alive = disable;
}

#[cfg(feature = "server")]
pub(crate) fn set_allow_half_close(&mut self) {
self.state.allow_half_close = true;
Expand Down Expand Up @@ -208,6 +213,7 @@ where
#[cfg(feature = "ffi")]
preserve_header_order: self.state.preserve_header_order,
h09_responses: self.state.h09_responses,
h10_disable_keep_alive: self.state.h10_disable_keep_alive,
#[cfg(feature = "ffi")]
on_informational: &mut self.state.on_informational,
#[cfg(feature = "ffi")]
Expand Down Expand Up @@ -614,7 +620,13 @@ where
// If we know the remote speaks an older version, we try to fix up any messages
// to work with our older peer.
fn enforce_version(&mut self, head: &mut MessageHead<T::Outgoing>) {
if let Version::HTTP_10 = self.state.version {
// if h10_disable_keep_alive is set, force http/1.0 connection header to close.
// this function is only called in encode_head.
if self.state.h10_disable_keep_alive && head.version == Version::HTTP_10 {
self.state.disable_keep_alive();
head.headers
.insert(CONNECTION, HeaderValue::from_static("close"));
} else if let Version::HTTP_10 = self.state.version {
// Fixes response or connection when keep-alive header is not present
self.fix_keep_alive(head);
// If the remote only knows HTTP/1.0, we should force ourselves
Expand Down Expand Up @@ -816,6 +828,7 @@ struct State {
error: Option<crate::Error>,
/// Current keep-alive status.
keep_alive: KA,
h10_disable_keep_alive: bool,
/// If mid-message, the HTTP Method that started it.
///
/// This is used to know things such as if the message can include
Expand Down
2 changes: 2 additions & 0 deletions src/proto/h1/io.rs
Original file line number Diff line number Diff line change
Expand Up @@ -201,6 +201,7 @@ where
#[cfg(feature = "ffi")]
preserve_header_order: parse_ctx.preserve_header_order,
h09_responses: parse_ctx.h09_responses,
h10_disable_keep_alive: parse_ctx.h10_disable_keep_alive,
#[cfg(feature = "ffi")]
on_informational: parse_ctx.on_informational,
#[cfg(feature = "ffi")]
Expand Down Expand Up @@ -755,6 +756,7 @@ mod tests {
#[cfg(feature = "ffi")]
preserve_header_order: false,
h09_responses: false,
h10_disable_keep_alive: false,
#[cfg(feature = "ffi")]
on_informational: &mut None,
#[cfg(feature = "ffi")]
Expand Down
1 change: 1 addition & 0 deletions src/proto/h1/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -86,6 +86,7 @@ pub(crate) struct ParseContext<'a> {
#[cfg(feature = "ffi")]
preserve_header_order: bool,
h09_responses: bool,
h10_disable_keep_alive: bool,
#[cfg(feature = "ffi")]
on_informational: &'a mut Option<crate::ffi::OnInformational>,
#[cfg(feature = "ffi")]
Expand Down
38 changes: 34 additions & 4 deletions src/proto/h1/role.rs
Original file line number Diff line number Diff line change
Expand Up @@ -262,7 +262,7 @@ impl Http1Transaction for Server {
// SAFETY: array is valid up to `headers_len`
let header = unsafe { &*header.as_ptr() };
let name = header_name!(&slice[header.name.0..header.name.1]);
let value = header_value!(slice.slice(header.value.0..header.value.1));
let mut value = header_value!(slice.slice(header.value.0..header.value.1));

match name {
header::TRANSFER_ENCODING => {
Expand Down Expand Up @@ -309,7 +309,14 @@ impl Http1Transaction for Server {
keep_alive = !headers::connection_close(&value);
} else {
// HTTP/1.0
keep_alive = headers::connection_keep_alive(&value);
if ctx.h10_disable_keep_alive {
// if h10_disable_keep_alive is set, disable keep_alive,
// read and parsed the connection header as close
keep_alive = false;
value = HeaderValue::from_static("close");
} else {
keep_alive = headers::connection_keep_alive(&value);
}
}
}
header::EXPECT => {
Expand Down Expand Up @@ -1057,7 +1064,7 @@ impl Http1Transaction for Client {
// SAFETY: array is valid up to `headers_len`
let header = unsafe { &*header.as_ptr() };
let name = header_name!(&slice[header.name.0..header.name.1]);
let value = header_value!(slice.slice(header.value.0..header.value.1));
let mut value = header_value!(slice.slice(header.value.0..header.value.1));

if let header::CONNECTION = name {
// keep_alive was previously set to default for Version
Expand All @@ -1066,7 +1073,14 @@ impl Http1Transaction for Client {
keep_alive = !headers::connection_close(&value);
} else {
// HTTP/1.0
keep_alive = headers::connection_keep_alive(&value);
if ctx.h10_disable_keep_alive {
// if h10_disable_keep_alive is set, disable keep_alive,
// read and parsed the connection header as close
keep_alive = false;
value = HeaderValue::from_static("close");
} else {
keep_alive = headers::connection_keep_alive(&value);
}
}
}

Expand Down Expand Up @@ -1565,6 +1579,7 @@ mod tests {
#[cfg(feature = "ffi")]
preserve_header_order: false,
h09_responses: false,
h10_disable_keep_alive: false,
#[cfg(feature = "ffi")]
on_informational: &mut None,
#[cfg(feature = "ffi")]
Expand Down Expand Up @@ -1600,6 +1615,7 @@ mod tests {
#[cfg(feature = "ffi")]
preserve_header_order: false,
h09_responses: false,
h10_disable_keep_alive: false,
#[cfg(feature = "ffi")]
on_informational: &mut None,
#[cfg(feature = "ffi")]
Expand Down Expand Up @@ -1630,6 +1646,7 @@ mod tests {
#[cfg(feature = "ffi")]
preserve_header_order: false,
h09_responses: false,
h10_disable_keep_alive: false,
#[cfg(feature = "ffi")]
on_informational: &mut None,
#[cfg(feature = "ffi")]
Expand Down Expand Up @@ -1658,6 +1675,7 @@ mod tests {
#[cfg(feature = "ffi")]
preserve_header_order: false,
h09_responses: true,
h10_disable_keep_alive: false,
#[cfg(feature = "ffi")]
on_informational: &mut None,
#[cfg(feature = "ffi")]
Expand Down Expand Up @@ -1688,6 +1706,7 @@ mod tests {
#[cfg(feature = "ffi")]
preserve_header_order: false,
h09_responses: false,
h10_disable_keep_alive: false,
#[cfg(feature = "ffi")]
on_informational: &mut None,
#[cfg(feature = "ffi")]
Expand Down Expand Up @@ -1722,6 +1741,7 @@ mod tests {
#[cfg(feature = "ffi")]
preserve_header_order: false,
h09_responses: false,
h10_disable_keep_alive: false,
#[cfg(feature = "ffi")]
on_informational: &mut None,
#[cfg(feature = "ffi")]
Expand Down Expand Up @@ -1753,6 +1773,7 @@ mod tests {
#[cfg(feature = "ffi")]
preserve_header_order: false,
h09_responses: false,
h10_disable_keep_alive: false,
#[cfg(feature = "ffi")]
on_informational: &mut None,
#[cfg(feature = "ffi")]
Expand All @@ -1779,6 +1800,7 @@ mod tests {
#[cfg(feature = "ffi")]
preserve_header_order: false,
h09_responses: false,
h10_disable_keep_alive: false,
#[cfg(feature = "ffi")]
on_informational: &mut None,
#[cfg(feature = "ffi")]
Expand Down Expand Up @@ -1826,6 +1848,7 @@ mod tests {
#[cfg(feature = "ffi")]
preserve_header_order: false,
h09_responses: false,
h10_disable_keep_alive: false,
#[cfg(feature = "ffi")]
on_informational: &mut None,
#[cfg(feature = "ffi")]
Expand Down Expand Up @@ -1854,6 +1877,7 @@ mod tests {
#[cfg(feature = "ffi")]
preserve_header_order: false,
h09_responses: false,
h10_disable_keep_alive: false,
#[cfg(feature = "ffi")]
on_informational: &mut None,
#[cfg(feature = "ffi")]
Expand Down Expand Up @@ -2091,6 +2115,7 @@ mod tests {
#[cfg(feature = "ffi")]
preserve_header_order: false,
h09_responses: false,
h10_disable_keep_alive: false,
#[cfg(feature = "ffi")]
on_informational: &mut None,
#[cfg(feature = "ffi")]
Expand Down Expand Up @@ -2119,6 +2144,7 @@ mod tests {
#[cfg(feature = "ffi")]
preserve_header_order: false,
h09_responses: false,
h10_disable_keep_alive: false,
#[cfg(feature = "ffi")]
on_informational: &mut None,
#[cfg(feature = "ffi")]
Expand Down Expand Up @@ -2147,6 +2173,7 @@ mod tests {
#[cfg(feature = "ffi")]
preserve_header_order: false,
h09_responses: false,
h10_disable_keep_alive: false,
#[cfg(feature = "ffi")]
on_informational: &mut None,
#[cfg(feature = "ffi")]
Expand Down Expand Up @@ -2652,6 +2679,7 @@ mod tests {
#[cfg(feature = "ffi")]
preserve_header_order: false,
h09_responses: false,
h10_disable_keep_alive: false,
#[cfg(feature = "ffi")]
on_informational: &mut None,
#[cfg(feature = "ffi")]
Expand Down Expand Up @@ -2766,6 +2794,7 @@ mod tests {
#[cfg(feature = "ffi")]
preserve_header_order: false,
h09_responses: false,
h10_disable_keep_alive: false,
#[cfg(feature = "ffi")]
on_informational: &mut None,
#[cfg(feature = "ffi")]
Expand Down Expand Up @@ -2814,6 +2843,7 @@ mod tests {
#[cfg(feature = "ffi")]
preserve_header_order: false,
h09_responses: false,
h10_disable_keep_alive: false,
#[cfg(feature = "ffi")]
on_informational: &mut None,
#[cfg(feature = "ffi")]
Expand Down
Loading
Loading