cogo_http/header/common/
origin.rs

1use crate::header::{Header, Host, HeaderFormat};
2use std::fmt;
3use std::str::FromStr;
4use crate::header::parsing::from_one_raw_str;
5
6/// The `Origin` header.
7///
8/// The `Origin` header is a version of the `Referer` header that is used for all HTTP fetches and `POST`s whose CORS flag is set.
9/// This header is often used to inform recipients of the security context of where the request was initiated.
10///
11///
12/// Following the spec, https://fetch.spec.whatwg.org/#origin-header, the value of this header is composed of
13/// a String (scheme), header::Host (host/port)
14///
15/// # Examples
16/// ```
17/// use cogo_http::header::{Headers, Origin};
18///
19/// let mut headers = Headers::new();
20/// headers.set(
21///     Origin::new("http", "hyper.rs", None)
22/// );
23/// ```
24/// ```
25/// use cogo_http::header::{Headers, Origin};
26///
27/// let mut headers = Headers::new();
28/// headers.set(
29///     Origin::new("https", "wikipedia.org", Some(443))
30/// );
31/// ```
32
33#[derive(Clone, Debug)]
34pub struct Origin {
35    /// The scheme, such as http or https
36    pub scheme: String,
37    /// The host, such as Host{hostname: "hyper.rs".to_owned(), port: None}
38    pub host: Host,
39}
40
41impl Origin {
42    /// Creates a new `Origin` header.
43    pub fn new<S: Into<String>, H: Into<String>>(scheme: S, hostname: H, port: Option<u16>) -> Origin{
44        Origin {
45            scheme: scheme.into(),
46            host: Host {
47                hostname: hostname.into(),
48                port: port
49            }
50        }
51    }
52}
53
54impl Header for Origin {
55    fn header_name() -> &'static str {
56        static NAME: &'static str = "Origin";
57        NAME
58    }
59
60    fn parse_header(raw: &[Vec<u8>]) -> crate::Result<Origin> {
61        from_one_raw_str(raw)
62    }
63}
64
65impl FromStr for Origin {
66    type Err = crate::Error;
67
68    fn from_str(s: &str) -> crate::Result<Origin> {
69        let idx = match s.find("://") {
70            Some(idx) => idx,
71            None => return Err(crate::Error::Header)
72        };
73        // idx + 3 because thats how long "://" is
74        let (scheme, etc) = (&s[..idx], &s[idx + 3..]);
75        let host = r#try!(Host::from_str(etc));
76
77
78        Ok(Origin{
79            scheme: scheme.to_owned(),
80            host: host
81        })
82    }
83}
84
85impl HeaderFormat for Origin {
86    fn fmt_header(&self, f: &mut fmt::Formatter) -> fmt::Result {
87        fmt::Display::fmt(self, f)
88    }
89}
90
91impl fmt::Display for Origin {
92    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
93        write!(f, "{}://{}", self.scheme, self.host)
94    }
95}
96
97impl PartialEq for Origin {
98    fn eq(&self, other: &Origin) -> bool {
99        self.scheme == other.scheme && self.host == other.host
100    }
101}
102
103
104#[cfg(test)]
105mod tests {
106    use super::Origin;
107    use crate::header::Header;
108
109    #[test]
110    fn test_origin() {
111        let origin = Header::parse_header([b"http://foo.com".to_vec()].as_ref());
112        assert_eq!(origin.ok(), Some(Origin::new("http", "foo.com", None)));
113
114        let origin = Header::parse_header([b"https://foo.com:443".to_vec()].as_ref());
115        assert_eq!(origin.ok(), Some(Origin::new("https", "foo.com", Some(443))));
116    }
117}
118
119bench_header!(bench, Origin, { vec![b"https://foo.com".to_vec()] });