use header::{Header, Raw, Host}; use std::borrow::Cow; use std::fmt; use std::str::FromStr; use header::parsing::from_one_raw_str; /// The `Origin` header. /// /// 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. /// This header is often used to inform recipients of the security context of where the request was initiated. /// /// /// Following the spec, https://fetch.spec.whatwg.org/#origin-header, the value of this header is composed of /// a String (scheme), header::Host (host/port) /// /// # Examples /// ``` /// use hyper::header::{Headers, Origin}; /// /// let mut headers = Headers::new(); /// headers.set( /// Origin::new("http", "hyper.rs", None) /// ); /// ``` /// ``` /// use hyper::header::{Headers, Origin}; /// /// let mut headers = Headers::new(); /// headers.set( /// Origin::new("https", "wikipedia.org", Some(443)) /// ); /// ``` #[derive(PartialEq, Clone, Debug)] pub struct Origin(OriginOrNull); #[derive(PartialEq, Clone, Debug)] enum OriginOrNull { Origin { /// The scheme, such as http or https scheme: Cow<'static,str>, /// The host, such as Host{hostname: "hyper.rs".to_owned(), port: None} host: Host, }, Null, } impl Origin { /// Creates a new `Origin` header. pub fn new>, H: Into>>(scheme: S, hostname: H, port: Option) -> Origin{ Origin(OriginOrNull::Origin { scheme: scheme.into(), host: Host::new(hostname, port), }) } /// Creates a `Null` `Origin` header. pub fn null() -> Origin { Origin(OriginOrNull::Null) } /// Checks if `Origin` is `Null`. pub fn is_null(&self) -> bool { match self { &Origin(OriginOrNull::Null) => true, _ => false, } } /// The scheme, such as http or https /// ``` /// use hyper::header::Origin; /// let origin = Origin::new("https", "foo.com", Some(443)); /// assert_eq!(origin.scheme(), Some("https")); /// ``` pub fn scheme(&self) -> Option<&str> { match self { &Origin(OriginOrNull::Origin { ref scheme, .. }) => Some(&scheme), _ => None, } } /// The host, such as Host{hostname: "hyper.rs".to_owned(), port: None} /// ``` /// use hyper::header::{Origin,Host}; /// let origin = Origin::new("https", "foo.com", Some(443)); /// assert_eq!(origin.host(), Some(&Host::new("foo.com", Some(443)))); /// ``` pub fn host(&self) -> Option<&Host> { match self { &Origin(OriginOrNull::Origin { ref host, .. }) => Some(&host), _ => None, } } } impl Header for Origin { fn header_name() -> &'static str { static NAME: &'static str = "Origin"; NAME } fn parse_header(raw: &Raw) -> ::Result { from_one_raw_str(raw) } fn fmt_header(&self, f: &mut ::header::Formatter) -> fmt::Result { f.fmt_line(self) } } static HTTP : &'static str = "http"; static HTTPS : &'static str = "https"; impl FromStr for Origin { type Err = ::Error; fn from_str(s: &str) -> ::Result { let idx = match s.find("://") { Some(idx) => idx, None => return Err(::Error::Header) }; // idx + 3 because that's how long "://" is let (scheme, etc) = (&s[..idx], &s[idx + 3..]); let host = try!(Host::from_str(etc)); let scheme = match scheme { "http" => Cow::Borrowed(HTTP), "https" => Cow::Borrowed(HTTPS), s => Cow::Owned(s.to_owned()) }; Ok(Origin(OriginOrNull::Origin { scheme: scheme, host: host })) } } impl fmt::Display for Origin { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { match self.0 { OriginOrNull::Origin { ref scheme, ref host } => write!(f, "{}://{}", scheme, host), // Serialized as "null" per ASCII serialization of an origin // https://html.spec.whatwg.org/multipage/browsers.html#ascii-serialisation-of-an-origin OriginOrNull::Null => f.write_str("null") } } } #[cfg(test)] mod tests { use super::Origin; use header::Header; use std::borrow::Cow; macro_rules! assert_borrowed{ ($expr : expr) => { match $expr { Cow::Owned(ref v) => panic!("assertion failed: `{}` owns {:?}", stringify!($expr), v), _ => {} } } } #[test] fn test_origin() { let origin : Origin = Header::parse_header(&vec![b"http://foo.com".to_vec()].into()).unwrap(); assert_eq!(&origin, &Origin::new("http", "foo.com", None)); assert_borrowed!(origin.scheme().unwrap().into()); let origin : Origin = Header::parse_header(&vec![b"https://foo.com:443".to_vec()].into()).unwrap(); assert_eq!(&origin, &Origin::new("https", "foo.com", Some(443))); assert_borrowed!(origin.scheme().unwrap().into()); } } bench_header!(bench, Origin, { vec![b"https://foo.com".to_vec()] });