use crate::{
error::Result,
helpers::{ self, BufReadExt, MatchConfig::Trim }
};
use std::{
mem, slice, collections::BTreeMap, iter::FromIterator, ops::Deref,
io::{ BufRead, Write }
};
#[derive(Debug, Clone)]
pub enum RequestTarget {
Wildcard,
Absolute {
path: RequestTargetPath,
query: QueryString
}
}
impl RequestTarget {
pub const fn new_wildcard() -> Self {
Self::Wildcard
}
pub const fn new_absolute(path: RequestTargetPath, query: QueryString) -> Self {
Self::Absolute { path, query }
}
pub fn read<T>(source: &mut T) -> Result<Self> where T: BufRead {
let this = match source.peek_one()? {
Some(b'/') => {
let path = source.read_word("?", [Trim])?;
let query = source.read_all([])?;
Self::Absolute {
path: RequestTargetPath::read(&mut helpers::memreader(path))?,
query: QueryString::read(&mut helpers::memreader(query))?
}
},
Some(b'*') => Self::Wildcard,
first => return Err(einval!("Invalid request target: {:?}", first))
};
Ok(this)
}
pub fn write_all<T>(&self, output: &mut T) -> Result where T: Write {
match self {
Self::Absolute { path, query } => {
path.write_all(output)?;
query.write_all(output)?;
},
Self::Wildcard => write!(output, "*")?,
}
Ok(())
}
}
#[derive(Debug, Clone, Default)]
pub struct RequestTargetPath {
components: Vec<Vec<u8>>
}
impl RequestTargetPath {
pub const fn new() -> Self {
Self { components: Vec::new() }
}
pub fn push<T>(&mut self, component: T) where T: Into<Vec<u8>> {
self.components.push(component.into());
}
pub fn read<T>(source: &mut T) -> Result<Self> where T: BufRead {
let mut this = Self { components: Vec::new() };
let mut component = Vec::new();
while source.peek_one()?.is_some() {
let mut next = 0;
source.read_exact(slice::from_mut(&mut next))?;
match next {
b'/' if component.is_empty() => (),
b'/' => this.components.push(mem::take(&mut component)),
other => component.push(other)
}
}
Ok(this)
}
pub fn write_all<T>(&self, output: &mut T) -> Result where T: Write {
if self.components.is_empty() {
output.write_all(b"/")?;
return Ok(());
}
for component in self.components.iter() {
output.write_all(b"/")?;
output.write_all(component)?;
}
Ok(())
}
}
impl<T> FromIterator<T> for RequestTargetPath where T: Into<Vec<u8>> {
fn from_iter<I: IntoIterator<Item = T>>(components: I) -> Self {
let components = components.into_iter()
.map(|c| c.into())
.collect();
Self { components }
}
}
impl IntoIterator for RequestTargetPath {
type Item = <Vec<Vec<u8>> as IntoIterator>::Item;
type IntoIter = <Vec<Vec<u8>> as IntoIterator>::IntoIter;
fn into_iter(self) -> Self::IntoIter {
self.components.into_iter()
}
}
#[derive(Debug, Clone, Default)]
pub struct QueryString {
fields: BTreeMap<Vec<u8>, Vec<u8>>
}
impl QueryString {
pub fn new() -> Self {
Self { fields: BTreeMap::new() }
}
pub fn get<T>(&self, name: T) -> Option<&[u8]> where T: AsRef<[u8]> {
self.fields.get(name.as_ref()).map(|s| s.as_ref())
}
pub fn set<A, B>(&mut self, name: A, value: B) where A: Into<Vec<u8>>, B: Into<Vec<u8>> {
self.fields.insert(name.into(), value.into());
}
pub fn read<T>(source: &mut T) -> Result<Self> where T: BufRead {
let mut fields = BTreeMap::new();
while source.peek_one()?.is_some() {
let pair = source.read_word("&", [Trim])?;
let mut pair = helpers::memreader(pair);
let key = pair.read_word("=", [Trim])?;
if !key.is_empty() {
let value = pair.read_all([])?;
fields.insert(key, value);
}
}
Ok(Self { fields })
}
pub fn write_all<T>(&self, output: &mut T) -> Result where T: Write {
for (nth_pair, (key, value)) in self.fields.iter().enumerate() {
match nth_pair {
0 => output.write_all(b"?")?,
_ => output.write_all(b"&")?
}
output.write_all(key)?;
if !value.is_empty() {
output.write_all(b"=")?;
output.write_all(value)?;
}
}
Ok(())
}
}
impl Deref for QueryString {
type Target = BTreeMap<Vec<u8>, Vec<u8>>;
fn deref(&self) -> &Self::Target {
&self.fields
}
}
impl<K, V> FromIterator<(K, V)> for QueryString where K: Into<Vec<u8>>, V: Into<Vec<u8>> {
fn from_iter<T: IntoIterator<Item = (K, V)>>(pairs: T) -> Self {
let fields = pairs.into_iter()
.map(|(k, v)| (k.into(), v.into()))
.collect();
Self { fields }
}
}
impl IntoIterator for QueryString {
type Item = <BTreeMap<Vec<u8>, Vec<u8>> as IntoIterator>::Item;
type IntoIter = <BTreeMap<Vec<u8>, Vec<u8>> as IntoIterator>::IntoIter;
fn into_iter(self) -> Self::IntoIter {
self.fields.into_iter()
}
}