refactor(header): Host header internals made private
This allows us to improve the performance. For now, a Cow is used internally, so clients can set the host to a static value and no longer need copies. Later, we can change it to also possibly have a MemSlice. BREAKING CHANGE: The fields of the `Host` header are no longer available. Use the getter methods instead.
This commit is contained in:
		| @@ -123,10 +123,7 @@ impl<C: Connect> Service for Client<C> { | |||||||
|  |  | ||||||
|         let (mut head, body) = request::split(req); |         let (mut head, body) = request::split(req); | ||||||
|         let mut headers = Headers::new(); |         let mut headers = Headers::new(); | ||||||
|         headers.set(Host { |         headers.set(Host::new(url.host_str().unwrap().to_owned(), url.port())); | ||||||
|             hostname: url.host_str().unwrap().to_owned(), |  | ||||||
|             port: url.port().or(None), |  | ||||||
|         }); |  | ||||||
|         headers.extend(head.headers.iter()); |         headers.extend(head.headers.iter()); | ||||||
|         head.subject.1 = RequestUri::AbsolutePath { |         head.subject.1 = RequestUri::AbsolutePath { | ||||||
|             path: url.path().to_owned(), |             path: url.path().to_owned(), | ||||||
|   | |||||||
| @@ -1,27 +1,22 @@ | |||||||
| use header::{Header, Raw}; | use std::borrow::Cow; | ||||||
| use std::fmt; | use std::fmt; | ||||||
| use std::str::FromStr; | use std::str::FromStr; | ||||||
|  |  | ||||||
|  | use header::{Header, Raw}; | ||||||
| use header::parsing::from_one_raw_str; | use header::parsing::from_one_raw_str; | ||||||
| use url::idna::domain_to_unicode; |  | ||||||
|  |  | ||||||
| /// The `Host` header. | /// The `Host` header. | ||||||
| /// | /// | ||||||
| /// HTTP/1.1 requires that all requests include a `Host` header, and so hyper | /// HTTP/1.1 requires that all requests include a `Host` header, and so hyper | ||||||
| /// client requests add one automatically. | /// client requests add one automatically. | ||||||
| /// | /// | ||||||
| /// Currently is just a String, but it should probably become a better type, |  | ||||||
| /// like `url::Host` or something. |  | ||||||
| /// |  | ||||||
| /// # Examples | /// # Examples | ||||||
| /// ``` | /// ``` | ||||||
| /// use hyper::header::{Headers, Host}; | /// use hyper::header::{Headers, Host}; | ||||||
| /// | /// | ||||||
| /// let mut headers = Headers::new(); | /// let mut headers = Headers::new(); | ||||||
| /// headers.set( | /// headers.set( | ||||||
| ///     Host{ | ///     Host::new("hyper.rs", None) | ||||||
| ///         hostname: "hyper.rs".to_owned(), |  | ||||||
| ///         port: None, |  | ||||||
| ///     } |  | ||||||
| /// ); | /// ); | ||||||
| /// ``` | /// ``` | ||||||
| /// ``` | /// ``` | ||||||
| @@ -29,18 +24,36 @@ use url::idna::domain_to_unicode; | |||||||
| /// | /// | ||||||
| /// let mut headers = Headers::new(); | /// let mut headers = Headers::new(); | ||||||
| /// headers.set( | /// headers.set( | ||||||
| ///     Host{ | ///     Host::new("hyper.rs", 8080) | ||||||
| ///         hostname: "hyper.rs".to_owned(), |  | ||||||
| ///         port: Some(8080), |  | ||||||
| ///     } |  | ||||||
| /// ); | /// ); | ||||||
| /// ``` | /// ``` | ||||||
| #[derive(Clone, PartialEq, Debug)] | #[derive(Clone, PartialEq, Debug)] | ||||||
| pub struct Host { | pub struct Host { | ||||||
|     /// The hostname, such a example.domain. |     hostname: Cow<'static, str>, | ||||||
|     pub hostname: String, |     port: Option<u16> | ||||||
|     /// An optional port number. | } | ||||||
|     pub port: Option<u16> |  | ||||||
|  | impl Host { | ||||||
|  |     /// Create a `Host` header, providing the hostname and optional port. | ||||||
|  |     pub fn new<H, P>(hostname: H, port: P) -> Host | ||||||
|  |     where H: Into<Cow<'static, str>>, | ||||||
|  |           P: Into<Option<u16>> | ||||||
|  |     { | ||||||
|  |         Host { | ||||||
|  |             hostname: hostname.into(), | ||||||
|  |             port: port.into(), | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     /// Get the hostname, such as example.domain. | ||||||
|  |     pub fn hostname(&self) -> &str { | ||||||
|  |         self.hostname.as_ref() | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     /// Get the optional port number. | ||||||
|  |     pub fn port(&self) -> Option<u16> { | ||||||
|  |         self.port | ||||||
|  |     } | ||||||
| } | } | ||||||
|  |  | ||||||
| impl Header for Host { | impl Header for Host { | ||||||
| @@ -75,27 +88,14 @@ impl FromStr for Host { | |||||||
|         let port = idx.and_then( |         let port = idx.and_then( | ||||||
|             |idx| s[idx + 1..].parse().ok() |             |idx| s[idx + 1..].parse().ok() | ||||||
|         ); |         ); | ||||||
|         let hostname_encoded = match port { |         let hostname = match port { | ||||||
|             None => s, |             None => s, | ||||||
|             Some(_) => &s[..idx.unwrap()] |             Some(_) => &s[..idx.unwrap()] | ||||||
|         }; |         }; | ||||||
|  |  | ||||||
|         let hostname = if hostname_encoded.starts_with("[") { |  | ||||||
|             if !hostname_encoded.ends_with("]") { |  | ||||||
|                 return Err(::Error::Header) |  | ||||||
|             } |  | ||||||
|             hostname_encoded.to_owned() |  | ||||||
|         } else { |  | ||||||
|             let (hostname, res) = domain_to_unicode(hostname_encoded); |  | ||||||
|             if res.is_err() { |  | ||||||
|                 return Err(::Error::Header) |  | ||||||
|             } |  | ||||||
|             hostname |  | ||||||
|         }; |  | ||||||
|  |  | ||||||
|         Ok(Host { |         Ok(Host { | ||||||
|             hostname: hostname, |             hostname: hostname.to_owned().into(), | ||||||
|             port: port |             port: port, | ||||||
|         }) |         }) | ||||||
|     } |     } | ||||||
| } | } | ||||||
| @@ -109,35 +109,20 @@ mod tests { | |||||||
|     #[test] |     #[test] | ||||||
|     fn test_host() { |     fn test_host() { | ||||||
|         let host = Header::parse_header(&vec![b"foo.com".to_vec()].into()); |         let host = Header::parse_header(&vec![b"foo.com".to_vec()].into()); | ||||||
|         assert_eq!(host.ok(), Some(Host { |         assert_eq!(host.ok(), Some(Host::new("foo.com", None))); | ||||||
|             hostname: "foo.com".to_owned(), |  | ||||||
|             port: None |  | ||||||
|         })); |  | ||||||
|  |  | ||||||
|  |  | ||||||
|         let host = Header::parse_header(&vec![b"foo.com:8080".to_vec()].into()); |         let host = Header::parse_header(&vec![b"foo.com:8080".to_vec()].into()); | ||||||
|         assert_eq!(host.ok(), Some(Host { |         assert_eq!(host.ok(), Some(Host::new("foo.com", 8080))); | ||||||
|             hostname: "foo.com".to_owned(), |  | ||||||
|             port: Some(8080) |  | ||||||
|         })); |  | ||||||
|  |  | ||||||
|         let host = Header::parse_header(&vec![b"foo.com".to_vec()].into()); |         let host = Header::parse_header(&vec![b"foo.com".to_vec()].into()); | ||||||
|         assert_eq!(host.ok(), Some(Host { |         assert_eq!(host.ok(), Some(Host::new("foo.com", None))); | ||||||
|             hostname: "foo.com".to_owned(), |  | ||||||
|             port: None |  | ||||||
|         })); |  | ||||||
|  |  | ||||||
|         let host = Header::parse_header(&vec![b"[::1]:8080".to_vec()].into()); |         let host = Header::parse_header(&vec![b"[::1]:8080".to_vec()].into()); | ||||||
|         assert_eq!(host.ok(), Some(Host { |         assert_eq!(host.ok(), Some(Host::new("[::1]", 8080))); | ||||||
|             hostname: "[::1]".to_owned(), |  | ||||||
|             port: Some(8080) |  | ||||||
|         })); |  | ||||||
|  |  | ||||||
|         let host = Header::parse_header(&vec![b"[::1]".to_vec()].into()); |         let host = Header::parse_header(&vec![b"[::1]".to_vec()].into()); | ||||||
|         assert_eq!(host.ok(), Some(Host { |         assert_eq!(host.ok(), Some(Host::new("[::1]", None))); | ||||||
|             hostname: "[::1]".to_owned(), |  | ||||||
|             port: None |  | ||||||
|         })); |  | ||||||
|     } |     } | ||||||
| } | } | ||||||
|  |  | ||||||
|   | |||||||
| @@ -43,10 +43,7 @@ impl Origin { | |||||||
|     pub fn new<S: Into<String>, H: Into<String>>(scheme: S, hostname: H, port: Option<u16>) -> Origin{ |     pub fn new<S: Into<String>, H: Into<String>>(scheme: S, hostname: H, port: Option<u16>) -> Origin{ | ||||||
|         Origin { |         Origin { | ||||||
|             scheme: scheme.into(), |             scheme: scheme.into(), | ||||||
|             host: Host { |             host: Host::new(hostname.into(), port), | ||||||
|                 hostname: hostname.into(), |  | ||||||
|                 port: port |  | ||||||
|             } |  | ||||||
|         } |         } | ||||||
|     } |     } | ||||||
| } | } | ||||||
|   | |||||||
| @@ -683,10 +683,10 @@ mod tests { | |||||||
|     } |     } | ||||||
|  |  | ||||||
|     #[test] |     #[test] | ||||||
|     fn test_headers_show() { |     fn test_headers_to_string() { | ||||||
|         let mut headers = Headers::new(); |         let mut headers = Headers::new(); | ||||||
|         headers.set(ContentLength(15)); |         headers.set(ContentLength(15)); | ||||||
|         headers.set(Host { hostname: "foo.bar".to_owned(), port: None }); |         headers.set(Host::new("foo.bar", None)); | ||||||
|  |  | ||||||
|         let s = headers.to_string(); |         let s = headers.to_string(); | ||||||
|         assert!(s.contains("Host: foo.bar\r\n")); |         assert!(s.contains("Host: foo.bar\r\n")); | ||||||
| @@ -694,7 +694,7 @@ mod tests { | |||||||
|     } |     } | ||||||
|  |  | ||||||
|     #[test] |     #[test] | ||||||
|     fn test_headers_show_raw() { |     fn test_headers_to_string_raw() { | ||||||
|         let headers = Headers::from_raw(&raw!(b"Content-Length: 10")).unwrap(); |         let headers = Headers::from_raw(&raw!(b"Content-Length: 10")).unwrap(); | ||||||
|         let s = headers.to_string(); |         let s = headers.to_string(); | ||||||
|         assert_eq!(s, "Content-Length: 10\r\n"); |         assert_eq!(s, "Content-Length: 10\r\n"); | ||||||
| @@ -766,7 +766,7 @@ mod tests { | |||||||
|         assert_eq!(headers1, headers2); |         assert_eq!(headers1, headers2); | ||||||
|  |  | ||||||
|         headers1.set(ContentLength(11)); |         headers1.set(ContentLength(11)); | ||||||
|         headers2.set(Host {hostname: "foo.bar".to_owned(), port: None}); |         headers2.set(Host::new("foo.bar", None)); | ||||||
|         assert!(headers1 != headers2); |         assert!(headers1 != headers2); | ||||||
|  |  | ||||||
|         headers1 = Headers::new(); |         headers1 = Headers::new(); | ||||||
| @@ -782,7 +782,7 @@ mod tests { | |||||||
|         headers1 = Headers::new(); |         headers1 = Headers::new(); | ||||||
|         headers2 = Headers::new(); |         headers2 = Headers::new(); | ||||||
|  |  | ||||||
|         headers1.set(Host { hostname: "foo.bar".to_owned(), port: None }); |         headers1.set(Host::new("foo.bar", None)); | ||||||
|         headers1.set(ContentLength(11)); |         headers1.set(ContentLength(11)); | ||||||
|         headers2.set(ContentLength(11)); |         headers2.set(ContentLength(11)); | ||||||
|         assert!(headers1 != headers2); |         assert!(headers1 != headers2); | ||||||
|   | |||||||
		Reference in New Issue
	
	Block a user