hyperx/header/common/
origin.rs1use header::{Header, RawLike, Host};
2use std::borrow::Cow;
3use std::fmt;
4use std::str::FromStr;
5use header::parsing::from_one_raw_str;
6
7#[derive(PartialEq, Clone, Debug)]
39pub struct Origin(OriginOrNull);
40
41#[derive(PartialEq, Clone, Debug)]
42enum OriginOrNull {
43 Origin {
44 scheme: Cow<'static,str>,
46 host: Host,
48 },
49 Null,
50}
51
52impl Origin {
53 pub fn new<S: Into<Cow<'static,str>>, H: Into<Cow<'static,str>>>(scheme: S, hostname: H, port: Option<u16>) -> Origin{
55 Origin(OriginOrNull::Origin {
56 scheme: scheme.into(),
57 host: Host::new(hostname, port),
58 })
59 }
60
61 pub fn null() -> Origin {
63 Origin(OriginOrNull::Null)
64 }
65
66 pub fn is_null(&self) -> bool {
68 match self {
69 &Origin(OriginOrNull::Null) => true,
70 _ => false,
71 }
72 }
73
74 pub fn scheme(&self) -> Option<&str> {
82 match self {
83 &Origin(OriginOrNull::Origin { ref scheme, .. }) => Some(&scheme),
84 _ => None,
85 }
86 }
87
88 pub fn host(&self) -> Option<&Host> {
96 match self {
97 &Origin(OriginOrNull::Origin { ref host, .. }) => Some(&host),
98 _ => None,
99 }
100 }
101}
102
103impl Header for Origin {
104 fn header_name() -> &'static str {
105 static NAME: &'static str = "Origin";
106 NAME
107 }
108
109 fn parse_header<'a, T>(raw: &'a T) -> ::Result<Origin>
110 where T: RawLike<'a>
111 {
112 from_one_raw_str(raw)
113 }
114
115 fn fmt_header(&self, f: &mut ::header::Formatter) -> fmt::Result {
116 f.fmt_line(self)
117 }
118}
119
120static HTTP : &'static str = "http";
121static HTTPS : &'static str = "https";
122
123impl FromStr for Origin {
124 type Err = ::Error;
125
126 fn from_str(s: &str) -> ::Result<Origin> {
127 let idx = match s.find("://") {
128 Some(idx) => idx,
129 None => return Err(::Error::Header)
130 };
131 let (scheme, etc) = (&s[..idx], &s[idx + 3..]);
133 let host = Host::from_str(etc)?;
134 let scheme = match scheme {
135 "http" => Cow::Borrowed(HTTP),
136 "https" => Cow::Borrowed(HTTPS),
137 s => Cow::Owned(s.to_owned())
138 };
139
140 Ok(Origin(OriginOrNull::Origin {
141 scheme: scheme,
142 host: host
143 }))
144 }
145}
146
147impl fmt::Display for Origin {
148 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
149 match self.0 {
150 OriginOrNull::Origin { ref scheme, ref host } => write!(f, "{}://{}", scheme, host),
151 OriginOrNull::Null => f.write_str("null")
154 }
155 }
156}
157
158#[cfg(test)]
159mod tests {
160 use super::Origin;
161 use header::{Header, Raw};
162 use std::borrow::Cow;
163
164 macro_rules! assert_borrowed{
165 ($expr : expr) => {
166 match $expr {
167 Cow::Owned(ref v) => panic!("assertion failed: `{}` owns {:?}", stringify!($expr), v),
168 _ => {}
169 }
170 }
171 }
172
173 #[test]
174 fn test_origin() {
175 let r: Raw = vec![b"http://foo.com".to_vec()].into();
176 let origin : Origin = Header::parse_header(&r).unwrap();
177 assert_eq!(&origin, &Origin::new("http", "foo.com", None));
178 assert_borrowed!(origin.scheme().unwrap().into());
179
180 let r: Raw = vec![b"https://foo.com:443".to_vec()].into();
181 let origin : Origin = Header::parse_header(&r).unwrap();
182 assert_eq!(&origin, &Origin::new("https", "foo.com", Some(443)));
183 assert_borrowed!(origin.scheme().unwrap().into());
184 }
185}
186
187bench_header!(bench, Origin, { vec![b"https://foo.com".to_vec()] });
188
189standard_header!(Origin, ORIGIN);