rama_http/headers/forwarded/
x_forwarded_host.rsuse crate::headers::{self, Header};
use crate::{HeaderName, HeaderValue};
use rama_net::address::Host;
use rama_net::forwarded::{ForwardedAuthority, ForwardedElement};
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct XForwardedHost(ForwardedAuthority);
impl Header for XForwardedHost {
fn name() -> &'static HeaderName {
&crate::header::X_FORWARDED_HOST
}
fn decode<'i, I: Iterator<Item = &'i HeaderValue>>(
values: &mut I,
) -> Result<Self, headers::Error> {
Ok(XForwardedHost(
values
.next()
.and_then(|value| value.to_str().ok().and_then(|s| s.parse().ok()))
.ok_or_else(crate::headers::Error::invalid)?,
))
}
fn encode<E: Extend<HeaderValue>>(&self, values: &mut E) {
let s = self.0.to_string();
values.extend(Some(HeaderValue::from_str(&s).unwrap()))
}
}
impl XForwardedHost {
#[inline]
pub fn host(&self) -> &Host {
self.0.host()
}
#[inline]
pub fn port(&self) -> Option<u16> {
self.0.port()
}
pub fn inner(&self) -> &ForwardedAuthority {
&self.0
}
pub fn into_inner(self) -> ForwardedAuthority {
self.0
}
}
impl IntoIterator for XForwardedHost {
type Item = ForwardedElement;
type IntoIter = XForwardedHostIterator;
fn into_iter(self) -> Self::IntoIter {
XForwardedHostIterator(Some(self.0))
}
}
impl super::ForwardHeader for XForwardedHost {
fn try_from_forwarded<'a, I>(input: I) -> Option<Self>
where
I: IntoIterator<Item = &'a ForwardedElement>,
{
let el = input.into_iter().next()?;
let host = el.ref_forwarded_host().cloned()?;
Some(XForwardedHost(host))
}
}
#[derive(Debug, Clone)]
pub struct XForwardedHostIterator(Option<ForwardedAuthority>);
impl Iterator for XForwardedHostIterator {
type Item = ForwardedElement;
fn next(&mut self) -> Option<Self::Item> {
self.0.take().map(ForwardedElement::forwarded_host)
}
}
#[cfg(test)]
mod tests {
use super::*;
use rama_http_types::HeaderValue;
macro_rules! test_header {
($name: ident, $input: expr, $expected: expr) => {
#[test]
fn $name() {
assert_eq!(
XForwardedHost::decode(
&mut $input
.into_iter()
.map(|s| HeaderValue::from_bytes(s.as_bytes()).unwrap())
.collect::<Vec<_>>()
.iter()
)
.ok(),
$expected,
);
}
};
}
test_header!(
test1,
vec!["id42.example-cdn.com"],
Some(XForwardedHost("id42.example-cdn.com".parse().unwrap()))
);
test_header!(
test2,
vec!["id42.example-cdn.com", "example.com"],
Some(XForwardedHost("id42.example-cdn.com".parse().unwrap()))
);
test_header!(
test3,
vec!["id42.example-cdn.com:443"],
Some(XForwardedHost("id42.example-cdn.com:443".parse().unwrap()))
);
test_header!(
test4,
vec!["203.0.113.195"],
Some(XForwardedHost("203.0.113.195".parse().unwrap()))
);
test_header!(
test5,
vec!["203.0.113.195:80"],
Some(XForwardedHost("203.0.113.195:80".parse().unwrap()))
);
test_header!(
test6,
vec!["2001:db8:85a3:8d3:1319:8a2e:370:7348"],
Some(XForwardedHost(
"2001:db8:85a3:8d3:1319:8a2e:370:7348".parse().unwrap()
))
);
test_header!(
test7,
vec!["[2001:db8:85a3:8d3:1319:8a2e:370:7348]:8080"],
Some(XForwardedHost(
"[2001:db8:85a3:8d3:1319:8a2e:370:7348]:8080"
.parse()
.unwrap()
))
);
#[test]
fn test_x_forwarded_host_symmetry_encode() {
for input in [
XForwardedHost("id42.example-cdn.com".parse().unwrap()),
XForwardedHost("id42.example-cdn.com:443".parse().unwrap()),
XForwardedHost("127.0.0.1".parse().unwrap()),
] {
let mut values = Vec::new();
input.encode(&mut values);
assert_eq!(XForwardedHost::decode(&mut values.iter()).unwrap(), input);
}
}
}