diff --git a/src/convert.rs b/src/convert.rs index 3c53a780..d527705b 100644 --- a/src/convert.rs +++ b/src/convert.rs @@ -1,4 +1,4 @@ -use crate::header::{HeaderName, HeaderValue}; +use crate::header::{HeaderMap, HeaderName, HeaderValue}; use crate::method::Method; use crate::sealed::Sealed; use crate::status::StatusCode; @@ -55,6 +55,7 @@ reflexive! { Uri, Method, StatusCode, + HeaderMap, HeaderName, HeaderValue, Scheme, diff --git a/src/header/map.rs b/src/header/map.rs index 1c48cce6..e968c017 100644 --- a/src/header/map.rs +++ b/src/header/map.rs @@ -1,12 +1,16 @@ -use super::name::{HdrName, HeaderName, InvalidHeaderName}; -use super::HeaderValue; - +use std::collections::HashMap; use std::collections::hash_map::RandomState; use std::hash::{BuildHasher, Hash, Hasher}; use std::iter::{FromIterator, FusedIterator}; use std::marker::PhantomData; use std::{fmt, mem, ops, ptr, vec}; +use crate::convert::{HttpTryFrom, HttpTryInto}; +use crate::Error; + +use super::HeaderValue; +use super::name::{HdrName, HeaderName, InvalidHeaderName}; + pub use self::as_header_name::AsHeaderName; pub use self::into_header_name::IntoHeaderName; @@ -23,6 +27,7 @@ pub use self::into_header_name::IntoHeaderName; /// ``` /// # use http::HeaderMap; /// # use http::header::{CONTENT_LENGTH, HOST, LOCATION}; +/// # use http::HttpTryFrom; /// let mut headers = HeaderMap::new(); /// /// headers.insert(HOST, "example.com".parse().unwrap()); @@ -1749,6 +1754,43 @@ impl FromIterator<(HeaderName, T)> for HeaderMap { } } +/// Convert a collection of tuples into a HeaderMap +/// +/// # Examples +/// +/// ``` +/// # use http::{HttpTryFrom, Result, header::HeaderMap}; +/// # use std::collections::HashMap; +/// let mut headers_hashmap: HashMap = vec![ +/// ("X-Custom-Header".to_string(), "my value".to_string()), +/// ].iter().cloned().collect(); +/// +/// let good_headers: Result = HeaderMap::try_from(&headers_hashmap); +/// assert!(good_headers.is_ok()); +/// +/// headers_hashmap.insert("\r".into(), "\0".into()); +/// let bad_headers: Result = HeaderMap::try_from(&headers_hashmap); +/// assert!(bad_headers.is_err()); +/// ``` +impl<'a, K, V> HttpTryFrom<&'a HashMap> for HeaderMap + where + K: Eq + Hash, + HeaderName: HttpTryFrom<&'a K>, + HeaderValue: HttpTryFrom<&'a V> +{ + type Error = Error; + + fn try_from(c: &'a HashMap) -> Result { + c.into_iter() + .map(|(k, v)| -> crate::Result<(HeaderName, HeaderValue)> { + let name : HeaderName = k.http_try_into()?; + let value : HeaderValue = v.http_try_into()?; + Ok((name, value)) + }) + .collect() + } +} + impl Extend<(Option, T)> for HeaderMap { /// Extend a `HeaderMap` with the contents of another `HeaderMap`. /// @@ -3209,7 +3251,7 @@ mod as_header_name { use super::{Entry, HdrName, HeaderMap, HeaderName, InvalidHeaderName}; /// A marker trait used to identify values that can be used as search keys - /// to a `HeaderMap`. + /// to a `HeaderMap`. pub trait AsHeaderName: Sealed {} // All methods are on this pub(super) trait, instead of `AsHeaderName`, diff --git a/src/header/name.rs b/src/header/name.rs index 4e85469b..ba1ff5a0 100644 --- a/src/header/name.rs +++ b/src/header/name.rs @@ -1776,6 +1776,14 @@ impl<'a> HttpTryFrom<&'a str> for HeaderName { } } +impl<'a> HttpTryFrom<&'a String> for HeaderName { + type Error = InvalidHeaderName; + #[inline] + fn try_from(s: &'a String) -> Result { + Self::from_bytes(s.as_bytes()) + } +} + impl<'a> HttpTryFrom<&'a [u8]> for HeaderName { type Error = InvalidHeaderName; #[inline] diff --git a/src/header/value.rs b/src/header/value.rs index 69ed0716..dfd2fd2c 100644 --- a/src/header/value.rs +++ b/src/header/value.rs @@ -518,6 +518,14 @@ impl<'a> HttpTryFrom<&'a str> for HeaderValue { } } +impl<'a> HttpTryFrom<&'a String> for HeaderValue { + type Error = InvalidHeaderValue; + #[inline] + fn try_from(s: &'a String) -> Result { + Self::from_bytes(s.as_bytes()) + } +} + impl<'a> HttpTryFrom<&'a [u8]> for HeaderValue { type Error = InvalidHeaderValue;