diff --git a/src/datadog/grok/grok_filter.rs b/src/datadog/grok/grok_filter.rs index 11f28bc24..fd482e12e 100644 --- a/src/datadog/grok/grok_filter.rs +++ b/src/datadog/grok/grok_filter.rs @@ -203,7 +203,9 @@ pub fn apply_filter(value: &Value, filter: &GrokFilter) -> Result parse_value_error_prone(value, filter, |b| { parse_ruby_hash(String::from_utf8_lossy(b).as_ref()) }), - GrokFilter::Querystring => parse_value_error_prone(value, filter, parse_query_string), + GrokFilter::Querystring => { + parse_value_error_prone(value, filter, |s| parse_query_string(s, true)) + } GrokFilter::Boolean => parse_value(value, filter, |b| { "true".eq_ignore_ascii_case(String::from_utf8_lossy(b).as_ref()) }), diff --git a/src/parsing/query_string.rs b/src/parsing/query_string.rs index 4b31a7d9a..8f77c66f7 100644 --- a/src/parsing/query_string.rs +++ b/src/parsing/query_string.rs @@ -2,7 +2,7 @@ use crate::compiler::prelude::*; use std::collections::BTreeMap; use url::form_urlencoded; -pub(crate) fn parse_query_string(bytes: &Bytes) -> Resolved { +pub(crate) fn parse_query_string(bytes: &Bytes, ignore_keys_without_values: bool) -> Resolved { let mut query_string = bytes.as_ref(); if !query_string.is_empty() && query_string[0] == b'?' { query_string = &query_string[1..]; @@ -11,7 +11,7 @@ pub(crate) fn parse_query_string(bytes: &Bytes) -> Resolved { let parsed = form_urlencoded::parse(query_string); for (k, value) in parsed { let value = value.as_ref(); - if value.is_empty() { + if ignore_keys_without_values && value.is_empty() { continue; } result @@ -38,19 +38,21 @@ mod tests { #[test] fn test_parses_complete() { - let result = parse_query_string(&"foo=%2B1&bar=2&xyz=&abc".into()).unwrap(); + let result = parse_query_string(&"foo=%2B1&bar=2&xyz=&abc".into(), false).unwrap(); assert_eq!( result, Value::from(btreemap! { "foo" => "+1", "bar" => "2", + "xyz" => "", + "abc" => "", }) ); } #[test] fn test_parses_multiple_values() { - let result = parse_query_string(&"foo=bar&foo=xyz".into()).unwrap(); + let result = parse_query_string(&"foo=bar&foo=xyz".into(), false).unwrap(); assert_eq!( result, Value::from(btreemap! { @@ -61,7 +63,7 @@ mod tests { #[test] fn test_parses_ruby_on_rails_multiple_values() { - let result = parse_query_string(&"?foo%5b%5d=bar&foo%5b%5d=xyz".into()).unwrap(); + let result = parse_query_string(&"?foo%5b%5d=bar&foo%5b%5d=xyz".into(), false).unwrap(); assert_eq!( result, Value::from(btreemap! { @@ -72,31 +74,41 @@ mod tests { #[test] fn test_parses_empty_key() { - let result = parse_query_string(&"=&=".into()).unwrap(); - assert_eq!(result, Value::from(btreemap! {})); + let result = parse_query_string(&"=&=".into(), false).unwrap(); + assert_eq!( + result, + Value::from(btreemap! { + "" => vec!["", ""], + }) + ); } #[test] - fn test_parses_empty_value() { - let result = parse_query_string(&"-".into()).unwrap(); - assert_eq!(result, Value::from(btreemap! {})); + fn test_parses_single_key() { + let result = parse_query_string(&"foo".into(), false).unwrap(); + assert_eq!( + result, + Value::from(btreemap! { + "foo" => "", + }) + ); } #[test] - fn test_parses_single_key() { - let result = parse_query_string(&"foo".into()).unwrap(); + fn ignores_key_without_values() { + let result = parse_query_string(&"foo".into(), true).unwrap(); assert_eq!(result, Value::from(btreemap! {})); } #[test] fn test_parses_empty_string() { - let result = parse_query_string(&"".into()).unwrap(); + let result = parse_query_string(&"".into(), false).unwrap(); assert_eq!(result, Value::from(btreemap! {})); } #[test] fn test_parses_if_starts_with_question_mark() { - let result = parse_query_string(&"?foo=bar".into()).unwrap(); + let result = parse_query_string(&"?foo=bar".into(), false).unwrap(); assert_eq!( result, Value::from(btreemap! { diff --git a/src/stdlib/parse_query_string.rs b/src/stdlib/parse_query_string.rs index 0455dabae..61b444a15 100644 --- a/src/stdlib/parse_query_string.rs +++ b/src/stdlib/parse_query_string.rs @@ -49,7 +49,7 @@ struct ParseQueryStringFn { impl FunctionExpression for ParseQueryStringFn { fn resolve(&self, ctx: &mut Context) -> Resolved { let bytes = self.value.resolve(ctx)?.try_bytes()?; - parse_query_string(&bytes) + parse_query_string(&bytes, false) } fn type_def(&self, _: &state::TypeState) -> TypeDef {