rama_http_headers/common/
host.rs

1use std::convert::TryFrom;
2use std::fmt;
3use std::net::IpAddr;
4
5use bytes::Bytes;
6use rama_http_types::dep::http::uri;
7use rama_http_types::{HeaderName, HeaderValue};
8use rama_net::address;
9
10use crate::{Error, Header};
11
12/// The `Host` header.
13#[derive(Clone, Debug, PartialEq, Eq, Hash, PartialOrd)]
14pub struct Host {
15    host: address::Host,
16    port: Option<u16>,
17}
18
19impl Host {
20    /// Get the [`address::Host`], such as example.domain.
21    pub fn host(&self) -> &address::Host {
22        &self.host
23    }
24
25    /// Get the optional port number.
26    pub fn port(&self) -> Option<u16> {
27        self.port
28    }
29
30    /// Consume self into its parts: `(host, ?port)`
31    pub fn into_parts(self) -> (address::Host, Option<u16>) {
32        (self.host, self.port)
33    }
34}
35
36impl Header for Host {
37    fn name() -> &'static HeaderName {
38        &::rama_http_types::header::HOST
39    }
40
41    fn decode<'i, I: Iterator<Item = &'i HeaderValue>>(values: &mut I) -> Result<Self, Error> {
42        let auth = values
43            .next()
44            .and_then(|val| uri::Authority::try_from(val.as_bytes()).ok())
45            .ok_or_else(Error::invalid)?;
46        let host = address::Host::try_from(auth.host()).map_err(|_| Error::invalid())?;
47        let port = auth.port_u16();
48        Ok(Self { host, port })
49    }
50
51    fn encode<E: Extend<HeaderValue>>(&self, values: &mut E) {
52        let s = self.to_string();
53        let bytes = Bytes::from_owner(s);
54        let val = HeaderValue::from_maybe_shared(bytes).expect("Authority is a valid HeaderValue");
55
56        values.extend(::std::iter::once(val));
57    }
58}
59
60impl From<address::Host> for Host {
61    fn from(host: address::Host) -> Host {
62        Host { host, port: None }
63    }
64}
65
66impl From<address::Authority> for Host {
67    fn from(auth: address::Authority) -> Host {
68        let (host, port) = auth.into_parts();
69        Host {
70            host,
71            port: Some(port),
72        }
73    }
74}
75
76impl fmt::Display for Host {
77    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
78        match self.port {
79            Some(port) => match &self.host {
80                address::Host::Address(IpAddr::V6(ip)) => write!(f, "[{ip}]:{port}"),
81                host => write!(f, "{host}:{port}"),
82            },
83            None => self.host.fmt(f),
84        }
85    }
86}