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
use std::collections::HashMap;
use crate::helpers::http::{form_url_decode, FormUrlDecoded};
pub(crate) type QueryStringMapping = HashMap<String, Vec<FormUrlDecoded>>;
pub(crate) fn split<'r>(query: Option<&'r str>) -> QueryStringMapping {
let mut query_string_mapping = QueryStringMapping::new();
if let Some(query) = query {
let pairs = query.split(is_separator).filter(|pair| pair.contains('='));
for p in pairs {
let mut sp = p.splitn(2, '=');
let (k, v) = (sp.next().unwrap(), sp.next().unwrap());
if let Ok(k) = form_url_decode(k) {
let vec = query_string_mapping.entry(k).or_insert_with(Vec::new);
if let Some(dv) = FormUrlDecoded::new(v) {
vec.push(dv);
}
};
}
}
query_string_mapping
}
fn is_separator(c: char) -> bool {
c == '&' || c == ';'
}
#[cfg(test)]
mod tests {
use super::*;
fn to_pairs<'a>(qsm: &'a QueryStringMapping) -> Vec<(&'a str, Vec<&'a str>)> {
let mut pairs: Vec<(&str, Vec<&str>)> = qsm
.iter()
.map(|(k, v)| {
let mut values: Vec<&str> = v.iter().map(AsRef::as_ref).collect();
values.sort_unstable();
(k.as_str(), values)
})
.collect();
pairs.sort_by(|&(ref a, ref _a_val), &(ref b, ref _b_val)| a.cmp(b));
pairs
}
#[test]
fn query_string_mapping_tests() {
let qsm = split(Some("a=b&c=d&e=f"));
assert_eq!(
to_pairs(&qsm),
vec![("a", vec!["b"]), ("c", vec!["d"]), ("e", vec!["f"])],
);
let qsm = split(Some("a=b&a=d&e=f"));
assert_eq!(
to_pairs(&qsm),
vec![("a", vec!["b", "d"]), ("e", vec!["f"])],
);
let qsm = split(Some("a&b"));
assert_eq!(to_pairs(&qsm), vec![],);
let qsm = split(Some("a=b;c=d&e=f"));
assert_eq!(
to_pairs(&qsm),
vec![("a", vec!["b"]), ("c", vec!["d"]), ("e", vec!["f"])],
);
let qsm = split(Some("a=b=c&d=e"));
assert_eq!(to_pairs(&qsm), vec![("a", vec!["b=c"]), ("d", vec!["e"])],);
}
}