leyline-http 0.1.1

HTTP client that mimics browsers on the wire
Documentation
use url::Url;

use crate::cookie::parse::registrable_domain;

#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
#[non_exhaustive]
pub enum FetchSite {
    SameOrigin,
    SameSite,
    CrossSite,
}

impl FetchSite {
    #[must_use]
    pub fn of(context: &Url, request: &Url) -> Self {
        if context.origin() == request.origin() {
            return Self::SameOrigin;
        }
        let same_site = context.scheme() == request.scheme()
            && match (context.host_str(), request.host_str()) {
                (Some(a), Some(b)) => match (registrable_domain(a), registrable_domain(b)) {
                    (Some(da), Some(db)) => da == db,
                    _ => a == b,
                },
                _ => false,
            };
        if same_site {
            Self::SameSite
        } else {
            Self::CrossSite
        }
    }

    pub(crate) fn across<'a>(context: &Url, chain: impl IntoIterator<Item = &'a Url>) -> Self {
        chain
            .into_iter()
            .map(|url| Self::of(context, url))
            .max_by_key(|site| match site {
                Self::SameOrigin => 0,
                Self::SameSite => 1,
                Self::CrossSite => 2,
            })
            .unwrap_or(Self::SameOrigin)
    }

    #[must_use]
    pub fn as_str(self) -> &'static str {
        match self {
            Self::SameOrigin => "same-origin",
            Self::SameSite => "same-site",
            Self::CrossSite => "cross-site",
        }
    }
}

impl std::fmt::Display for FetchSite {
    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
        f.write_str(self.as_str())
    }
}