rama_http_headers/forwarded/
x_forwarded_proto.rs1use crate::{Error, Header};
2use rama_http_types::{HeaderName, HeaderValue, header};
3use rama_net::forwarded::{ForwardedElement, ForwardedProtocol};
4
5#[derive(Debug, Clone, PartialEq, Eq)]
27pub struct XForwardedProto(ForwardedProtocol);
28
29impl Header for XForwardedProto {
30 fn name() -> &'static HeaderName {
31 &header::X_FORWARDED_PROTO
32 }
33
34 fn decode<'i, I: Iterator<Item = &'i HeaderValue>>(values: &mut I) -> Result<Self, Error> {
35 Ok(XForwardedProto(
36 values
37 .next()
38 .and_then(|value| value.to_str().ok().and_then(|s| s.parse().ok()))
39 .ok_or_else(Error::invalid)?,
40 ))
41 }
42
43 fn encode<E: Extend<HeaderValue>>(&self, values: &mut E) {
44 let s = self.0.to_string();
45 values.extend(Some(HeaderValue::from_str(&s).unwrap()))
46 }
47}
48
49impl XForwardedProto {
50 pub fn protocol(&self) -> &ForwardedProtocol {
52 &self.0
53 }
54
55 pub fn into_protocol(self) -> ForwardedProtocol {
57 self.0
58 }
59}
60
61impl IntoIterator for XForwardedProto {
62 type Item = ForwardedElement;
63 type IntoIter = XForwardedProtoIterator;
64
65 fn into_iter(self) -> Self::IntoIter {
66 XForwardedProtoIterator(Some(self.0))
67 }
68}
69
70impl super::ForwardHeader for XForwardedProto {
71 fn try_from_forwarded<'a, I>(input: I) -> Option<Self>
72 where
73 I: IntoIterator<Item = &'a ForwardedElement>,
74 {
75 let proto = input.into_iter().next()?.ref_forwarded_proto()?;
76 Some(XForwardedProto(proto))
77 }
78}
79
80#[derive(Debug, Clone)]
81pub struct XForwardedProtoIterator(Option<ForwardedProtocol>);
83
84impl Iterator for XForwardedProtoIterator {
85 type Item = ForwardedElement;
86
87 fn next(&mut self) -> Option<Self::Item> {
88 self.0.take().map(ForwardedElement::forwarded_proto)
89 }
90}
91
92#[cfg(test)]
93mod tests {
94 use super::*;
95
96 use rama_http_types::HeaderValue;
97
98 macro_rules! test_header {
99 ($name: ident, $input: expr, $expected: expr) => {
100 #[test]
101 fn $name() {
102 assert_eq!(
103 XForwardedProto::decode(
104 &mut $input
105 .into_iter()
106 .map(|s| HeaderValue::from_bytes(s.as_bytes()).unwrap())
107 .collect::<Vec<_>>()
108 .iter()
109 )
110 .ok(),
111 $expected,
112 );
113 }
114 };
115 }
116
117 test_header!(
119 test1,
120 vec!["https"],
121 Some(XForwardedProto(ForwardedProtocol::HTTPS))
122 );
123 test_header!(
124 test2,
125 vec!["https", "http"],
127 Some(XForwardedProto(ForwardedProtocol::HTTPS))
128 );
129 test_header!(
130 test3,
131 vec!["http"],
132 Some(XForwardedProto(ForwardedProtocol::HTTP))
133 );
134
135 #[test]
136 fn test_x_forwarded_proto_symmetric_encoder() {
137 for input in [ForwardedProtocol::HTTP, ForwardedProtocol::HTTPS] {
138 let input = XForwardedProto(input);
139 let mut values = Vec::new();
140 input.encode(&mut values);
141 let output = XForwardedProto::decode(&mut values.iter()).unwrap();
142 assert_eq!(input, output);
143 }
144 }
145}