diff --git a/src/header/map.rs b/src/header/map.rs index a123606e..de8bd2d2 100644 --- a/src/header/map.rs +++ b/src/header/map.rs @@ -2133,12 +2133,16 @@ impl Extend<(Option, T)> for HeaderMap { // Reserve the entire hint lower bound if the map is empty. // Otherwise reserve half the hint (rounded up), so the map // will only resize twice in the worst case. - let reserve = if self.is_empty() { + let hint = if self.is_empty() { iter.size_hint().0 } else { (iter.size_hint().0 + 1) / 2 }; + // Clamp the hint so an over-estimate cannot overflow `reserve`. + let max_reserve = usable_capacity(MAX_SIZE).saturating_sub(self.entries.len()); + let reserve = hint.min(max_reserve); + self.reserve(reserve); // The structure of this is a bit weird, but it is mostly to make the @@ -2189,12 +2193,16 @@ impl Extend<(HeaderName, T)> for HeaderMap { // will only resize twice in the worst case. let iter = iter.into_iter(); - let reserve = if self.is_empty() { + let hint = if self.is_empty() { iter.size_hint().0 } else { (iter.size_hint().0 + 1) / 2 }; + // Clamp the hint so an over-estimate cannot overflow `reserve`. + let max_reserve = usable_capacity(MAX_SIZE).saturating_sub(self.entries.len()); + let reserve = hint.min(max_reserve); + self.reserve(reserve); for (k, v) in iter { diff --git a/tests/header_map.rs b/tests/header_map.rs index 9a9d7e12..8f407fd9 100644 --- a/tests/header_map.rs +++ b/tests/header_map.rs @@ -55,6 +55,23 @@ fn with_capacity_overflow() { HeaderMap::::with_capacity(24_577); } +#[test] +fn extend_size_hint_above_capacity() { + // A `HeaderMap` may hold more values than the table can index when many + // values are appended under one name, so an exact size hint can exceed the + // largest `reserve` request. Extending must not panic in that case. + let name = HeaderName::from_static("h"); + let value = HeaderValue::from_static("0"); + let pairs: Vec<(HeaderName, HeaderValue)> = + std::iter::repeat_with(|| (name.clone(), value.clone())) + .take(24_577) + .collect(); + + let map = HeaderMap::from_iter(pairs); + assert_eq!(map.len(), 24_577); + assert_eq!(map.keys_len(), 1); +} + #[test] #[should_panic] fn reserve_overflow() {