mod format;
mod parse;
mod pc;
mod util;
pub use format::*;
pub use parse::*;
pub use util::*;
use std::{collections::VecDeque, fmt::Display, ops::Index};
use serde::{Deserialize, Serialize};
use crate::{stringesc::StringLosslessExt, stringutil::CharClassExt};
#[derive(Debug, Clone, Serialize, Deserialize)]
#[serde(from = "Vec<FieldPair>")]
#[serde(into = "Vec<FieldPair>")]
pub struct HeaderMap {
pairs: Vec<FieldPair>,
}
impl HeaderMap {
pub fn new() -> Self {
Self { pairs: Vec::new() }
}
pub fn len(&self) -> usize {
self.pairs.len()
}
pub fn is_empty(&self) -> bool {
self.len() == 0
}
pub fn iter(&self) -> HeaderMapIter<'_> {
HeaderMapIter {
map: self,
index: 0,
}
}
pub fn contains_key<N: Into<String>>(&self, name: N) -> bool {
self.get(name).is_some()
}
pub fn get<N: Into<String>>(&self, name: N) -> Option<&FieldValue> {
let mut name = name.into();
name.make_ascii_lowercase();
for pair in &self.pairs {
if pair.name.normalized == name {
return Some(&pair.value);
}
}
None
}
pub fn get_all<N: Into<String>>(&self, name: N) -> FieldValuesIter<'_> {
let mut name = name.into();
name.make_ascii_lowercase();
FieldValuesIter {
name,
map: self,
index: 0,
}
}
pub fn get_str<N: Into<String>>(&self, name: N) -> Option<&str> {
match self.get(name) {
Some(field) => Some(field.text.as_ref()),
None => None,
}
}
pub fn append<N, V>(&mut self, name: N, value: V)
where
N: Into<FieldName>,
V: Into<FieldValue>,
{
self.pairs.push(FieldPair::new(name.into(), value.into()))
}
pub fn insert<N, V>(&mut self, name: N, value: V)
where
N: Into<FieldName>,
V: Into<FieldValue>,
{
let name = name.into();
self.pairs
.retain(|pair| pair.name.normalized != name.normalized);
self.pairs.push(FieldPair::new(name, value.into()));
}
pub fn reorder_front(&mut self, name: &str) {
let name = name.to_ascii_lowercase();
let mut input_pairs = VecDeque::from(std::mem::take(&mut self.pairs));
let mut high_priority = VecDeque::new();
let mut low_priority = VecDeque::new();
self.pairs.reserve(input_pairs.len());
while let Some(pair) = input_pairs.pop_front() {
if name == pair.name.normalized {
high_priority.push_back(pair);
} else {
low_priority.push_back(pair);
}
}
while let Some(pair) = high_priority.pop_front() {
self.pairs.push(pair);
}
while let Some(pair) = low_priority.pop_front() {
self.pairs.push(pair);
}
}
}
impl Default for HeaderMap {
fn default() -> Self {
Self::new()
}
}
impl<N: Into<String>> Index<N> for HeaderMap {
type Output = FieldValue;
fn index(&self, index: N) -> &Self::Output {
self.get(index).unwrap()
}
}
impl From<Vec<FieldPair>> for HeaderMap {
fn from(pairs: Vec<FieldPair>) -> Self {
Self { pairs }
}
}
impl From<HeaderMap> for Vec<FieldPair> {
fn from(header: HeaderMap) -> Self {
header.pairs
}
}
impl Display for HeaderMap {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
for pair in self.pairs.iter() {
pair.fmt(f)?;
}
Ok(())
}
}
pub struct HeaderMapIter<'a> {
map: &'a HeaderMap,
index: usize,
}
impl<'a> Iterator for HeaderMapIter<'a> {
type Item = &'a FieldPair;
fn next(&mut self) -> Option<Self::Item> {
match self.map.pairs.get(self.index) {
Some(item) => {
self.index += 1;
Some(item)
}
None => None,
}
}
}
pub struct FieldValuesIter<'a> {
name: String,
map: &'a HeaderMap,
index: usize,
}
impl<'a> Iterator for FieldValuesIter<'a> {
type Item = &'a FieldValue;
fn next(&mut self) -> Option<Self::Item> {
loop {
match self.map.pairs.get(self.index) {
Some(item) => {
self.index += 1;
if self.name == item.name.normalized {
return Some(&item.value);
}
}
None => return None,
}
}
}
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct FieldPair {
pub name: FieldName,
pub value: FieldValue,
}
impl FieldPair {
pub fn new(name: FieldName, value: FieldValue) -> Self {
Self { name, value }
}
}
impl From<(FieldName, FieldValue)> for FieldPair {
fn from(pair: (FieldName, FieldValue)) -> Self {
FieldPair::new(pair.0, pair.1)
}
}
impl Display for FieldPair {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
f.write_str(&self.name.to_text_lossy())?;
f.write_str(": ")?;
f.write_str(&self.value.to_text_lossy())?;
f.write_str("\r\n")?;
Ok(())
}
}
#[derive(Debug, Clone, Serialize, Deserialize)]
#[serde(from = "FieldNameDe")]
pub struct FieldName {
#[serde(skip)]
normalized: String,
pub text: String,
pub raw: Option<Vec<u8>>,
}
impl FieldName {
pub fn new(text: String, raw: Option<Vec<u8>>) -> Self {
Self {
normalized: text.to_ascii_lowercase(),
text,
raw,
}
}
pub fn to_text_lossy(&self) -> String {
self.text.replace(|c| !(c as u8).is_token(), "\u{FFFD}")
}
}
impl From<&str> for FieldName {
fn from(value: &str) -> Self {
Self::from(value.to_string())
}
}
impl From<String> for FieldName {
fn from(value: String) -> Self {
Self {
normalized: value.to_ascii_lowercase(),
text: value,
raw: None,
}
}
}
impl From<&[u8]> for FieldName {
fn from(value: &[u8]) -> Self {
Self::from(value.to_vec())
}
}
impl From<Vec<u8>> for FieldName {
fn from(value: Vec<u8>) -> Self {
let text = String::from_utf8_lossless(&value);
Self {
normalized: text.to_ascii_lowercase(),
text: text.to_string(),
raw: Some(value),
}
}
}
impl Display for FieldName {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
f.write_str(&self.text)
}
}
impl From<FieldNameDe> for FieldName {
fn from(original: FieldNameDe) -> Self {
Self {
normalized: original.text.to_ascii_lowercase(),
text: original.text,
raw: original.raw,
}
}
}
#[derive(Deserialize)]
struct FieldNameDe {
text: String,
raw: Option<Vec<u8>>,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct FieldValue {
pub text: String,
pub raw: Option<Vec<u8>>,
}
impl FieldValue {
pub fn new(text: String, raw: Option<Vec<u8>>) -> Self {
Self { text, raw }
}
pub fn to_text_lossy(&self) -> String {
self.text.replace(|c| c == '\r' || c == '\n', "\u{FFFD}")
}
}
impl From<&str> for FieldValue {
fn from(value: &str) -> Self {
Self::from(value.to_string())
}
}
impl From<String> for FieldValue {
fn from(value: String) -> Self {
Self {
text: value,
raw: None,
}
}
}
impl From<&[u8]> for FieldValue {
fn from(value: &[u8]) -> Self {
Self::from(value.to_vec())
}
}
impl From<Vec<u8>> for FieldValue {
fn from(value: Vec<u8>) -> Self {
Self {
text: String::from_utf8_lossless(&value),
raw: Some(value),
}
}
}
impl Display for FieldValue {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
f.write_str(&self.text)
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_header_get_convenience() {
let mut map = HeaderMap::new();
map.insert("k1", "v1");
map.insert("k2", "v2");
assert_eq!(map.len(), 2);
assert!(!map.is_empty());
assert!(map.contains_key("k1"));
assert!(map.contains_key("k2"));
assert!(!map.contains_key("k3"));
assert_eq!(map.get_str("k1"), Some("v1"));
assert_eq!(map.get_str("k2"), Some("v2"));
assert_eq!(map.get_str("k3"), None);
}
#[test]
fn test_header_map_uniques() {
let mut map = HeaderMap::new();
map.insert("k1", "v1");
map.insert("k2", "v2");
assert_eq!(map.len(), 2);
assert_eq!(map.get("k1").map(|v| v.text.as_ref()), Some("v1"));
assert_eq!(map.get("k2").map(|v| v.text.as_ref()), Some("v2"));
map.insert("k2", "hello world");
assert_eq!(map.len(), 2);
assert_eq!(map.get("k1").map(|v| v.text.as_ref()), Some("v1"));
assert_eq!(map.get("k2").map(|v| v.text.as_ref()), Some("hello world"));
}
#[test]
fn test_header_map_duplicates() {
let mut map = HeaderMap::new();
map.append("k1", "v1");
map.append("k2", "v2");
map.append("k1", "v3");
map.append("k2", "v4");
assert_eq!(map.len(), 4);
assert_eq!(map.get("k1").map(|v| v.text.as_ref()), Some("v1"));
assert_eq!(map.get("k2").map(|v| v.text.as_ref()), Some("v2"));
assert_eq!(
map.get_all("k1")
.map(|v| v.text.to_string())
.collect::<Vec<String>>(),
vec!["v1", "v3"]
);
assert_eq!(
map.get_all("k2")
.map(|v| v.text.to_string())
.collect::<Vec<String>>(),
vec!["v2", "v4"]
);
map.insert("k1", "hello world");
assert_eq!(map.len(), 3);
assert_eq!(
map.get_all("k1")
.map(|v| v.text.to_string())
.collect::<Vec<String>>(),
vec!["hello world"]
);
assert_eq!(
map.get_all("k2")
.map(|v| v.text.to_string())
.collect::<Vec<String>>(),
vec!["v2", "v4"]
);
}
#[test]
fn test_header_iter() {
let mut map = HeaderMap::new();
map.insert("k1", "v1");
map.insert("k2", "v2");
assert_eq!(map.len(), 2);
let pairs = map.iter().cloned().collect::<Vec<FieldPair>>();
assert_eq!(pairs[0].name.text, "k1");
assert_eq!(pairs[0].value.text, "v1");
assert_eq!(pairs[1].name.text, "k2");
assert_eq!(pairs[1].value.text, "v2");
}
#[test]
fn test_header_map_case_sensitivity() {
let mut map = HeaderMap::new();
map.insert("Hello-World", "v1");
map.insert("hello-world", "v2");
assert_eq!(map.len(), 1);
assert_eq!(map.get("HELLO-WORLD").map(|v| v.text.as_ref()), Some("v2"));
map.append("HELLO-world", "v3");
assert_eq!(map.len(), 2);
assert_eq!(
map.get_all("hello-WORLD")
.map(|v| v.text.to_string())
.collect::<Vec<String>>(),
vec!["v2", "v3"]
);
}
#[test]
fn test_display() {
let mut map = HeaderMap::new();
map.insert("k1", "v1");
map.insert("k2", "v2");
let result = map.to_string();
assert_eq!(result, "k1: v1\r\nk2: v2\r\n");
}
#[test]
fn test_reorder_front() {
let mut map = HeaderMap::new();
map.insert("k1", "v1");
map.insert("Host", "example.com");
map.append("Host", "example.net");
map.reorder_front("host");
let list = map
.iter()
.map(|pair| (pair.name.text.as_str(), pair.value.text.as_str()))
.collect::<Vec<(&str, &str)>>();
assert_eq!(list[0], ("Host", "example.com"));
assert_eq!(list[1], ("Host", "example.net"));
assert_eq!(list[2], ("k1", "v1"));
}
}