feat(headers): support Opaque origin headers (#1147)
Add support for Opaque origin header, serializing it to `null`. https://html.spec.whatwg.org/multipage/browsers.html#concept-origin Closes #1065 BREAKING CHANGE: `Origin.scheme` and `Origin.host` now return `Option`s, since the `Origin` could be `null`.
This commit is contained in:
		
				
					committed by
					
						 Sean McArthur
						Sean McArthur
					
				
			
			
				
	
			
			
			
						parent
						
							1cd8ea36f3
						
					
				
				
					commit
					414859978b
				
			| @@ -31,20 +31,39 @@ use header::parsing::from_one_raw_str; | ||||
| /// ); | ||||
| /// ``` | ||||
|  | ||||
| #[derive(Clone, Debug)] | ||||
| pub struct 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, | ||||
| #[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<S: Into<Cow<'static,str>>, H: Into<Cow<'static,str>>>(scheme: S, hostname: H, port: Option<u16>) -> Origin{ | ||||
|         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, | ||||
|         } | ||||
|     } | ||||
|  | ||||
| @@ -52,20 +71,26 @@ impl Origin { | ||||
|     /// ``` | ||||
|     /// use hyper::header::Origin; | ||||
|     /// let origin = Origin::new("https", "foo.com", Some(443)); | ||||
|     /// assert_eq!(origin.scheme(), "https"); | ||||
|     /// assert_eq!(origin.scheme(), Some("https")); | ||||
|     /// ``` | ||||
|     pub fn scheme(&self) -> &str { | ||||
|         &(self.scheme) | ||||
|     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(), &Host::new("foo.com", Some(443))); | ||||
|     /// assert_eq!(origin.host(), Some(&Host::new("foo.com", Some(443)))); | ||||
|     /// ``` | ||||
|     pub fn host(&self) -> &Host { | ||||
|         &(self.host) | ||||
|     pub fn host(&self) -> Option<&Host> { | ||||
|         match self { | ||||
|             &Origin(OriginOrNull::Origin { ref host, .. }) => Some(&host), | ||||
|             _ => None, | ||||
|         } | ||||
|     } | ||||
| } | ||||
|  | ||||
| @@ -104,26 +129,24 @@ impl FromStr for Origin { | ||||
|             s       => Cow::Owned(s.to_owned()) | ||||
|         }; | ||||
|  | ||||
|         Ok(Origin{ | ||||
|         Ok(Origin(OriginOrNull::Origin { | ||||
|             scheme: scheme, | ||||
|             host: host | ||||
|         }) | ||||
|         })) | ||||
|     } | ||||
| } | ||||
|  | ||||
| impl fmt::Display for Origin { | ||||
|     fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { | ||||
|         write!(f, "{}://{}", self.scheme, self.host) | ||||
|         match self { | ||||
|             &Origin(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 | ||||
|             _ => write!(f, "null") | ||||
|         } | ||||
|     } | ||||
| } | ||||
|  | ||||
| impl PartialEq for Origin { | ||||
|     fn eq(&self, other: &Origin) -> bool { | ||||
|         self.scheme == other.scheme && self.host == other.host | ||||
|     } | ||||
| } | ||||
|  | ||||
|  | ||||
| #[cfg(test)] | ||||
| mod tests { | ||||
|     use super::Origin; | ||||
| @@ -143,11 +166,11 @@ mod tests { | ||||
|     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); | ||||
|         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); | ||||
|         assert_borrowed!(origin.scheme().unwrap().into()); | ||||
|     } | ||||
| } | ||||
|  | ||||
|   | ||||
		Reference in New Issue
	
	Block a user