pub struct Host<'a>(_);
Expand description
A domain and port identified by a client as the server being messaged.
For requests made via HTTP/1.1, a host is identified via the HOST
header.
In HTTP/2 and HTTP/3, this information is instead communicated via the
:authority
and :port
pseudo-header request fields. It is a
client-controlled value via which the client communicates to the server the
domain name and port it is attempting to communicate with. The following
diagram illustrates the syntactic structure of a Host
:
some.domain.foo:8088
|-------------| |--|
domain port
Only the domain part is required. Its value is case-insensitive.
URI Construction
A Host
is not a Uri
, and none of Rocket’s APIs will
accept a Host
value as such. This is because doing so would facilitate the
construction of URIs to internal routes in a manner controllable by an
attacker, inevitably leading to “HTTP Host header attacks”.
Instead, a Host
must be checked before being converted to a [Uri
]
value. The Host::to_authority
and Host::to_absolute
methods provide
these mechanisms:
use rocket::http::uri::Host;
// A sensitive URI we want to prefix with safe hosts.
#[get("/token?<secret>")]
fn token(secret: Token) { /* .. */ }
// Whitelist of known hosts. In a real setting, you might retrieve this
// list from config at ignite-time using tools like `AdHoc::config()`.
const WHITELIST: [Host<'static>; 4] = [
Host::new(uri!("rocket.rs")),
Host::new(uri!("rocket.rs:443")),
Host::new(uri!("guide.rocket.rs")),
Host::new(uri!("guide.rocket.rs:443")),
];
// Use `Host::to_absolute()` to case-insensitively check a host against a
// whitelist, returning an `Absolute` usable as a `uri!()` prefix.
let host = Host::new(uri!("guide.ROCKET.rs"));
let prefix = host.to_absolute("https", &WHITELIST);
// Since `guide.rocket.rs` is in the whitelist, `prefix` is `Some`.
assert!(prefix.is_some());
if let Some(prefix) = prefix {
// We can use this prefix to safely construct URIs.
let uri = uri!(prefix, token("some-secret-token"));
assert_eq!(uri, "https://guide.ROCKET.rs/token?secret=some-secret-token");
}
(De)serialization
Host
is both Serialize
and Deserialize
:
use serde::{Serialize, Deserialize};
use rocket::http::uri::Host;
#[derive(Deserialize, Serialize)]
struct UriOwned {
uri: Host<'static>,
}
#[derive(Deserialize, Serialize)]
struct UriBorrowed<'a> {
uri: Host<'a>,
}
Implementations§
§impl<'a> Host<'a>
impl<'a> Host<'a>
pub const fn new(authority: Authority<'a>) -> Host<'a>
pub const fn new(authority: Authority<'a>) -> Host<'a>
Create a new Host
from an Authority
. Only the host
and port
parts are preserved.
use rocket::http::uri::Host;
let host = Host::new(uri!("developer.mozilla.org"));
assert_eq!(host.to_string(), "developer.mozilla.org");
let host = Host::new(uri!("foo:bar@developer.mozilla.org:1234"));
assert_eq!(host.to_string(), "developer.mozilla.org:1234");
let host = Host::new(uri!("rocket.rs:443"));
assert_eq!(host.to_string(), "rocket.rs:443");
pub fn parse(string: &'a str) -> Result<Host<'a>, Error<'a>>
pub fn parse(string: &'a str) -> Result<Host<'a>, Error<'a>>
Parses the string string
into a Host
. Parsing will never allocate.
Returns an Error
if string
is not a valid authority URI, meaning
that this parser accepts a user_info
part for compatibility but
discards it.
Example
use rocket::http::uri::Host;
// Parse from a valid authority URI.
let host = Host::parse("user:pass@domain").expect("valid host");
assert_eq!(host.domain(), "domain");
assert_eq!(host.port(), None);
// Parse from a valid host.
let host = Host::parse("domain:311").expect("valid host");
assert_eq!(host.domain(), "doMaIN");
assert_eq!(host.port(), Some(311));
// Invalid hosts fail to parse.
Host::parse("https://rocket.rs").expect_err("invalid host");
// Prefer to use `uri!()` when the input is statically known:
let host = Host::new(uri!("domain"));
assert_eq!(host.domain(), "domain");
assert_eq!(host.port(), None);
pub fn parse_owned(string: String) -> Result<Host<'static>, Error<'static>>
pub fn parse_owned(string: String) -> Result<Host<'static>, Error<'static>>
Parses the string string
into an Host
. Parsing never allocates
on success. May allocate on error.
This method should be used instead of Host::parse()
when the source
is already a String
. Returns an Error
if string
is not a valid
authority URI, meaning that this parser accepts a user_info
part for
compatibility but discards it.
Example
use rocket::http::uri::Host;
let source = format!("rocket.rs:8000");
let host = Host::parse_owned(source).expect("valid host");
assert_eq!(host.domain(), "rocket.rs");
assert_eq!(host.port(), Some(8000));
pub fn domain(&self) -> &UncasedStr
pub fn domain(&self) -> &UncasedStr
Returns the case-insensitive domain part of the host.
Example
use rocket::http::uri::Host;
let host = Host::new(uri!("domain.com:123"));
assert_eq!(host.domain(), "domain.com");
let host = Host::new(uri!("username:password@domain:123"));
assert_eq!(host.domain(), "domain");
let host = Host::new(uri!("[1::2]:123"));
assert_eq!(host.domain(), "[1::2]");
pub fn port(&self) -> Option<u16>
pub fn port(&self) -> Option<u16>
Returns the port part of the host, if there is one.
Example
use rocket::http::uri::Host;
// With a port.
let host = Host::new(uri!("domain:123"));
assert_eq!(host.port(), Some(123));
let host = Host::new(uri!("domain.com:8181"));
assert_eq!(host.port(), Some(8181));
// Without a port.
let host = Host::new(uri!("domain.foo.bar.tld"));
assert_eq!(host.port(), None);
Checks self
against whitelist
. If self
is in whitelist
, returns
an Authority
URI representing self. Otherwise, returns None
.
Domain comparison is case-insensitive.
See URI construction for more.
Example
use rocket::http::uri::Host;
let whitelist = &[Host::new(uri!("domain.tld"))];
// A host in the whitelist returns `Some`.
let host = Host::new(uri!("domain.tld"));
let uri = host.to_authority(whitelist);
assert!(uri.is_some());
assert_eq!(uri.unwrap().to_string(), "domain.tld");
let host = Host::new(uri!("foo:bar@doMaIN.tLd"));
let uri = host.to_authority(whitelist);
assert!(uri.is_some());
assert_eq!(uri.unwrap().to_string(), "doMaIN.tLd");
// A host _not_ in the whitelist returns `None`.
let host = Host::new(uri!("domain.tld:1234"));
let uri = host.to_authority(whitelist);
assert!(uri.is_none());
pub fn to_absolute<'h, W>(
&self,
scheme: &'a str,
whitelist: W
) -> Option<Absolute<'a>>where
W: IntoIterator<Item = &'h Host<'h>>,
pub fn to_absolute<'h, W>( &self, scheme: &'a str, whitelist: W ) -> Option<Absolute<'a>>where W: IntoIterator<Item = &'h Host<'h>>,
Checks self
against whitelist
. If self
is in whitelist
, returns
an Absolute
URI representing self
with scheme scheme
. Otherwise,
returns None
. Domain comparison is case-insensitive.
See URI construction for more.
Example
use rocket::http::uri::Host;
let whitelist = &[Host::new(uri!("domain.tld:443"))];
// A host in the whitelist returns `Some`.
let host = Host::new(uri!("user@domain.tld:443"));
let uri = host.to_absolute("http", whitelist);
assert!(uri.is_some());
assert_eq!(uri.unwrap().to_string(), "http://domain.tld:443");
let host = Host::new(uri!("domain.TLD:443"));
let uri = host.to_absolute("https", whitelist);
assert!(uri.is_some());
assert_eq!(uri.unwrap().to_string(), "https://domain.TLD:443");
// A host _not_ in the whitelist returns `None`.
let host = Host::new(uri!("domain.tld"));
let uri = host.to_absolute("http", whitelist);
assert!(uri.is_none());
Trait Implementations§
§impl<'a, 'de> Deserialize<'de> for Host<'a>
impl<'a, 'de> Deserialize<'de> for Host<'a>
§fn deserialize<D>(
deserializer: D
) -> Result<Host<'a>, <D as Deserializer<'de>>::Error>where
D: Deserializer<'de>,
fn deserialize<D>( deserializer: D ) -> Result<Host<'a>, <D as Deserializer<'de>>::Error>where D: Deserializer<'de>,
source§impl<'r> FromRequest<'r> for &'r Host<'r>
impl<'r> FromRequest<'r> for &'r Host<'r>
§type Error = Infallible
type Error = Infallible
§impl<'a> Serialize for Host<'a>
impl<'a> Serialize for Host<'a>
§fn serialize<S>(
&self,
serializer: S
) -> Result<<S as Serializer>::Ok, <S as Serializer>::Error>where
S: Serializer,
fn serialize<S>( &self, serializer: S ) -> Result<<S as Serializer>::Ok, <S as Serializer>::Error>where S: Serializer,
impl Eq for Host<'_>
Auto Trait Implementations§
impl<'a> RefUnwindSafe for Host<'a>
impl<'a> Send for Host<'a>
impl<'a> Sync for Host<'a>
impl<'a> Unpin for Host<'a>
impl<'a> UnwindSafe for Host<'a>
Blanket Implementations§
§impl<'a, T> AsTaggedExplicit<'a> for Twhere
T: 'a,
impl<'a, T> AsTaggedExplicit<'a> for Twhere T: 'a,
§impl<'a, T> AsTaggedImplicit<'a> for Twhere
T: 'a,
impl<'a, T> AsTaggedImplicit<'a> for Twhere T: 'a,
source§impl<Q, K> Equivalent<K> for Qwhere
Q: Eq + ?Sized,
K: Borrow<Q> + ?Sized,
impl<Q, K> Equivalent<K> for Qwhere Q: Eq + ?Sized, K: Borrow<Q> + ?Sized,
source§fn equivalent(&self, key: &K) -> bool
fn equivalent(&self, key: &K) -> bool
key
and return true
if they are equal.source§impl<T> Instrument for T
impl<T> Instrument for T
source§fn instrument(self, span: Span) -> Instrumented<Self>
fn instrument(self, span: Span) -> Instrumented<Self>
source§fn in_current_span(self) -> Instrumented<Self>
fn in_current_span(self) -> Instrumented<Self>
§impl<T> IntoCollection<T> for T
impl<T> IntoCollection<T> for T
§fn into_collection<A>(self) -> SmallVec<A>where
A: Array<Item = T>,
fn into_collection<A>(self) -> SmallVec<A>where A: Array<Item = T>,
self
into a collection.