diff --git a/Cargo.toml b/Cargo.toml
index f7696c3e19..32657b2d32 100644
--- a/Cargo.toml
+++ b/Cargo.toml
@@ -256,3 +256,6 @@ required-features = ["full"]
name = "server"
path = "tests/server.rs"
required-features = ["full"]
+
+[patch.crates-io]
+http = { git = "https://github.com/glebpom/http", branch = "failable-headers-allocations" }
diff --git a/examples/upgrades.rs b/examples/upgrades.rs
index 38cfded386..6d8ef8d166 100644
--- a/examples/upgrades.rs
+++ b/examples/upgrades.rs
@@ -66,7 +66,8 @@ async fn server_upgrade(mut req: Request
) -> Result> {
// made-up 'foobar' protocol.
*res.status_mut() = StatusCode::SWITCHING_PROTOCOLS;
res.headers_mut()
- .insert(UPGRADE, HeaderValue::from_static("foobar"));
+ .try_insert(UPGRADE, HeaderValue::from_static("foobar"))
+ .expect("FIXME");
Ok(res)
}
diff --git a/src/client/client.rs b/src/client/client.rs
index bf4db79fde..2292e17378 100644
--- a/src/client/client.rs
+++ b/src/client/client.rs
@@ -257,7 +257,8 @@ where
if self.config.set_host {
let uri = req.uri().clone();
- req.headers_mut().entry(HOST).or_insert_with(|| {
+ let entry = headers_op!(req.headers_mut().try_entry(HOST), error);
+ headers_op!(entry.or_try_insert_with(|| {
let hostname = uri.host().expect("authority implies host");
if let Some(port) = get_non_default_port(&uri) {
let s = format!("{}:{}", hostname, port);
@@ -266,7 +267,7 @@ where
HeaderValue::from_str(hostname)
}
.expect("uri host is valid header value")
- });
+ }), capacity);
}
// CONNECT always sends authority-form, so check it first...
@@ -752,6 +753,12 @@ enum ClientError {
},
}
+impl From for ClientError {
+ fn from(e: crate::error::Parse) -> Self {
+ ClientError::Normal(e.into())
+ }
+}
+
impl ClientError {
fn map_with_reused(conn_reused: bool) -> impl Fn((crate::Error, Option>)) -> Self {
move |(err, orig_req)| {
diff --git a/src/error.rs b/src/error.rs
index 5beedeb8b2..adea7fed98 100644
--- a/src/error.rs
+++ b/src/error.rs
@@ -65,6 +65,9 @@ pub(super) enum Kind {
/// A general error from h2.
#[cfg(feature = "http2")]
Http2,
+
+ /// Error with HTTP request or response
+ Http(http::Error),
}
#[derive(Debug)]
@@ -518,6 +521,7 @@ impl Error {
Kind::User(User::DispatchGone) => "dispatch task is gone",
#[cfg(feature = "ffi")]
Kind::User(User::AbortedByCallback) => "operation aborted by an application callback",
+ Kind::Http(ref _e) => "FIXME: HTTP request or response building error"
}
}
}
@@ -559,6 +563,20 @@ impl From for Error {
}
}
+#[doc(hidden)]
+impl From for Error {
+ fn from(err: http::CapacityOverflow) -> Error {
+ Error::new(Kind::Http(err.into()))
+ }
+}
+
+#[doc(hidden)]
+impl From for Error {
+ fn from(err: http::Error) -> Error {
+ Error::new(Kind::Http(err))
+ }
+}
+
#[cfg(feature = "http1")]
impl Parse {
pub(crate) fn content_length_invalid() -> Self {
@@ -628,6 +646,34 @@ impl fmt::Display for TimedOut {
impl StdError for TimedOut {}
+macro_rules! headers_op {
+ ($op:expr, capacity) => {
+ match $op {
+ Err(http::CapacityOverflow { .. }) => {
+ return Err(crate::error::Parse::TooLarge.into());
+ },
+ Ok(r) => r,
+ }
+ };
+ ($op:expr, error) => {
+ match $op {
+ Err(e) if e.is::() => {
+ return Err(crate::error::Parse::TooLarge.into());
+ },
+ Err(e) if e.is::() => {
+ // FIXME!
+ return Err(crate::error::Parse::Internal.into());
+ },
+ Err(_e) => {
+ // FIXME!
+ return Err(crate::error::Parse::Internal.into());
+ },
+ Ok(r) => r,
+ }
+ };
+}
+
+
#[cfg(test)]
mod tests {
use super::*;
diff --git a/src/ext.rs b/src/ext.rs
index 224206dd66..8c6ea4d59e 100644
--- a/src/ext.rs
+++ b/src/ext.rs
@@ -5,7 +5,7 @@ use bytes::Bytes;
use http::header::HeaderName;
#[cfg(feature = "http1")]
use http::header::{IntoHeaderName, ValueIter};
-use http::HeaderMap;
+use http::{CapacityOverflow, HeaderMap};
#[cfg(feature = "ffi")]
use std::collections::HashMap;
#[cfg(feature = "http2")]
@@ -119,15 +119,17 @@ impl HeaderCaseMap {
}
#[cfg(any(test, feature = "ffi"))]
- pub(crate) fn insert(&mut self, name: HeaderName, orig: Bytes) {
- self.0.insert(name, orig);
+ pub(crate) fn try_insert(&mut self, name: HeaderName, orig: Bytes) -> Result<(), CapacityOverflow> {
+ self.0.try_insert(name, orig)?;
+ Ok(())
}
- pub(crate) fn append(&mut self, name: N, orig: Bytes)
+ pub(crate) fn try_append(&mut self, name: N, orig: Bytes) -> Result<(), CapacityOverflow>
where
N: IntoHeaderName,
{
- self.0.append(name, orig);
+ self.0.try_append(name, orig)?;
+ Ok(())
}
}
diff --git a/src/ffi/error.rs b/src/ffi/error.rs
index 015e595aee..b3017b7114 100644
--- a/src/ffi/error.rs
+++ b/src/ffi/error.rs
@@ -24,6 +24,8 @@ pub enum hyper_code {
HYPERE_FEATURE_NOT_ENABLED,
/// The peer sent an HTTP message that could not be parsed.
HYPERE_INVALID_PEER_MESSAGE,
+ /// HTTP headers reached the maximum capacity
+ HYPERE_HEADERS_CAPACITY,
}
// ===== impl hyper_error =====
diff --git a/src/ffi/http_types.rs b/src/ffi/http_types.rs
index ea10f139cb..d0a62cdf09 100644
--- a/src/ffi/http_types.rs
+++ b/src/ffi/http_types.rs
@@ -468,8 +468,18 @@ ffi_fn! {
let headers = non_null!(&mut *headers ?= hyper_code::HYPERE_INVALID_ARG);
match unsafe { raw_name_value(name, name_len, value, value_len) } {
Ok((name, value, orig_name)) => {
- headers.headers.insert(&name, value);
- headers.orig_casing.insert(name.clone(), orig_name.clone());
+ match headers.headers.try_insert(&name, value) {
+ Err(http::CapacityOverflow { .. }) => {
+ return hyper_code::HYPERE_HEADERS_CAPACITY;
+ }
+ Ok(_) => {},
+ }
+ match headers.orig_casing.try_insert(name.clone(), orig_name.clone()) {
+ Err(http::CapacityOverflow { .. }) => {
+ return hyper_code::HYPERE_HEADERS_CAPACITY;
+ }
+ Ok(()) => {},
+ }
headers.orig_order.insert(name);
hyper_code::HYPERE_OK
}
@@ -488,8 +498,18 @@ ffi_fn! {
match unsafe { raw_name_value(name, name_len, value, value_len) } {
Ok((name, value, orig_name)) => {
- headers.headers.append(&name, value);
- headers.orig_casing.append(&name, orig_name.clone());
+ match headers.headers.try_append(&name, value) {
+ Err(http::CapacityOverflow { .. }) => {
+ return hyper_code::HYPERE_HEADERS_CAPACITY;
+ }
+ Ok(_) => {},
+ }
+ match headers.orig_casing.try_append(&name, orig_name.clone()) {
+ Err(http::CapacityOverflow { .. }) => {
+ return hyper_code::HYPERE_HEADERS_CAPACITY;
+ }
+ Ok(()) => {},
+ }
headers.orig_order.append(name);
hyper_code::HYPERE_OK
}
diff --git a/src/headers.rs b/src/headers.rs
index 8407be185f..2839f0e037 100644
--- a/src/headers.rs
+++ b/src/headers.rs
@@ -2,7 +2,7 @@
use bytes::BytesMut;
use http::header::CONTENT_LENGTH;
use http::header::{HeaderValue, ValueIter};
-use http::HeaderMap;
+use http::{CapacityOverflow, HeaderMap};
#[cfg(all(feature = "http2", feature = "client"))]
use http::Method;
@@ -100,10 +100,18 @@ pub(super) fn method_has_defined_payload_semantics(method: &Method) -> bool {
}
#[cfg(feature = "http2")]
-pub(super) fn set_content_length_if_missing(headers: &mut HeaderMap, len: u64) {
- headers
- .entry(CONTENT_LENGTH)
- .or_insert_with(|| HeaderValue::from(len));
+pub(super) fn set_content_length_if_missing(headers: &mut HeaderMap, len: u64) -> Result<(), CapacityOverflow> {
+ match headers
+ .try_entry(CONTENT_LENGTH){
+ Err(e) if e.is::() => return Err(CapacityOverflow::new()),
+ Err(_) => {
+ unreachable!()
+ },
+ Ok(e) => {
+ e.or_try_insert_with(|| HeaderValue::from(len))?;
+ }
+ };
+ Ok(())
}
#[cfg(feature = "http1")]
diff --git a/src/lib.rs b/src/lib.rs
index e5e4cfc56e..9c7c0df4cf 100644
--- a/src/lib.rs
+++ b/src/lib.rs
@@ -77,6 +77,7 @@ mod cfg;
#[macro_use]
mod common;
pub mod body;
+#[macro_use]
mod error;
pub mod ext;
#[cfg(test)]
diff --git a/src/proto/h1/conn.rs b/src/proto/h1/conn.rs
index 5ebff2803e..fe5824a827 100644
--- a/src/proto/h1/conn.rs
+++ b/src/proto/h1/conn.rs
@@ -551,7 +551,11 @@ where
self.state.busy();
}
- self.enforce_version(&mut head);
+ if let Err(err) = self.enforce_version(&mut head) {
+ self.state.error = Some(err.into());
+ self.state.writing = Writing::Closed;
+ return None;
+ }
let buf = self.io.headers_buf();
match super::role::encode_headers::(
@@ -587,7 +591,7 @@ where
}
// Fix keep-alive when Connection: keep-alive header is not present
- fn fix_keep_alive(&mut self, head: &mut MessageHead) {
+ fn fix_keep_alive(&mut self, head: &mut MessageHead) -> Result<(), http::Error> {
let outgoing_is_keep_alive = head
.headers
.get(CONNECTION)
@@ -604,20 +608,22 @@ where
Version::HTTP_11 => {
if self.state.wants_keep_alive() {
head.headers
- .insert(CONNECTION, HeaderValue::from_static("keep-alive"));
+ .try_insert(CONNECTION, HeaderValue::from_static("keep-alive"))?;
}
}
_ => (),
}
}
+
+ Ok(())
}
// 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) {
+ fn enforce_version(&mut self, head: &mut MessageHead) -> Result<(), http::Error> {
if let Version::HTTP_10 = self.state.version {
// Fixes response or connection when keep-alive header is not present
- self.fix_keep_alive(head);
+ self.fix_keep_alive(head)?;
// If the remote only knows HTTP/1.0, we should force ourselves
// to do only speak HTTP/1.0 as well.
head.version = Version::HTTP_10;
@@ -625,6 +631,8 @@ where
// If the remote speaks HTTP/1.1, then it *should* be fine with
// both HTTP/1.0 and HTTP/1.1 from us. So again, we just let
// the user's headers be.
+
+ Ok(())
}
pub(crate) fn write_body(&mut self, chunk: B) {
@@ -1061,7 +1069,7 @@ mod tests {
let io = tokio_test::io::Builder::new().build();
let mut conn = Conn::<_, bytes::Bytes, crate::proto::h1::ServerTransaction>::new(io);
*conn.io.read_buf_mut() = ::bytes::BytesMut::from(&s[..]);
- conn.state.cached_headers = Some(HeaderMap::with_capacity(2));
+ conn.state.cached_headers = Some(HeaderMap::try_with_capacity(2).unwrap());
let rt = tokio::runtime::Builder::new_current_thread()
.enable_all()
diff --git a/src/proto/h1/role.rs b/src/proto/h1/role.rs
index 6252207baf..0a2936938e 100644
--- a/src/proto/h1/role.rs
+++ b/src/proto/h1/role.rs
@@ -224,7 +224,7 @@ impl Http1Transaction for Server {
let mut headers = ctx.cached_headers.take().unwrap_or_else(HeaderMap::new);
- headers.reserve(headers_len);
+ headers_op!(headers.try_reserve(headers_len), capacity);
for header in &headers_indices[..headers_len] {
// SAFETY: array is valid up to `headers_len`
@@ -295,7 +295,7 @@ impl Http1Transaction for Server {
}
if let Some(ref mut header_case_map) = header_case_map {
- header_case_map.append(&name, slice.slice(header.name.0..header.name.1));
+ headers_op!(header_case_map.try_append(&name, slice.slice(header.name.0..header.name.1)), capacity);
}
#[cfg(feature = "ffi")]
@@ -303,7 +303,7 @@ impl Http1Transaction for Server {
header_order.append(&name);
}
- headers.append(name, value);
+ headers_op!(headers.try_append(name, value), capacity);
}
if is_te && !is_te_chunked {
@@ -1020,7 +1020,7 @@ impl Http1Transaction for Client {
None
};
- headers.reserve(headers_len);
+ headers_op!(headers.try_reserve(headers_len), capacity);
for header in &headers_indices[..headers_len] {
// SAFETY: array is valid up to `headers_len`
let header = unsafe { &*header.as_ptr() };
@@ -1039,7 +1039,7 @@ impl Http1Transaction for Client {
}
if let Some(ref mut header_case_map) = header_case_map {
- header_case_map.append(&name, slice.slice(header.name.0..header.name.1));
+ headers_op!(header_case_map.try_append(&name, slice.slice(header.name.0..header.name.1)), capacity);
}
#[cfg(feature = "ffi")]
@@ -1047,7 +1047,12 @@ impl Http1Transaction for Client {
header_order.append(&name);
}
- headers.append(name, value);
+ match headers.try_append(name.clone(), value) {
+ Err(http::CapacityOverflow { .. }) => {
+ return Err(Parse::TooLarge);
+ },
+ Ok(_) => {}
+ }
}
let mut extensions = http::Extensions::default();
@@ -1152,7 +1157,7 @@ impl Http1Transaction for Client {
extend(dst, b"\r\n");
msg.head.headers.clear(); //TODO: remove when switching to drain()
- Ok(body)
+ body
}
fn on_error(_err: &crate::Error) -> Option> {
@@ -1233,12 +1238,12 @@ impl Client {
Ok(Some((DecodedLength::CLOSE_DELIMITED, false)))
}
}
- fn set_length(head: &mut RequestHead, body: Option) -> Encoder {
+ fn set_length(head: &mut RequestHead, body: Option) -> crate::Result {
let body = if let Some(body) = body {
body
} else {
head.headers.remove(header::TRANSFER_ENCODING);
- return Encoder::length(0);
+ return Ok(Encoder::length(0));
};
// HTTP/1.0 doesn't know about chunked
@@ -1262,19 +1267,19 @@ impl Client {
}
return if let Some(len) = existing_con_len {
- Encoder::length(len)
+ Ok(Encoder::length(len))
} else if let BodyLength::Known(len) = body {
- set_content_length(headers, len)
+ Ok(headers_op!(set_content_length(headers, len), error))
} else {
// HTTP/1.0 client requests without a content-length
// cannot have any body at all.
- Encoder::length(0)
+ Ok(Encoder::length(0))
};
}
// If the user set a transfer-encoding, respect that. Let's just
// make sure `chunked` is the final encoding.
- let encoder = match headers.entry(header::TRANSFER_ENCODING) {
+ let encoder = match headers_op!(headers.try_entry(header::TRANSFER_ENCODING), error) {
Entry::Occupied(te) => {
should_remove_con_len = true;
if headers::is_chunked(te.iter()) {
@@ -1314,7 +1319,7 @@ impl Client {
match head.subject.0 {
Method::GET | Method::HEAD | Method::CONNECT => Some(Encoder::length(0)),
_ => {
- te.insert(HeaderValue::from_static("chunked"));
+ headers_op!(te.try_insert(HeaderValue::from_static("chunked")), capacity);
Some(Encoder::chunked())
}
}
@@ -1330,7 +1335,7 @@ impl Client {
if should_remove_con_len && existing_con_len.is_some() {
headers.remove(header::CONTENT_LENGTH);
}
- return encoder;
+ return Ok(encoder);
}
// User didn't set transfer-encoding, AND we know body length,
@@ -1342,11 +1347,11 @@ impl Client {
unreachable!("BodyLength::Unknown would set chunked");
};
- set_content_length(headers, len)
+ Ok(headers_op!(set_content_length(headers, len), error))
}
}
-fn set_content_length(headers: &mut HeaderMap, len: u64) -> Encoder {
+fn set_content_length(headers: &mut HeaderMap, len: u64) -> Result {
// At this point, there should not be a valid Content-Length
// header. However, since we'll be indexing in anyways, we can
// warn the user if there was an existing illegal header.
@@ -1355,7 +1360,7 @@ fn set_content_length(headers: &mut HeaderMap, len: u64) -> Encoder {
// so perhaps only do that while the user is developing/testing.
if cfg!(debug_assertions) {
- match headers.entry(header::CONTENT_LENGTH) {
+ match headers.try_entry(header::CONTENT_LENGTH)? {
Entry::Occupied(mut cl) => {
// Internal sanity check, we should have already determined
// that the header was illegal before calling this function.
@@ -1366,16 +1371,16 @@ fn set_content_length(headers: &mut HeaderMap, len: u64) -> Encoder {
error!("user provided content-length header was invalid");
cl.insert(HeaderValue::from(len));
- Encoder::length(len)
+ Ok(Encoder::length(len))
}
Entry::Vacant(cl) => {
- cl.insert(HeaderValue::from(len));
- Encoder::length(len)
+ cl.try_insert(HeaderValue::from(len))?;
+ Ok(Encoder::length(len))
}
}
} else {
- headers.insert(header::CONTENT_LENGTH, HeaderValue::from(len));
- Encoder::length(len)
+ headers.try_insert(header::CONTENT_LENGTH, HeaderValue::from(len))?;
+ Ok(Encoder::length(len))
}
}
@@ -2391,10 +2396,10 @@ mod tests {
let mut head = MessageHead::default();
head.headers
- .insert("content-length", HeaderValue::from_static("10"));
+ .try_insert("content-length", HeaderValue::from_static("10")).unwrap();
head.headers
- .insert("content-type", HeaderValue::from_static("application/json"));
- head.headers.insert("*-*", HeaderValue::from_static("o_o"));
+ .try_insert("content-type", HeaderValue::from_static("application/json")).unwrap();
+ head.headers.try_insert("*-*", HeaderValue::from_static("o_o")).unwrap();
let mut vec = Vec::new();
Client::encode(
@@ -2419,12 +2424,12 @@ mod tests {
let mut head = MessageHead::default();
head.headers
- .insert("content-length", HeaderValue::from_static("10"));
+ .try_insert("content-length", HeaderValue::from_static("10")).unwrap();
head.headers
- .insert("content-type", HeaderValue::from_static("application/json"));
+ .try_insert("content-type", HeaderValue::from_static("application/json")).unwrap();
let mut orig_headers = HeaderCaseMap::default();
- orig_headers.insert(CONTENT_LENGTH, "CONTENT-LENGTH".into());
+ orig_headers.try_insert(CONTENT_LENGTH, "CONTENT-LENGTH".into()).unwrap();
head.extensions.insert(orig_headers);
let mut vec = Vec::new();
@@ -2453,12 +2458,12 @@ mod tests {
let mut head = MessageHead::default();
head.headers
- .insert("content-length", HeaderValue::from_static("10"));
+ .try_insert("content-length", HeaderValue::from_static("10")).unwrap();
head.headers
- .insert("content-type", HeaderValue::from_static("application/json"));
+ .try_insert("content-type", HeaderValue::from_static("application/json")).unwrap();
let mut orig_headers = HeaderCaseMap::default();
- orig_headers.insert(CONTENT_LENGTH, "CONTENT-LENGTH".into());
+ orig_headers.try_insert(CONTENT_LENGTH, "CONTENT-LENGTH".into()).unwrap();
head.extensions.insert(orig_headers);
let mut vec = Vec::new();
@@ -2508,11 +2513,11 @@ mod tests {
let mut head = MessageHead::default();
head.headers
- .insert("content-length", HeaderValue::from_static("10"));
+ .try_insert("content-length", HeaderValue::from_static("10")).unwrap();
head.headers
- .insert("content-type", HeaderValue::from_static("application/json"));
+ .try_insert("content-type", HeaderValue::from_static("application/json")).unwrap();
head.headers
- .insert("weird--header", HeaderValue::from_static(""));
+ .try_insert("weird--header", HeaderValue::from_static("")).unwrap();
let mut vec = Vec::new();
Server::encode(
@@ -2540,12 +2545,12 @@ mod tests {
let mut head = MessageHead::default();
head.headers
- .insert("content-length", HeaderValue::from_static("10"));
+ .try_insert("content-length", HeaderValue::from_static("10")).unwrap();
head.headers
- .insert("content-type", HeaderValue::from_static("application/json"));
+ .try_insert("content-type", HeaderValue::from_static("application/json")).unwrap();
let mut orig_headers = HeaderCaseMap::default();
- orig_headers.insert(CONTENT_LENGTH, "CONTENT-LENGTH".into());
+ orig_headers.try_insert(CONTENT_LENGTH, "CONTENT-LENGTH".into()).unwrap();
head.extensions.insert(orig_headers);
let mut vec = Vec::new();
@@ -2574,12 +2579,12 @@ mod tests {
let mut head = MessageHead::default();
head.headers
- .insert("content-length", HeaderValue::from_static("10"));
+ .try_insert("content-length", HeaderValue::from_static("10")).unwrap();
head.headers
- .insert("content-type", HeaderValue::from_static("application/json"));
+ .try_insert("content-type", HeaderValue::from_static("application/json")).unwrap();
let mut orig_headers = HeaderCaseMap::default();
- orig_headers.insert(CONTENT_LENGTH, "CONTENT-LENGTH".into());
+ orig_headers.try_insert(CONTENT_LENGTH, "CONTENT-LENGTH".into()).unwrap();
head.extensions.insert(orig_headers);
let mut vec = Vec::new();
@@ -2636,9 +2641,9 @@ mod tests {
fn test_write_headers_orig_case_empty_value() {
let mut headers = HeaderMap::new();
let name = http::header::HeaderName::from_static("x-empty");
- headers.insert(&name, "".parse().expect("parse empty"));
+ headers.try_insert(&name, "".parse().expect("parse empty")).unwrap();
let mut orig_cases = HeaderCaseMap::default();
- orig_cases.insert(name, Bytes::from_static(b"X-EmptY"));
+ orig_cases.try_insert(name, Bytes::from_static(b"X-EmptY")).unwrap();
let mut dst = Vec::new();
super::write_headers_original_case(&headers, &orig_cases, &mut dst, false);
@@ -2653,12 +2658,12 @@ mod tests {
fn test_write_headers_orig_case_multiple_entries() {
let mut headers = HeaderMap::new();
let name = http::header::HeaderName::from_static("x-empty");
- headers.insert(&name, "a".parse().unwrap());
- headers.append(&name, "b".parse().unwrap());
+ headers.try_insert(&name, "a".parse().unwrap()).unwrap();
+ headers.try_append(&name, "b".parse().unwrap()).unwrap();
let mut orig_cases = HeaderCaseMap::default();
- orig_cases.insert(name.clone(), Bytes::from_static(b"X-Empty"));
- orig_cases.append(name, Bytes::from_static(b"X-EMPTY"));
+ orig_cases.try_insert(name.clone(), Bytes::from_static(b"X-Empty")).unwrap();
+ orig_cases.try_append(name, Bytes::from_static(b"X-EMPTY")).unwrap();
let mut dst = Vec::new();
super::write_headers_original_case(&headers, &orig_cases, &mut dst, false);
@@ -2793,8 +2798,8 @@ mod tests {
let mut head = MessageHead::default();
let mut headers = HeaderMap::new();
- headers.insert("content-length", HeaderValue::from_static("10"));
- headers.insert("content-type", HeaderValue::from_static("application/json"));
+ headers.try_insert("content-length", HeaderValue::from_static("10")).unwrap();
+ headers.try_insert("content-type", HeaderValue::from_static("application/json")).unwrap();
b.iter(|| {
let mut vec = Vec::new();
diff --git a/src/proto/h2/client.rs b/src/proto/h2/client.rs
index bac8eceb3a..56310eb215 100644
--- a/src/proto/h2/client.rs
+++ b/src/proto/h2/client.rs
@@ -371,7 +371,7 @@ where
super::strip_connection_headers(req.headers_mut(), true);
if let Some(len) = body.size_hint().exact() {
if len != 0 || headers::method_has_defined_payload_semantics(req.method()) {
- headers::set_content_length_if_missing(req.headers_mut(), len);
+ headers::set_content_length_if_missing(req.headers_mut(), len)?;
}
}
diff --git a/src/proto/h2/server.rs b/src/proto/h2/server.rs
index 4127387e71..adfdb56b8d 100644
--- a/src/proto/h2/server.rs
+++ b/src/proto/h2/server.rs
@@ -482,8 +482,8 @@ where
// set Date header if it isn't already set...
res.headers_mut()
- .entry(::http::header::DATE)
- .or_insert_with(date::update_and_header_value);
+ .try_entry(::http::header::DATE)?
+ .or_try_insert_with(date::update_and_header_value)?;
if let Some(connect_parts) = connect_parts.take() {
if res.status().is_success() {
@@ -511,7 +511,7 @@ where
if !body.is_end_stream() {
// automatically set Content-Length from body...
if let Some(len) = body.size_hint().exact() {
- headers::set_content_length_if_missing(res.headers_mut(), len);
+ headers::set_content_length_if_missing(res.headers_mut(), len)?;
}
let body_tx = reply!(me, res, false);
diff --git a/tests/server.rs b/tests/server.rs
index 786bb4b42f..c23d375de0 100644
--- a/tests/server.rs
+++ b/tests/server.rs
@@ -3003,7 +3003,7 @@ impl TestService {
*res.version_mut() = v;
}
Reply::Header(name, value) => {
- res.headers_mut().insert(name, value);
+ res.headers_mut().try_insert(name, value)?;
}
Reply::Body(body) => {
*res.body_mut() = body;
diff --git a/tests/support/mod.rs b/tests/support/mod.rs
index 6b3c8f4472..5ae314de29 100644
--- a/tests/support/mod.rs
+++ b/tests/support/mod.rs
@@ -202,7 +202,7 @@ macro_rules! __internal_req_res_prop {
macro_rules! __internal_headers_map {
($headers:ident, { $($name:expr => $val:expr,)* }) => {
$(
- $headers.insert($name, $val.to_string().parse().expect("header value"));
+ $headers.try_insert($name, $val.to_string().parse().expect("header value")).unwrap();
)*
}
}