typed_headers/impls/
host.rs1use bytes::Bytes;
2use http::header::{self, HeaderName, HeaderValue, HOST};
3use http::uri::Authority;
4
5use crate::{Error, Header, ToValues};
6
7#[derive(Debug, Clone)]
22pub struct Host {
23 host: String,
24 port: Option<u16>,
25}
26
27impl Host {
28 #[inline]
30 pub fn new(host: &'static str, port: Option<u16>) -> Result<Host, Error> {
31 let authority = match port {
33 Some(port) => Bytes::from(format!("{}:{}", host, port)),
34 None => Bytes::from(host),
35 };
36 let authority = Authority::from_maybe_shared(authority).map_err(|_| Error::invalid_value())?;
37
38 Ok(Host::from_authority(&authority))
39 }
40
41 #[inline]
45 pub fn from_authority(authority: &Authority) -> Host {
46 Host {
47 host: authority.host().to_string(),
48 port: authority.port_u16(),
49 }
50 }
51
52 #[inline]
54 pub fn host(&self) -> &str {
55 &self.host
56 }
57
58 #[inline]
60 pub fn port(&self) -> Option<u16> {
61 self.port
62 }
63}
64
65impl Header for Host {
66 #[inline]
67 fn name() -> &'static HeaderName {
68 &HOST
69 }
70
71 #[inline]
72 fn from_values<'a>(
73 values: &mut header::ValueIter<'a, HeaderValue>,
74 ) -> Result<Option<Host>, Error> {
75 let value = match values.next() {
76 Some(value) => value,
77 None => return Ok(None),
78 };
79
80 let authority = Authority::from_maybe_shared(Bytes::copy_from_slice(value.as_bytes()))
81 .map_err(|_| Error::invalid_value())?;
82 if authority.as_str().contains('@') {
84 return Err(Error::invalid_value());
85 }
86
87 Ok(Some(Host::from_authority(&authority)))
88 }
89
90 #[inline]
91 fn to_values(&self, values: &mut ToValues) {
92 let value = match self.port {
93 Some(port) => HeaderValue::from_str(&format!("{}:{}", self.host, port)),
94 None => HeaderValue::from_str(&self.host),
95 };
96 let value = value.expect("should have already validated contents");
97
98 values.append(value);
99 }
100}