use alloc::string::{String, ToString};
use alloc::vec::Vec;
use core::fmt;
use crate::validate::{
QuotedStringError, escape_quotes, is_token_char, is_valid_token, parse_quoted_string,
split_with_quotes, trim_ows,
};
#[derive(Debug, Clone, PartialEq, Eq)]
#[non_exhaustive]
pub enum ExpectError {
Empty,
InvalidFormat,
InvalidToken,
InvalidValue,
UnterminatedQuote,
}
impl fmt::Display for ExpectError {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self {
ExpectError::Empty => write!(f, "empty Expect header"),
ExpectError::InvalidFormat => write!(f, "invalid Expect header format"),
ExpectError::InvalidToken => write!(f, "invalid Expect token"),
ExpectError::InvalidValue => write!(f, "invalid Expect value"),
ExpectError::UnterminatedQuote => write!(f, "unterminated quoted-string"),
}
}
}
impl core::error::Error for ExpectError {}
impl From<QuotedStringError> for ExpectError {
fn from(e: QuotedStringError) -> Self {
match e {
QuotedStringError::InvalidQdtext | QuotedStringError::InvalidQuotedPair => {
ExpectError::InvalidValue
}
QuotedStringError::Unterminated => ExpectError::UnterminatedQuote,
}
}
}
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct Expect {
items: Vec<Expectation>,
}
impl Expect {
pub fn parse(input: &str) -> Result<Self, ExpectError> {
let input = trim_ows(input);
let mut items = Vec::new();
for part in split_with_quotes(input, ',') {
let part = trim_ows(&part);
if part.is_empty() {
continue;
}
let (token, value) = if let Some((token, value)) = part.split_once('=') {
let token = trim_ows(token);
if token.is_empty() {
return Err(ExpectError::InvalidFormat);
}
let value = parse_value(value)?;
(token, Some(value))
} else {
(part, None)
};
if !is_valid_token(token) {
return Err(ExpectError::InvalidToken);
}
items.push(Expectation {
token: token.to_ascii_lowercase(),
value,
});
}
Ok(Expect { items })
}
pub fn items(&self) -> &[Expectation] {
&self.items
}
pub fn has_100_continue(&self) -> bool {
self.items
.iter()
.any(|item| item.token.eq_ignore_ascii_case("100-continue"))
}
}
impl fmt::Display for Expect {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
let values: Vec<String> = self.items.iter().map(|item| item.to_string()).collect();
write!(f, "{}", values.join(", "))
}
}
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct Expectation {
token: String,
value: Option<String>,
}
impl Expectation {
pub fn token(&self) -> &str {
&self.token
}
pub fn value(&self) -> Option<&str> {
self.value.as_deref()
}
pub fn is_100_continue(&self) -> bool {
self.token.eq_ignore_ascii_case("100-continue")
}
}
impl fmt::Display for Expectation {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match &self.value {
Some(value) => {
if needs_quoting(value) {
write!(f, "{}=\"{}\"", self.token, escape_quotes(value))
} else {
write!(f, "{}={}", self.token, value)
}
}
None => write!(f, "{}", self.token),
}
}
}
fn parse_value(input: &str) -> Result<String, ExpectError> {
let input = trim_ows(input);
if input.is_empty() {
return Err(ExpectError::InvalidValue);
}
if let Some(rest) = input.strip_prefix('"') {
let (value, remaining) = parse_quoted_string(rest)?;
if !trim_ows(remaining).is_empty() {
return Err(ExpectError::InvalidValue);
}
Ok(value)
} else if !is_valid_token(input) {
Err(ExpectError::InvalidValue)
} else {
Ok(input.to_string())
}
}
fn needs_quoting(s: &str) -> bool {
s.is_empty() || s.bytes().any(|b| !is_token_char(b))
}