diff --git a/src/auth/authorization.rs b/src/auth/authorization.rs index cc8fa5b1..839d4f23 100644 --- a/src/auth/authorization.rs +++ b/src/auth/authorization.rs @@ -1,6 +1,6 @@ use crate::auth::AuthenticationScheme; use crate::bail_status as bail; -use crate::headers::{HeaderName, HeaderValue, Headers, AUTHORIZATION}; +use crate::headers::{Header, HeaderName, HeaderValue, Headers, AUTHORIZATION}; /// Credentials to authenticate a user agent with a server. /// @@ -78,7 +78,7 @@ impl Authorization { /// Get the `HeaderName`. pub fn name(&self) -> HeaderName { - AUTHORIZATION + self.header_name() } /// Get the `HeaderValue`. @@ -110,6 +110,16 @@ impl Authorization { } } +impl Header for Authorization { + fn header_name(&self) -> HeaderName { + AUTHORIZATION + } + + fn header_value(&self) -> HeaderValue { + self.value() + } +} + #[cfg(test)] mod test { use super::*; diff --git a/src/auth/basic_auth.rs b/src/auth/basic_auth.rs index afcd6046..36f1aad7 100644 --- a/src/auth/basic_auth.rs +++ b/src/auth/basic_auth.rs @@ -113,6 +113,16 @@ impl BasicAuth { } } +impl crate::headers::Header for BasicAuth { + fn header_name(&self) -> HeaderName { + AUTHORIZATION + } + + fn header_value(&self) -> HeaderValue { + self.value() + } +} + #[cfg(test)] mod test { use super::*; diff --git a/src/auth/www_authenticate.rs b/src/auth/www_authenticate.rs index f7f43c8f..628ff777 100644 --- a/src/auth/www_authenticate.rs +++ b/src/auth/www_authenticate.rs @@ -132,6 +132,16 @@ impl WwwAuthenticate { } } +impl crate::headers::Header for WwwAuthenticate { + fn header_name(&self) -> HeaderName { + WWW_AUTHENTICATE + } + + fn header_value(&self) -> HeaderValue { + self.value() + } +} + #[cfg(test)] mod test { use super::*; diff --git a/src/cache/age.rs b/src/cache/age.rs index 4d23c1a3..e45227bb 100644 --- a/src/cache/age.rs +++ b/src/cache/age.rs @@ -95,6 +95,16 @@ impl ToHeaderValues for Age { } } +impl crate::headers::Header for Age { + fn header_name(&self) -> HeaderName { + AGE + } + + fn header_value(&self) -> HeaderValue { + self.value() + } +} + #[cfg(test)] mod test { use super::*; diff --git a/src/cache/cache_control/cache_control.rs b/src/cache/cache_control/cache_control.rs index 47f99326..4257c133 100644 --- a/src/cache/cache_control/cache_control.rs +++ b/src/cache/cache_control/cache_control.rs @@ -104,6 +104,15 @@ impl CacheControl { } } +impl crate::headers::Header for CacheControl { + fn header_name(&self) -> HeaderName { + CACHE_CONTROL + } + fn header_value(&self) -> HeaderValue { + self.value() + } +} + impl IntoIterator for CacheControl { type Item = CacheDirective; type IntoIter = IntoIter; diff --git a/src/cache/clear_site_data/mod.rs b/src/cache/clear_site_data/mod.rs index c816062d..21294be5 100644 --- a/src/cache/clear_site_data/mod.rs +++ b/src/cache/clear_site_data/mod.rs @@ -249,6 +249,15 @@ impl Debug for ClearSiteData { } } +impl crate::headers::Header for ClearSiteData { + fn header_name(&self) -> HeaderName { + CLEAR_SITE_DATA + } + fn header_value(&self) -> HeaderValue { + self.value() + } +} + #[cfg(test)] mod test { use crate::cache::{ClearDirective, ClearSiteData}; diff --git a/src/cache/expires.rs b/src/cache/expires.rs index 73c3e66d..746a5e7b 100644 --- a/src/cache/expires.rs +++ b/src/cache/expires.rs @@ -90,6 +90,15 @@ impl Expires { } } +impl crate::headers::Header for Expires { + fn header_name(&self) -> HeaderName { + EXPIRES + } + fn header_value(&self) -> HeaderValue { + self.value() + } +} + impl ToHeaderValues for Expires { type Iter = option::IntoIter; fn to_header_values(&self) -> crate::Result { diff --git a/src/conditional/etag.rs b/src/conditional/etag.rs index 548e4bdb..4c3e522d 100644 --- a/src/conditional/etag.rs +++ b/src/conditional/etag.rs @@ -130,6 +130,15 @@ impl ETag { } } +impl crate::headers::Header for ETag { + fn header_name(&self) -> HeaderName { + ETAG + } + fn header_value(&self) -> HeaderValue { + self.value() + } +} + impl Display for ETag { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { match self { diff --git a/src/conditional/if_match.rs b/src/conditional/if_match.rs index 24f961c5..5e163f2a 100644 --- a/src/conditional/if_match.rs +++ b/src/conditional/if_match.rs @@ -134,6 +134,15 @@ impl IfMatch { } } +impl crate::headers::Header for IfMatch { + fn header_name(&self) -> HeaderName { + IF_MATCH + } + fn header_value(&self) -> HeaderValue { + self.value() + } +} + impl IntoIterator for IfMatch { type Item = ETag; type IntoIter = IntoIter; diff --git a/src/conditional/if_modified_since.rs b/src/conditional/if_modified_since.rs index d964c427..35b82989 100644 --- a/src/conditional/if_modified_since.rs +++ b/src/conditional/if_modified_since.rs @@ -93,6 +93,15 @@ impl ToHeaderValues for IfModifiedSince { } } +impl crate::headers::Header for IfModifiedSince { + fn header_name(&self) -> HeaderName { + IF_MODIFIED_SINCE + } + fn header_value(&self) -> HeaderValue { + self.value() + } +} + #[cfg(test)] mod test { use super::*; diff --git a/src/conditional/if_none_match.rs b/src/conditional/if_none_match.rs index 608b45bd..96cf0f94 100644 --- a/src/conditional/if_none_match.rs +++ b/src/conditional/if_none_match.rs @@ -140,6 +140,15 @@ impl IfNoneMatch { } } +impl crate::headers::Header for IfNoneMatch { + fn header_name(&self) -> HeaderName { + IF_NONE_MATCH + } + fn header_value(&self) -> HeaderValue { + self.value() + } +} + impl IntoIterator for IfNoneMatch { type Item = ETag; type IntoIter = IntoIter; diff --git a/src/conditional/if_unmodified_since.rs b/src/conditional/if_unmodified_since.rs index 2696cb0b..f407e143 100644 --- a/src/conditional/if_unmodified_since.rs +++ b/src/conditional/if_unmodified_since.rs @@ -85,6 +85,15 @@ impl IfUnmodifiedSince { } } +impl crate::headers::Header for IfUnmodifiedSince { + fn header_name(&self) -> HeaderName { + IF_UNMODIFIED_SINCE + } + fn header_value(&self) -> HeaderValue { + self.value() + } +} + impl ToHeaderValues for IfUnmodifiedSince { type Iter = option::IntoIter; fn to_header_values(&self) -> crate::Result { diff --git a/src/conditional/last_modified.rs b/src/conditional/last_modified.rs index a4fb3153..97aa847a 100644 --- a/src/conditional/last_modified.rs +++ b/src/conditional/last_modified.rs @@ -84,6 +84,15 @@ impl LastModified { } } +impl crate::headers::Header for LastModified { + fn header_name(&self) -> HeaderName { + LAST_MODIFIED + } + fn header_value(&self) -> HeaderValue { + self.value() + } +} + impl ToHeaderValues for LastModified { type Iter = option::IntoIter; fn to_header_values(&self) -> crate::Result { diff --git a/src/conditional/vary.rs b/src/conditional/vary.rs index 38d4b68b..d6d73826 100644 --- a/src/conditional/vary.rs +++ b/src/conditional/vary.rs @@ -140,6 +140,15 @@ impl Vary { } } +impl crate::headers::Header for Vary { + fn header_name(&self) -> HeaderName { + VARY + } + fn header_value(&self) -> HeaderValue { + self.value() + } +} + impl IntoIterator for Vary { type Item = HeaderName; type IntoIter = IntoIter; diff --git a/src/content/accept.rs b/src/content/accept.rs index 828cd533..37bde14e 100644 --- a/src/content/accept.rs +++ b/src/content/accept.rs @@ -189,6 +189,15 @@ impl Accept { } } +impl crate::headers::Header for Accept { + fn header_name(&self) -> HeaderName { + ACCEPT + } + fn header_value(&self) -> HeaderValue { + self.value() + } +} + impl IntoIterator for Accept { type Item = MediaTypeProposal; type IntoIter = IntoIter; diff --git a/src/content/accept_encoding.rs b/src/content/accept_encoding.rs index 8a2814e6..98b90310 100644 --- a/src/content/accept_encoding.rs +++ b/src/content/accept_encoding.rs @@ -182,6 +182,15 @@ impl AcceptEncoding { } } +impl crate::headers::Header for AcceptEncoding { + fn header_name(&self) -> HeaderName { + ACCEPT_ENCODING + } + fn header_value(&self) -> HeaderValue { + self.value() + } +} + impl IntoIterator for AcceptEncoding { type Item = EncodingProposal; type IntoIter = IntoIter; diff --git a/src/content/content_encoding.rs b/src/content/content_encoding.rs index 0e57c4bb..9fa9e6fd 100644 --- a/src/content/content_encoding.rs +++ b/src/content/content_encoding.rs @@ -80,6 +80,15 @@ impl ContentEncoding { } } +impl crate::headers::Header for ContentEncoding { + fn header_name(&self) -> HeaderName { + CONTENT_ENCODING + } + fn header_value(&self) -> HeaderValue { + self.value() + } +} + impl ToHeaderValues for ContentEncoding { type Iter = option::IntoIter; fn to_header_values(&self) -> crate::Result { diff --git a/src/content/content_length.rs b/src/content/content_length.rs index b4495c9f..ec814e2c 100644 --- a/src/content/content_length.rs +++ b/src/content/content_length.rs @@ -80,6 +80,15 @@ impl ContentLength { } } +impl crate::headers::Header for ContentLength { + fn header_name(&self) -> HeaderName { + CONTENT_LENGTH + } + fn header_value(&self) -> HeaderValue { + self.value() + } +} + #[cfg(test)] mod test { use super::*; diff --git a/src/content/content_location.rs b/src/content/content_location.rs index a381923e..92854149 100644 --- a/src/content/content_location.rs +++ b/src/content/content_location.rs @@ -99,6 +99,15 @@ impl ContentLocation { } } +impl crate::headers::Header for ContentLocation { + fn header_name(&self) -> HeaderName { + CONTENT_LOCATION + } + fn header_value(&self) -> HeaderValue { + self.value() + } +} + #[cfg(test)] mod test { use super::*; diff --git a/src/content/content_type.rs b/src/content/content_type.rs index 3c2a1227..721e24b2 100644 --- a/src/content/content_type.rs +++ b/src/content/content_type.rs @@ -91,6 +91,15 @@ impl ContentType { } } +impl crate::headers::Header for ContentType { + fn header_name(&self) -> HeaderName { + CONTENT_TYPE + } + fn header_value(&self) -> HeaderValue { + self.value() + } +} + impl PartialEq for ContentType { fn eq(&self, other: &Mime) -> bool { &self.media_type == other diff --git a/src/headers/header.rs b/src/headers/header.rs new file mode 100644 index 00000000..deffa5f3 --- /dev/null +++ b/src/headers/header.rs @@ -0,0 +1,41 @@ +use crate::headers::{HeaderName, HeaderValue, Headers}; + +/// A trait representing a [`HeaderName`] and [`HeaderValue`] pair. +pub trait Header { + /// Access the header's name. + fn header_name(&self) -> HeaderName; + + /// Access the header's value. + fn header_value(&self) -> HeaderValue; + + /// Insert the header name and header value into something that looks like a + /// [`Headers`] map. + fn apply_header>(&self, mut headers: H) { + let name = self.header_name(); + let value = self.header_value(); + headers.as_mut().insert(name, value); + } +} + +impl<'a, 'b> Header for (&'a str, &'b str) { + fn header_name(&self) -> HeaderName { + 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") + } +} + +#[cfg(test)] +mod test { + use super::*; + + #[test] + fn header_from_strings() { + let strings = ("Content-Length", "12"); + assert_eq!(strings.header_name(), "Content-Length"); + assert_eq!(strings.header_value(), "12"); + } +} diff --git a/src/headers/mod.rs b/src/headers/mod.rs index 10838d60..e23aede0 100644 --- a/src/headers/mod.rs +++ b/src/headers/mod.rs @@ -1,6 +1,7 @@ //! HTTP headers. mod constants; +mod header; mod header_name; mod header_value; mod header_values; @@ -14,6 +15,7 @@ mod to_header_values; mod values; pub use constants::*; +pub use header::Header; pub use header_name::HeaderName; pub use header_value::HeaderValue; pub use header_values::HeaderValues; diff --git a/src/other/date.rs b/src/other/date.rs index 6889af95..45c85a93 100644 --- a/src/other/date.rs +++ b/src/other/date.rs @@ -92,6 +92,15 @@ impl Date { } } +impl crate::headers::Header for Date { + fn header_name(&self) -> HeaderName { + DATE + } + fn header_value(&self) -> HeaderValue { + self.value() + } +} + impl From for SystemTime { fn from(date: Date) -> Self { date.at diff --git a/src/other/expect.rs b/src/other/expect.rs index 5e8fd307..4007afc4 100644 --- a/src/other/expect.rs +++ b/src/other/expect.rs @@ -74,6 +74,15 @@ impl Expect { } } +impl crate::headers::Header for Expect { + fn header_name(&self) -> HeaderName { + EXPECT + } + fn header_value(&self) -> HeaderValue { + self.value() + } +} + impl ToHeaderValues for Expect { type Iter = option::IntoIter; fn to_header_values(&self) -> crate::Result { diff --git a/src/other/referer.rs b/src/other/referer.rs index 10510b1b..b7bee899 100644 --- a/src/other/referer.rs +++ b/src/other/referer.rs @@ -104,6 +104,15 @@ impl Referer { } } +impl crate::headers::Header for Referer { + fn header_name(&self) -> HeaderName { + REFERER + } + fn header_value(&self) -> HeaderValue { + self.value() + } +} + #[cfg(test)] mod test { use super::*; diff --git a/src/other/source_map.rs b/src/other/source_map.rs index 349a99a2..22191834 100644 --- a/src/other/source_map.rs +++ b/src/other/source_map.rs @@ -101,6 +101,15 @@ impl SourceMap { } } +impl crate::headers::Header for SourceMap { + fn header_name(&self) -> HeaderName { + SOURCE_MAP + } + fn header_value(&self) -> HeaderValue { + self.value() + } +} + #[cfg(test)] mod test { use super::*; diff --git a/src/proxies/forwarded.rs b/src/proxies/forwarded.rs index 79b95442..b9d6a828 100644 --- a/src/proxies/forwarded.rs +++ b/src/proxies/forwarded.rs @@ -408,6 +408,18 @@ impl<'a> Forwarded<'a> { } } +impl<'a> crate::headers::Header for Forwarded<'a> { + fn header_name(&self) -> HeaderName { + FORWARDED + } + fn header_value(&self) -> HeaderValue { + // NOTE(yosh): This will never panic because we always write into a string. + let output = self.value().unwrap(); + // SAFETY: the internal string is validated to be ASCII. + unsafe { HeaderValue::from_bytes_unchecked(output.into()) } + } +} + fn parse_value(input: &str) -> (Option>, &str) { match parse_token(input) { (Some(token), rest) => (Some(Cow::Borrowed(token)), rest), diff --git a/src/security/timing_allow_origin.rs b/src/security/timing_allow_origin.rs index 2c92d277..1e19c256 100644 --- a/src/security/timing_allow_origin.rs +++ b/src/security/timing_allow_origin.rs @@ -162,6 +162,15 @@ impl TimingAllowOrigin { } } +impl crate::headers::Header for TimingAllowOrigin { + fn header_name(&self) -> HeaderName { + TIMING_ALLOW_ORIGIN + } + fn header_value(&self) -> HeaderValue { + self.value() + } +} + impl IntoIterator for TimingAllowOrigin { type Item = Url; type IntoIter = IntoIter; diff --git a/src/server/allow.rs b/src/server/allow.rs index bad9f729..0ebda194 100644 --- a/src/server/allow.rs +++ b/src/server/allow.rs @@ -108,6 +108,15 @@ impl Allow { } } +impl crate::headers::Header for Allow { + fn header_name(&self) -> HeaderName { + ALLOW + } + fn header_value(&self) -> HeaderValue { + self.value() + } +} + impl IntoIterator for Allow { type Item = Method; type IntoIter = IntoIter; diff --git a/src/trace/server_timing/mod.rs b/src/trace/server_timing/mod.rs index f46490fe..620bbf77 100644 --- a/src/trace/server_timing/mod.rs +++ b/src/trace/server_timing/mod.rs @@ -131,6 +131,15 @@ impl ServerTiming { } } +impl crate::headers::Header for ServerTiming { + fn header_name(&self) -> HeaderName { + SERVER_TIMING + } + fn header_value(&self) -> HeaderValue { + self.value() + } +} + impl IntoIterator for ServerTiming { type Item = Metric; type IntoIter = IntoIter; diff --git a/src/trace/trace_context.rs b/src/trace/trace_context.rs index 74a4ebd7..4ed0c166 100644 --- a/src/trace/trace_context.rs +++ b/src/trace/trace_context.rs @@ -246,6 +246,15 @@ impl TraceContext { } } +impl crate::headers::Header for TraceContext { + fn header_name(&self) -> HeaderName { + TRACEPARENT + } + fn header_value(&self) -> HeaderValue { + self.value() + } +} + impl fmt::Display for TraceContext { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { write!( diff --git a/src/transfer/te.rs b/src/transfer/te.rs index 7be659e6..c5456347 100644 --- a/src/transfer/te.rs +++ b/src/transfer/te.rs @@ -1,4 +1,4 @@ -use crate::headers::{HeaderName, HeaderValue, Headers, ToHeaderValues, ACCEPT_ENCODING}; +use crate::headers::{self, HeaderName, HeaderValue, Headers, ToHeaderValues}; use crate::transfer::{Encoding, EncodingProposal, TransferEncoding}; use crate::utils::sort_by_weight; use crate::{Error, StatusCode}; @@ -33,7 +33,7 @@ use std::slice; /// let encoding = te.negotiate(&[Encoding::Brotli, Encoding::Gzip])?; /// encoding.apply(&mut res); /// -/// assert_eq!(res["Content-Encoding"], "br"); +/// assert_eq!(res["Transfer-Encoding"], "br"); /// # /// # Ok(()) } /// ``` @@ -54,7 +54,7 @@ impl TE { /// Create an instance of `TE` from a `Headers` instance. pub fn from_headers(headers: impl AsRef) -> crate::Result> { let mut entries = vec![]; - let headers = match headers.as_ref().get(ACCEPT_ENCODING) { + let headers = match headers.as_ref().get(headers::TE) { Some(headers) => headers, None => return Ok(None), }; @@ -138,12 +138,12 @@ impl TE { /// Sets the `Accept-Encoding` header. pub fn apply(&self, mut headers: impl AsMut) { - headers.as_mut().insert(ACCEPT_ENCODING, self.value()); + headers.as_mut().insert(headers::TE, self.value()); } /// Get the `HeaderName`. pub fn name(&self) -> HeaderName { - ACCEPT_ENCODING + headers::TE } /// Get the `HeaderValue`. @@ -183,6 +183,15 @@ impl TE { } } +impl crate::headers::Header for TE { + fn header_name(&self) -> HeaderName { + headers::TE + } + fn header_value(&self) -> HeaderValue { + self.value() + } +} + impl IntoIterator for TE { type Item = EncodingProposal; type IntoIter = IntoIter; diff --git a/src/transfer/transfer_encoding.rs b/src/transfer/transfer_encoding.rs index 2f3eb7ca..e67827fc 100644 --- a/src/transfer/transfer_encoding.rs +++ b/src/transfer/transfer_encoding.rs @@ -1,4 +1,4 @@ -use crate::headers::{HeaderName, HeaderValue, Headers, ToHeaderValues, CONTENT_ENCODING}; +use crate::headers::{HeaderName, HeaderValue, Headers, ToHeaderValues, TRANSFER_ENCODING}; use crate::transfer::{Encoding, EncodingProposal}; use std::fmt::{self, Debug}; @@ -42,7 +42,7 @@ impl TransferEncoding { /// Create a new instance from headers. pub fn from_headers(headers: impl AsRef) -> crate::Result> { - let headers = match headers.as_ref().get(CONTENT_ENCODING) { + let headers = match headers.as_ref().get(TRANSFER_ENCODING) { Some(headers) => headers, None => return Ok(None), }; @@ -61,12 +61,12 @@ impl TransferEncoding { /// Sets the `Content-Encoding` header. pub fn apply(&self, mut headers: impl AsMut) { - headers.as_mut().insert(CONTENT_ENCODING, self.value()); + headers.as_mut().insert(TRANSFER_ENCODING, self.value()); } /// Get the `HeaderName`. pub fn name(&self) -> HeaderName { - CONTENT_ENCODING + TRANSFER_ENCODING } /// Get the `HeaderValue`. @@ -80,6 +80,15 @@ impl TransferEncoding { } } +impl crate::headers::Header for TransferEncoding { + fn header_name(&self) -> HeaderName { + TRANSFER_ENCODING + } + fn header_value(&self) -> HeaderValue { + self.value() + } +} + impl ToHeaderValues for TransferEncoding { type Iter = option::IntoIter; fn to_header_values(&self) -> crate::Result {