use serde::{Deserialize, Serialize};
#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
pub enum HttpParameterLocation {
Header,
Query,
Cookie,
}
impl HttpParameterLocation {
pub fn parse(value: &str) -> Option<Self> {
match value.to_ascii_lowercase().as_str() {
"header" => Some(Self::Header),
"query" => Some(Self::Query),
"cookie" => Some(Self::Cookie),
_ => None,
}
}
pub fn as_str(self) -> &'static str {
match self {
Self::Header => "header",
Self::Query => "query",
Self::Cookie => "cookie",
}
}
pub fn names_equal(self, first: &str, second: &str) -> bool {
match self {
Self::Header => first.eq_ignore_ascii_case(second),
Self::Query | Self::Cookie => first == second,
}
}
pub fn valid_name(self, name: &str) -> bool {
match self {
Self::Header | Self::Cookie => http::HeaderName::from_bytes(name.as_bytes()).is_ok(),
Self::Query => !name.is_empty() && !name.chars().any(char::is_control),
}
}
}
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
pub struct VersionParameter {
pub location: HttpParameterLocation,
pub name: String,
}
impl VersionParameter {
pub(crate) fn validate_value(&self, value: &str) -> Result<(), String> {
if self.location == HttpParameterLocation::Header {
if value.trim_matches([' ', '\t']) != value {
return Err(
"version header value cannot start or end with HTTP whitespace".to_string(),
);
}
let header = http::HeaderValue::from_str(value)
.map_err(|error| format!("invalid version header value: {error}"))?;
header
.to_str()
.map_err(|error| format!("version header value must be visible ASCII: {error}"))?;
}
Ok(())
}
}