vrl/parsing/
query_string.rs1use crate::compiler::prelude::*;
2use std::collections::BTreeMap;
3use url::form_urlencoded;
4
5pub fn parse_query_string(bytes: &Bytes, ignore_keys_without_values: bool) -> Resolved {
6 let mut query_string = bytes.as_ref();
7 if !query_string.is_empty() && query_string[0] == b'?' {
8 query_string = &query_string[1..];
9 }
10 let mut result = BTreeMap::new();
11 let parsed = form_urlencoded::parse(query_string);
12 for (k, value) in parsed {
13 let value = value.as_ref();
14 if ignore_keys_without_values && value.is_empty() {
15 continue;
16 }
17 result
18 .entry(k.into_owned().into())
19 .and_modify(|v| {
20 match v {
21 Value::Array(v) => {
22 v.push(value.into());
23 }
24 v => {
25 *v = Value::Array(vec![v.clone(), value.into()]);
26 }
27 };
28 })
29 .or_insert_with(|| value.into());
30 }
31 Ok(result.into())
32}
33
34#[cfg(test)]
35mod tests {
36 use super::*;
37 use crate::btreemap;
38
39 #[test]
40 fn test_parses_complete() {
41 let result = parse_query_string(&"foo=%2B1&bar=2&xyz=&abc".into(), false).unwrap();
42 assert_eq!(
43 result,
44 Value::from(btreemap! {
45 "foo" => "+1",
46 "bar" => "2",
47 "xyz" => "",
48 "abc" => "",
49 })
50 );
51 }
52
53 #[test]
54 fn test_parses_multiple_values() {
55 let result = parse_query_string(&"foo=bar&foo=xyz".into(), false).unwrap();
56 assert_eq!(
57 result,
58 Value::from(btreemap! {
59 "foo" => vec!["bar", "xyz"],
60 })
61 );
62 }
63
64 #[test]
65 fn test_parses_ruby_on_rails_multiple_values() {
66 let result = parse_query_string(&"?foo%5b%5d=bar&foo%5b%5d=xyz".into(), false).unwrap();
67 assert_eq!(
68 result,
69 Value::from(btreemap! {
70 "foo[]" => vec!["bar", "xyz"],
71 })
72 );
73 }
74
75 #[test]
76 fn test_parses_empty_key() {
77 let result = parse_query_string(&"=&=".into(), false).unwrap();
78 assert_eq!(
79 result,
80 Value::from(btreemap! {
81 "" => vec!["", ""],
82 })
83 );
84 }
85
86 #[test]
87 fn test_parses_single_key() {
88 let result = parse_query_string(&"foo".into(), false).unwrap();
89 assert_eq!(
90 result,
91 Value::from(btreemap! {
92 "foo" => "",
93 })
94 );
95 }
96
97 #[test]
98 fn ignores_key_without_values() {
99 let result = parse_query_string(&"foo".into(), true).unwrap();
100 assert_eq!(result, Value::from(btreemap! {}));
101 }
102
103 #[test]
104 fn test_parses_empty_string() {
105 let result = parse_query_string(&"".into(), false).unwrap();
106 assert_eq!(result, Value::from(btreemap! {}));
107 }
108
109 #[test]
110 fn test_parses_if_starts_with_question_mark() {
111 let result = parse_query_string(&"?foo=bar".into(), false).unwrap();
112 assert_eq!(
113 result,
114 Value::from(btreemap! {
115 "foo" => "bar",
116 })
117 );
118 }
119}