use std::collections::BTreeMap;
use crate::PrivOwnedStr;
#[derive(Clone, Debug, PartialEq, Eq)]
#[non_exhaustive]
pub enum AuthenticateError {
InsufficientScope {
scope: String,
},
#[doc(hidden)]
_Custom {
errcode: PrivOwnedStr,
attributes: AuthenticateAttrs,
},
}
#[doc(hidden)]
#[derive(Clone, Debug, PartialEq, Eq)]
pub struct AuthenticateAttrs(BTreeMap<String, String>);
impl AuthenticateError {
fn from_str(s: &str) -> Option<Self> {
if let Some(val) = s.strip_prefix("Bearer").map(str::trim) {
let mut errcode = None;
let mut attrs = BTreeMap::new();
for (key, value) in val
.split(',')
.filter_map(|attr| attr.trim().split_once('='))
.map(|(key, value)| (key, value.trim_matches('"')))
{
if key == "error" {
errcode = Some(value);
} else {
attrs.insert(key.to_owned(), value.to_owned());
}
}
if let Some(errcode) = errcode {
let error = if let Some(scope) = attrs.get("scope").filter(|_| errcode == "insufficient_scope") {
AuthenticateError::InsufficientScope {
scope: scope.to_owned(),
}
} else {
AuthenticateError::_Custom {
errcode: PrivOwnedStr(errcode.into()),
attributes: AuthenticateAttrs(attrs),
}
};
return Some(error);
}
}
None
}
}
impl TryFrom<&AuthenticateError> for http::HeaderValue {
type Error = http::header::InvalidHeaderValue;
fn try_from(error: &AuthenticateError) -> Result<Self, Self::Error> {
let s = match error {
AuthenticateError::InsufficientScope { scope } => {
format!("Bearer error=\"insufficient_scope\", scope=\"{scope}\"")
}
AuthenticateError::_Custom { errcode, attributes } => {
let mut s = format!("Bearer error=\"{}\"", errcode.0);
for (key, value) in attributes.0.iter() {
s.push_str(&format!(", {key}=\"{value}\""));
}
s
}
};
s.try_into()
}
}