diff --git a/src/headers/header.rs b/src/headers/header.rs index deffa5f3..8bc9e83f 100644 --- a/src/headers/header.rs +++ b/src/headers/header.rs @@ -17,14 +17,27 @@ pub trait Header { } } -impl<'a, 'b> Header for (&'a str, &'b str) { +impl Header for (&'static str, &'static str) { fn header_name(&self) -> HeaderName { - HeaderName::from(self.0) + if self.0.chars().all(|c| c.is_ascii_lowercase()) { + HeaderName::from_lowercase_str(self.0) + } else { + HeaderName::from(self.0) + } } fn header_value(&self) -> HeaderValue { - HeaderValue::from_bytes(self.1.to_owned().into_bytes()) - .expect("String slice should be valid ASCII") + HeaderValue::from_static_str(self.1) + } +} + +impl Header for (String, String) { + fn header_name(&self) -> HeaderName { + self.0.parse().expect("Header name should be valid ASCII") + } + + fn header_value(&self) -> HeaderValue { + self.1.parse().expect("Header value should be valid ASCII") } } diff --git a/src/headers/header_value.rs b/src/headers/header_value.rs index 14100aad..f4f1d8b0 100644 --- a/src/headers/header_value.rs +++ b/src/headers/header_value.rs @@ -1,3 +1,4 @@ +use std::borrow::Cow; use std::convert::TryFrom; use std::fmt::{self, Debug, Display}; use std::str::FromStr; @@ -11,7 +12,7 @@ use crate::Mime; /// A header value. #[derive(Clone, Eq, PartialEq, Hash)] pub struct HeaderValue { - inner: String, + inner: Cow<'static, str>, } impl HeaderValue { @@ -25,7 +26,7 @@ impl HeaderValue { // This is permitted because ASCII is valid UTF-8, and we just checked that. let string = unsafe { String::from_utf8_unchecked(bytes) }; - Ok(Self { inner: string }) + Ok(Self { inner: string.into() }) } /// Converts a vector of bytes to a `HeaderValue` without checking that the string contains @@ -39,19 +40,27 @@ impl HeaderValue { /// that Strings are valid ASCII. pub unsafe fn from_bytes_unchecked(bytes: Vec) -> Self { let string = String::from_utf8_unchecked(bytes); - Self { inner: string } + Self { inner: string.into() } } /// Get the header value as a `&str` pub fn as_str(&self) -> &str { &self.inner } + + /// Create a new `HeaderValue` from a static-lifetime string slice. + pub(crate) fn from_static_str(value: &'static str) -> Self { + assert!(value.is_ascii(), "Bytes should be valid ASCII"); + Self { + inner: Cow::Borrowed(value), + } + } } impl From for HeaderValue { fn from(mime: Mime) -> Self { HeaderValue { - inner: format!("{}", mime), + inner: format!("{}", mime).into(), } } } @@ -60,7 +69,7 @@ impl From for HeaderValue { impl From> for HeaderValue { fn from(cookie: Cookie<'_>) -> Self { HeaderValue { - inner: cookie.to_string(), + inner: cookie.to_string().into(), } } } @@ -68,7 +77,7 @@ impl From> for HeaderValue { impl From<&Mime> for HeaderValue { fn from(mime: &Mime) -> Self { HeaderValue { - inner: format!("{}", mime), + inner: format!("{}", mime).into(), } } } @@ -82,7 +91,7 @@ impl FromStr for HeaderValue { fn from_str(s: &str) -> Result { crate::ensure!(s.is_ascii(), "String slice should be valid ASCII"); Ok(Self { - inner: String::from(s), + inner: s.to_owned().into(), }) } } @@ -113,7 +122,7 @@ impl PartialEq for HeaderValue { } } -impl<'a> PartialEq<&'a str> for HeaderValue { +impl<'a, 'v> PartialEq<&'a str> for HeaderValue { fn eq(&self, other: &&'a str) -> bool { &self.inner == other } @@ -125,7 +134,7 @@ impl PartialEq for HeaderValue { } } -impl<'a> PartialEq<&String> for HeaderValue { +impl<'a, 'v> PartialEq<&String> for HeaderValue { fn eq(&self, other: &&String) -> bool { &&self.inner == other }