vrl/parsing/
query_string.rs

1use 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}