From 9eee25cfcf660b065f3614929afbccceba25b63f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?David=20Ml=C3=A1dek?= Date: Tue, 3 Sep 2024 16:11:52 +0200 Subject: [PATCH] properly escape quotes and backslases in target and other fields --- src/fmt/layer.rs | 44 ++++++++++++++++++++++++++++ src/layer/mod.rs | 74 ++++++++++++++++++++---------------------------- 2 files changed, 75 insertions(+), 43 deletions(-) diff --git a/src/fmt/layer.rs b/src/fmt/layer.rs index 40792d7..c20918d 100644 --- a/src/fmt/layer.rs +++ b/src/fmt/layer.rs @@ -665,4 +665,48 @@ mod tests { tracing::info!("some json test"); }); } + + #[test] + fn target_quote() { + let expected = json!( + { + "timestamp": "fake time", + "target": "\"", + "fields": { + "message": "some json test", + }, + } + ); + + let layer = Layer::default() + .with_span_list(false) + .with_current_span(false) + .with_level(false); + + test_json(&expected, layer, || { + tracing::info!(target: "\"", "some json test"); + }); + } + + #[test] + fn target_backslash() { + let expected = json!( + { + "timestamp": "fake time", + "target": "\\hello\\\\world\\", + "fields": { + "message": "some json test", + }, + } + ); + + let layer = Layer::default() + .with_span_list(false) + .with_current_span(false) + .with_level(false); + + test_json(&expected, layer, || { + tracing::info!(target: "\\hello\\\\world\\", "some json test"); + }); + } } diff --git a/src/layer/mod.rs b/src/layer/mod.rs index 7840544..b81893b 100644 --- a/src/layer/mod.rs +++ b/src/layer/mod.rs @@ -736,15 +736,7 @@ where self.schema.insert( SchemaKey::from(key.into()), JsonValue::DynamicRawFromEvent(Box::new(|event, writer| { - writer.write_str("\"")?; - let mut rest = event.metadata().target(); - while let Some((before, after)) = rest.split_once('"') { - writer.write_str(before)?; - writer.write_str(r#"\""#)?; - rest = after; - } - writer.write_str(rest)?; - writer.write_str("\"") + write_escaped(writer, event.metadata().target()) })), ); @@ -759,17 +751,10 @@ where self.schema.insert( SchemaKey::from(key.into()), JsonValue::DynamicRawFromEvent(Box::new(|event, writer| { - event.metadata().file().map_or(Ok(()), |file| { - writer.write_str("\"")?; - let mut rest = file; - while let Some((before, after)) = rest.split_once('"') { - writer.write_str(before)?; - writer.write_str(r#"\""#)?; - rest = after; - } - writer.write_str(rest)?; - writer.write_str("\"") - }) + event + .metadata() + .file() + .map_or(Ok(()), |file| write_escaped(writer, file)) })), ); self @@ -797,15 +782,7 @@ where self.schema.insert( SchemaKey::from(key.into()), JsonValue::DynamicRawFromEvent(Box::new(|event, writer| { - writer.write_str("\"")?; - let mut rest = event.metadata().level().as_str(); - while let Some((before, after)) = rest.split_once('"') { - writer.write_str(before)?; - writer.write_str(r#"\""#)?; - rest = after; - } - writer.write_str(rest)?; - writer.write_str("\"") + write_escaped(writer, event.metadata().level().as_str()) })), ); self @@ -819,17 +796,9 @@ where self.schema.insert( SchemaKey::from(key.into()), JsonValue::DynamicRawFromEvent(Box::new(|_event, writer| { - std::thread::current().name().map_or(Ok(()), |name| { - writer.write_str("\"")?; - let mut rest = name; - while let Some((before, after)) = rest.split_once('"') { - writer.write_str(before)?; - writer.write_str(r#"\""#)?; - rest = after; - } - writer.write_str(rest)?; - writer.write_str("\"") - }) + std::thread::current() + .name() + .map_or(Ok(()), |name| write_escaped(writer, name)) })), ); self @@ -843,9 +812,10 @@ where self.schema.insert( SchemaKey::from(key.into()), JsonValue::DynamicRawFromEvent(Box::new(|_event, writer| { - writer.write_str("\"")?; - write!(writer, "{:?}", std::thread::current().id())?; - writer.write_str("\"") + use std::fmt::Write; + let mut value = String::with_capacity(12); + write!(&mut value, "{:?}", std::thread::current().id())?; + write_escaped(writer, &value) })), ); @@ -892,6 +862,24 @@ where } } +fn write_escaped(writer: &mut dyn fmt::Write, value: &str) -> Result<(), fmt::Error> { + let mut rest = value; + writer.write_str("\"")?; + let mut shift = 0; + while let Some(position) = rest + .get(shift..) + .and_then(|haystack| haystack.find(['\"', '\\'])) + { + let (before, after) = rest.split_at(position + shift); + writer.write_str(before)?; + writer.write_char('\\')?; + rest = after; + shift = 1; + } + writer.write_str(rest)?; + writer.write_str("\"") +} + #[cfg(test)] mod tests { use serde_json::json;