use std::{borrow::Cow, fmt, str};
use actix_web::{
http::header::{HeaderValue, InvalidHeaderValue, TryIntoHeaderValue},
web::{BufMut, Bytes, BytesMut},
};
use super::Challenge;
use crate::utils;
#[derive(Eq, PartialEq, Ord, PartialOrd, Hash, Debug, Default, Clone)]
pub struct Basic {
pub(crate) realm: Option<Cow<'static, str>>,
}
impl Basic {
pub fn new() -> Basic {
Default::default()
}
pub fn with_realm<T>(value: T) -> Basic
where
T: Into<Cow<'static, str>>,
{
Basic {
realm: Some(value.into()),
}
}
}
#[doc(hidden)]
impl Challenge for Basic {
fn to_bytes(&self) -> Bytes {
let length = 5 + self.realm.as_ref().map_or(0, |realm| realm.len() + 9);
let mut buffer = BytesMut::with_capacity(length);
buffer.put(&b"Basic"[..]);
if let Some(ref realm) = self.realm {
buffer.put(&b" realm=\""[..]);
utils::put_quoted(&mut buffer, realm);
buffer.put_u8(b'"');
}
buffer.freeze()
}
}
impl fmt::Display for Basic {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> Result<(), fmt::Error> {
let bytes = self.to_bytes();
let repr = str::from_utf8(&bytes)
.map_err(|_| fmt::Error)?;
f.write_str(repr)
}
}
impl TryIntoHeaderValue for Basic {
type Error = InvalidHeaderValue;
fn try_into_value(self) -> Result<HeaderValue, Self::Error> {
HeaderValue::from_maybe_shared(self.to_bytes())
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_plain_into_header_value() {
let challenge = Basic { realm: None };
let value = challenge.try_into_value();
assert!(value.is_ok());
let value = value.unwrap();
assert_eq!(value, "Basic");
}
#[test]
fn test_with_realm_into_header_value() {
let challenge = Basic {
realm: Some("Restricted area".into()),
};
let value = challenge.try_into_value();
assert!(value.is_ok());
let value = value.unwrap();
assert_eq!(value, "Basic realm=\"Restricted area\"");
}
}