ruma_common/http_headers/
rfc8187.rsuse std::borrow::Cow;
use percent_encoding::{AsciiSet, NON_ALPHANUMERIC};
const ATTR_CHAR: AsciiSet = NON_ALPHANUMERIC
.remove(b'!')
.remove(b'#')
.remove(b'$')
.remove(b'&')
.remove(b'+')
.remove(b'-')
.remove(b'.')
.remove(b'^')
.remove(b'_')
.remove(b'`')
.remove(b'|')
.remove(b'~');
pub(super) fn encode(s: &str) -> String {
let encoded = percent_encoding::utf8_percent_encode(s, &ATTR_CHAR);
format!("utf-8''{encoded}")
}
pub(super) fn decode(bytes: &[u8]) -> Result<Cow<'_, str>, Rfc8187DecodeError> {
if bytes.is_empty() {
return Err(Rfc8187DecodeError::Empty);
}
let mut parts = bytes.split(|b| *b == b'\'');
let charset = parts.next().ok_or(Rfc8187DecodeError::WrongPartsCount)?;
let _lang = parts.next().ok_or(Rfc8187DecodeError::WrongPartsCount)?;
let encoded = parts.next().ok_or(Rfc8187DecodeError::WrongPartsCount)?;
if parts.next().is_some() {
return Err(Rfc8187DecodeError::WrongPartsCount);
}
if !charset.eq_ignore_ascii_case(b"utf-8") {
return Err(Rfc8187DecodeError::NotUtf8);
}
Ok(percent_encoding::percent_decode(encoded).decode_utf8_lossy())
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, thiserror::Error)]
#[non_exhaustive]
pub(super) enum Rfc8187DecodeError {
#[error("string is empty")]
Empty,
#[error("string does not contain the right number of parts")]
WrongPartsCount,
#[error("character set is not UTF-8")]
NotUtf8,
}