use crate::uri::Uri;
use crate::validate::trim_ows;
use core::fmt;
#[derive(Debug, Clone, PartialEq, Eq)]
#[non_exhaustive]
pub enum ContentLocationError {
Empty,
InvalidUri,
FragmentNotAllowed,
}
impl fmt::Display for ContentLocationError {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self {
ContentLocationError::Empty => write!(f, "empty Content-Location"),
ContentLocationError::InvalidUri => write!(f, "invalid Content-Location URI"),
ContentLocationError::FragmentNotAllowed => {
write!(f, "Content-Location must not contain a fragment")
}
}
}
}
impl core::error::Error for ContentLocationError {}
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct ContentLocation {
uri: Uri,
}
impl ContentLocation {
pub fn parse(input: &str) -> Result<Self, ContentLocationError> {
let input = trim_ows(input);
if input.is_empty() {
return Err(ContentLocationError::Empty);
}
let uri = Uri::parse(input).map_err(|_| ContentLocationError::InvalidUri)?;
if let Some(scheme) = uri.scheme()
&& (scheme.eq_ignore_ascii_case("http") || scheme.eq_ignore_ascii_case("https"))
&& uri.host().is_none_or(|h| h.is_empty())
{
return Err(ContentLocationError::InvalidUri);
}
if uri.fragment().is_some() {
return Err(ContentLocationError::FragmentNotAllowed);
}
Ok(ContentLocation { uri })
}
pub fn uri(&self) -> &Uri {
&self.uri
}
}
impl fmt::Display for ContentLocation {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "{}", self.uri)
}
}