Struct rocket_http::uri::Host
source · 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§
source§impl<'a> Host<'a>
impl<'a> Host<'a>
sourcepub const fn new(authority: Authority<'a>) -> Self
pub const fn new(authority: Authority<'a>) -> Self
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");
sourcepub 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);
sourcepub 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));
sourcepub 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]");
sourcepub 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());
sourcepub 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§
source§impl PartialEq<&str> for Host<'_>
impl PartialEq<&str> for Host<'_>
source§impl PartialEq<Host<'_>> for str
impl PartialEq<Host<'_>> for str
source§impl<'a, 'b> PartialEq<Host<'b>> for Host<'a>
impl<'a, 'b> PartialEq<Host<'b>> for Host<'a>
source§impl PartialEq<str> for Host<'_>
impl PartialEq<str> for Host<'_>
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§
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.