1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
use crate::{
HttpError,
helpers::{ iter_ext::IterExt, slice_ext::SliceExt },
data::{
Data,
encodings::{ Encoding, Uri, UriQuery}
}
};
use std::{
collections::HashMap, io::Write,
convert::{ TryFrom, TryInto }
};
use crate::helpers::slice_ext::ByteSliceExt;
#[derive(Clone, Debug, Eq, PartialEq)]
pub struct QueryString<'a>(HashMap<Data<'a, UriQuery>, Data<'a, UriQuery>>);
impl<'a> QueryString<'a> {
pub fn new() -> Self {
Self(HashMap::new())
}
pub fn field<'b: 'a>(&self, key: &Data<'b, UriQuery>) -> Option<&Data<'a, UriQuery>> {
self.0.get(&key)
}
pub fn field_mut<'b: 'a>(&mut self, key: &Data<'b, UriQuery>)
-> Option<&mut Data<'a, UriQuery>>
{
self.0.get_mut(&key)
}
pub fn insert(&mut self, key: Data<'a, UriQuery>, value: Data<'a, UriQuery>) {
self.0.insert(key, value);
}
pub fn fields(&self) -> &HashMap<Data<'a, UriQuery>, Data<'a, UriQuery>> {
&self.0
}
pub fn fields_mut(&mut self) -> &mut HashMap<Data<'a, UriQuery>, Data<'a, UriQuery>> {
&mut self.0
}
pub fn to_string(&self) -> String {
let mut query = vec![b'?'];
self.0.iter().for_each(|(k, v)| match v.len() {
0 => write!(&mut query, "{}&", k).unwrap(),
_ => write!(&mut query, "{}={}&", k, v).unwrap()
});
let trimmed_len = query.trim_end_matches(|b| *b == b'&').len();
query.truncate(trimmed_len);
String::from_utf8(query).unwrap()
}
}
impl<'a> TryFrom<Data<'a, Uri>> for QueryString<'a> {
type Error = HttpError;
fn try_from(uri: Data<'a, Uri>) -> Result<Self, Self::Error> {
let uri = uri.as_slice();
let query_part = match uri.splitn_pat(2, b"?").collect_min(2) {
Some(query_part) => query_part[1],
None => return Ok(Self::new())
};
let query_part = query_part.splitn_pat(2, b"#").next().unwrap();
if !UriQuery::is_valid(query_part) {
Err(HttpError::InvalidEncoding)?
}
let query_part = query_part.trim_end_matches(|b| *b == b'&');
if query_part.is_empty() {
return Ok(Self::new())
}
let mut query = HashMap::new();
for kv in query_part.split_pat(b"&") {
let kv: Vec<&[u8]> = kv.splitn_pat(2, b"=").collect();
match kv.len() {
1 => query.insert(kv[0].try_into()?, b"".as_ref().try_into()?),
2 => query.insert(kv[0].try_into()?, kv[1].try_into()?),
_ => unreachable!()
};
}
Ok(Self(query))
}
}