better_qs/
parser.rs

1use std::convert::Infallible;
2
3use crate::helpers::{create_array, push_item_to_array};
4use crate::merge::merge;
5#[cfg(feature = "regex1")]
6use lazy_static::lazy_static;
7use percent_encoding::percent_decode;
8#[cfg(feature = "regex1")]
9use regex::Regex;
10use serde_json::{Map, Number, Value};
11use thiserror::Error;
12
13#[cfg(feature = "regex1")]
14lazy_static! {
15    static ref PARENT_REGEX: Regex = Regex::new(r"^([^\]\[]+)").unwrap();
16    static ref CHILD_REGEX: Regex = Regex::new(r"(\[[^\]\[]*\])").unwrap();
17}
18
19type Object = Map<String, Value>;
20
21#[derive(Debug, Error)]
22pub enum ParseError {
23    #[error("Failed to decode: {0}")]
24    DecodingError(String),
25    #[error("Other")]
26    Other,
27}
28
29pub type ParseResult<T> = Result<T, ParseError>;
30
31pub fn decode_component(source: &str) -> Result<String, String> {
32    let result = percent_decode(source.as_bytes())
33        .decode_utf8_lossy()
34        .to_string();
35    Ok(result)
36}
37
38fn parse_pair(part: &str) -> (&str, Option<&str>) {
39    let separator = part
40        .find("]=")
41        .map(|pos| pos + 1)
42        .or_else(|| part.find('='));
43    match separator {
44        None => (part, None),
45        Some(pos) => {
46            let key = &part[..pos];
47            let val = &part[(pos + 1)..];
48            (key, Some(val))
49        }
50    }
51}
52
53fn parse_pairs(body: &str) -> Vec<(&str, Option<&str>)> {
54    let mut pairs = vec![];
55    for part in body.split('&') {
56        pairs.push(parse_pair(part));
57    }
58    pairs
59}
60
61#[cfg(feature = "regex1")]
62fn parse_key(key: &str) -> ParseResult<Vec<String>> {
63    let mut keys: Vec<String> = vec![];
64
65    if let Some(captures) = PARENT_REGEX.captures(key) {
66        match decode_component(captures.get(1).unwrap().as_str()) {
67            Ok(decoded_key) => keys.push(decoded_key),
68            Err(err_msg) => return Err(ParseError::DecodingError(err_msg)),
69        }
70    };
71
72    for captures in CHILD_REGEX.captures_iter(key) {
73        match decode_component(captures.get(1).unwrap().as_str()) {
74            Ok(decoded_key) => keys.push(decoded_key),
75            Err(err_msg) => return Err(ParseError::DecodingError(err_msg)),
76        }
77    }
78
79    Ok(keys)
80}
81
82#[cfg(not(feature = "regex1"))]
83fn parse_key(key: &str) -> ParseResult<Vec<String>> {
84    let mut keys: Vec<String> = vec![];
85
86    match key.split(|c| c == '[' || c == ']').next() {
87        Some(parent) if !parent.is_empty() => match decode_component(parent) {
88            Ok(decoded_key) => keys.push(decoded_key),
89            Err(err_msg) => return Err(ParseError::DecodingError(err_msg)),
90        },
91        _ => (),
92    }
93
94    let mut prev_bracket = None;
95    for (idx, ch) in key.char_indices() {
96        match ch {
97            '[' => prev_bracket = Some(idx),
98            ']' => {
99                if let Some(prev_idx) = prev_bracket {
100                    prev_bracket = None;
101                    let child = &key[prev_idx..=idx];
102                    match decode_component(child) {
103                        Ok(decoded_key) => keys.push(decoded_key),
104                        Err(err_msg) => {
105                            return Err(ParseError {
106                                kind: ParseErrorKind::DecodingError,
107                                message: err_msg,
108                            })
109                        }
110                    }
111                }
112            }
113            _ => (),
114        }
115    }
116
117    Ok(keys)
118}
119
120fn cleanup_key(key: &str) -> &str {
121    if key.starts_with('[') && key.ends_with(']') {
122        &key[1..(key.len() - 1)]
123    } else {
124        key
125    }
126}
127
128fn create_idx_merger(idx: u64, obj: Value) -> Value {
129    let mut tree = Object::new();
130    tree.insert("__idx".to_string(), Value::Number(Number::from(idx)));
131    tree.insert("__object".to_string(), obj);
132    Value::Object(tree)
133}
134
135fn create_object_with_key(key: String, obj: Value) -> Value {
136    let mut tree = Object::new();
137    tree.insert(key, obj);
138    Value::Object(tree)
139}
140
141fn apply_object(keys: &[String], val: Value) -> Value {
142    if !keys.is_empty() {
143        let key = keys.get(0).unwrap();
144        if key == "[]" {
145            let mut new_array = create_array();
146            let item = apply_object(&keys[1..], val);
147            push_item_to_array(&mut new_array, item);
148            new_array
149        } else {
150            let key = cleanup_key(key);
151            let array_index = key.parse();
152
153            match array_index {
154                Ok(idx) => {
155                    let result = apply_object(&keys[1..], val);
156                    create_idx_merger(idx, result)
157                }
158                Err(_) => create_object_with_key(key.to_string(), apply_object(&keys[1..], val)),
159            }
160        }
161    } else {
162        val
163    }
164}
165
166pub fn parse(params: &str) -> ParseResult<Value> {
167    let tree = Object::new();
168    let mut obj = Value::Object(tree);
169    let decoded_params = match decode_component(&params.replace('+', " ")) {
170        Ok(val) => val,
171        Err(err) => return Err(ParseError::DecodingError(err)),
172    };
173    let pairs = parse_pairs(&decoded_params);
174    for &(key, value) in pairs.iter() {
175        let parse_key_res = parse_key(key)?;
176        let key_chain = &parse_key_res[0..];
177        let decoded_value = match value {
178            None => Value::default(),
179            Some(val) => match decode_component(val) {
180                Ok(v) => {
181                    let n = v.parse::<i64>();
182                    let f = v.parse::<f64>();
183                    let b = v.parse::<bool>();
184                    let null = Ok::<_, Infallible>(v == "null");
185                    match (n, f, b, null) {
186                        (Ok(n), _, _, _) => Value::Number(Number::from(n)),
187                        (_, Ok(f), _, _) => Value::Number(Number::from_f64(f).unwrap()),
188                        (_, _, Ok(b), _) => Value::Bool(b),
189                        (_, _, _, Ok(true)) => Value::Null,
190                        _ => Value::String(v),
191                    }
192                }
193                Err(err) => return Err(ParseError::DecodingError(err)),
194            },
195        };
196        let partial = apply_object(key_chain, decoded_value);
197        merge(&mut obj, &partial);
198    }
199
200    Ok(obj)
201}
202
203#[cfg(test)]
204mod tests {
205    use super::{parse, parse_pair};
206    use serde_json::{json, to_string, Value};
207
208    fn eq_str(value: Value, string: &str) {
209        assert_eq!(&to_string(&value).unwrap(), string)
210    }
211
212    #[test]
213    fn test_parse_pair() {
214        assert_eq!(parse_pair("foo=1"), ("foo", Some("1")));
215        assert_eq!(parse_pair("empty="), ("empty", Some("")));
216        assert_eq!(parse_pair("noval"), ("noval", None));
217    }
218
219    #[test]
220    fn it_parses_simple_string() {
221        eq_str(parse("0=foo").unwrap(), r#"{"0":"foo"}"#);
222        eq_str(parse("a[<=>]==23").unwrap(), r#"{"a":{"<=>":"=23"}}"#);
223        eq_str(
224            parse(" foo = bar = baz ").unwrap(),
225            r#"{" foo ":" bar = baz "}"#,
226        );
227    }
228
229    #[test]
230    fn it_parses_nested_string() {
231        eq_str(
232            parse("a[b][c][d][e][f][g][h]=i").unwrap(),
233            r#"{"a":{"b":{"c":{"d":{"e":{"f":{"g":{"h":"i"}}}}}}}}"#,
234        );
235    }
236
237    #[test]
238    fn it_parses_simple_array() {
239        eq_str(
240            parse("a=b&a=c&a=d&a=e").unwrap(),
241            r#"{"a":["b","c","d","e"]}"#,
242        );
243    }
244
245    #[test]
246    fn it_parses_explicit_array() {
247        eq_str(
248            parse("a[]=b&a[]=c&a[]=d").unwrap(),
249            r#"{"a":["b","c","d"]}"#,
250        );
251    }
252
253    #[test]
254    fn it_parses_nested_array() {
255        eq_str(
256            parse("a[b][]=c&a[b][]=d").unwrap(),
257            r#"{"a":{"b":["c","d"]}}"#,
258        );
259    }
260
261    #[test]
262    fn it_allows_to_specify_array_indexes() {
263        eq_str(
264            parse("a[0][]=c&a[1][]=d").unwrap(),
265            r#"{"a":[["c"],["d"]]}"#,
266        );
267    }
268
269    #[test]
270    fn it_transforms_arrays_to_object() {
271        eq_str(
272            parse("foo[0]=bar&foo[bad]=baz").unwrap(),
273            r#"{"foo":{"0":"bar","bad":"baz"}}"#,
274        );
275
276        eq_str(
277            parse("foo[0][a]=a&foo[0][b]=b&foo[1][a]=aa&foo[1][b]=bb").unwrap(),
278            r#"{"foo":[{"a":"a","b":"b"},{"a":"aa","b":"bb"}]}"#,
279        );
280    }
281
282    #[test]
283    fn it_transforms_standalone_keys() {
284        eq_str(parse("foo=bar&baz").unwrap(), r#"{"baz":null,"foo":"bar"}"#);
285    }
286
287    #[test]
288    fn it_doesnt_produce_empty_keys() {
289        assert_eq!(parse("_r=1&").unwrap(), json!({"_r": 1}));
290    }
291
292    #[test]
293    fn it_supports_encoded_strings() {
294        eq_str(parse("a[b%20c]=c%20d").unwrap(), r#"{"a":{"b c":"c d"}}"#);
295    }
296
297    #[test]
298    fn it_parses_explicit_encoded_array() {
299        eq_str(
300            parse("a%5B%5D=b&a%5B%5D=c&a%5B%5D=d").unwrap(),
301            r#"{"a":["b","c","d"]}"#,
302        );
303    }
304    #[test]
305    fn it_parses_plus_sign() {
306        eq_str(parse("a=b%20c+d%2B").unwrap(), r#"{"a":"b c d+"}"#);
307    }
308
309    #[test]
310    fn it_parses_numbers() {
311        assert_eq!(parse("a=1").unwrap(), json!({"a": 1}));
312        assert_eq!(parse("a=1.1").unwrap(), json!({"a": 1.1}));
313        assert_eq!(parse("a=1.1e1").unwrap(), json!({"a": 11.0}));
314        assert_eq!(parse("a=1.1e-1").unwrap(), json!({"a": 0.11}));
315    }
316
317    #[test]
318    fn it_parses_booleans() {
319        assert_eq!(parse("a=true").unwrap(), json!({"a": true}));
320        assert_eq!(parse("a=false").unwrap(), json!({"a": false}));
321    }
322
323    #[test]
324    fn it_parses_null() {
325        assert_eq!(parse("a=null").unwrap(), json!({ "a": null }));
326    }
327
328    #[test]
329    fn it_parses_empty_string() {
330        assert_eq!(parse("a=").unwrap(), json!({ "a": "" }));
331    }
332
333    #[test]
334    fn it_parses_array_integer() {
335        assert_eq!(parse("a[]=1&a[]=2").unwrap(), json!({ "a": [1, 2] }));
336    }
337
338    #[test]
339    fn it_parses_nested_array_integer() {
340        assert_eq!(
341            parse("a[b]=null&a[b]=2").unwrap(),
342            json!({ "a": {"b": [null, 2] }})
343        );
344
345        assert_eq!(
346            parse("a[b]=1&a[b]=2").unwrap(),
347            json!({ "a": {"b": [1, 2] }})
348        );
349    }
350}