use std::fmt;
use crate::{authority::Authority, error::Error, request::Request};
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
pub(crate) struct Origin {
pub(crate) host: String,
pub(crate) port: u16,
}
impl Origin {
pub(crate) fn from_request(request: &Request) -> Result<Origin, Error> {
let url = request.url();
let host = url
.host_str()
.ok_or_else(|| {
Error::InvalidRequest {
reason: "URL has no host".into(),
}
})?
.to_string();
let port = url.port_or_known_default().unwrap_or(443);
Ok(Origin { host, port })
}
pub(crate) fn from_authority(authority: &Authority) -> Origin {
Origin {
host: authority.host().to_string(),
port: authority.port(),
}
}
}
impl fmt::Display for Origin {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "{}:{}", self.host, self.port)
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn port_defaults_to_443() {
let req = Request::get("https://example.org/x").build().unwrap();
let origin = Origin::from_request(&req).unwrap();
assert_eq!(origin.host, "example.org");
assert_eq!(origin.port, 443);
}
#[test]
fn explicit_port_is_used() {
let req = Request::get("https://example.org:8443/").build().unwrap();
let origin = Origin::from_request(&req).unwrap();
assert_eq!(origin.port, 8443);
}
#[test]
fn same_url_same_origin_regardless_of_path() {
let a = Origin::from_request(&Request::get("https://example.org/a").build().unwrap());
let b = Origin::from_request(&Request::get("https://example.org/b?x=1").build().unwrap());
assert_eq!(a.unwrap(), b.unwrap());
}
#[test]
fn authority_is_a_dns_origin() {
let authority = Authority::new("example.org", 8443).unwrap();
let origin = Origin::from_authority(&authority);
assert_eq!(origin.host, "example.org");
assert_eq!(origin.port, 8443);
}
}