use std::io::Write;
use serde_json::Value;
use crate::{
Redactor,
json::internal::{
JsonRedactionState,
JsonUnkeyedValuePolicy,
},
};
use crate::http::UnkeyedJsonValuePolicy;
use super::{
BoundedBodyWriter,
markers::{
TRUNCATED,
UNKEYED_JSON,
},
};
#[must_use]
pub(in crate::http) fn redact(
redactor: &Redactor,
value: &mut Value,
unkeyed: UnkeyedJsonValuePolicy,
max_mask_bytes: usize,
) -> bool {
let mut remaining_mask_bytes = max_mask_bytes;
redact_with_remaining(redactor, value, unkeyed, &mut remaining_mask_bytes)
}
#[must_use]
pub(in crate::http) fn redact_with_remaining(
redactor: &Redactor,
value: &mut Value,
unkeyed: UnkeyedJsonValuePolicy,
remaining_mask_bytes: &mut usize,
) -> bool {
let unkeyed = match unkeyed {
UnkeyedJsonValuePolicy::PassThrough => {
JsonUnkeyedValuePolicy::PassThrough
}
UnkeyedJsonValuePolicy::Redact => JsonUnkeyedValuePolicy::Redact {
marker: UNKEYED_JSON,
truncated_marker: TRUNCATED,
},
};
JsonRedactionState::new(redactor.policy(), unkeyed, remaining_mask_bytes)
.redact(value)
.has_passed_unkeyed()
}
#[must_use]
pub(in crate::http) fn serialize_bounded(
value: &Value,
max_output_bytes: usize,
) -> Option<(String, bool)> {
let mut writer = BoundedBodyWriter::new(max_output_bytes);
if serde_json::to_writer(&mut writer, value).is_err() {
return writer.into_string().map(|text| (text, true));
}
writer.flush().ok()?;
writer.into_string().map(|text| (text, false))
}
#[must_use]
pub(in crate::http) fn redact_ndjson(
redactor: &Redactor,
bytes: &[u8],
unkeyed: UnkeyedJsonValuePolicy,
max_mask_bytes: usize,
) -> Option<(String, bool, bool)> {
let mut remaining_mask_bytes = max_mask_bytes;
redact_ndjson_with_remaining(
redactor,
bytes,
unkeyed,
&mut remaining_mask_bytes,
max_mask_bytes,
)
}
#[must_use]
pub(in crate::http) fn redact_ndjson_with_remaining(
redactor: &Redactor,
bytes: &[u8],
unkeyed: UnkeyedJsonValuePolicy,
remaining_mask_bytes: &mut usize,
max_output_bytes: usize,
) -> Option<(String, bool, bool)> {
let text = std::str::from_utf8(bytes).ok()?;
let trailing_newline = text.ends_with('\n');
let mut output = BoundedBodyWriter::new(max_output_bytes);
let mut needs_separator = false;
let mut passed = false;
for line in text.lines() {
if needs_separator && output.write_all(b"\n").is_err() {
return output.into_string().map(|text| (text, passed, true));
}
needs_separator = true;
if line.trim().is_empty() {
continue;
}
let mut value = serde_json::from_str(line).ok()?;
passed |= redact_with_remaining(
redactor,
&mut value,
unkeyed,
remaining_mask_bytes,
);
if serde_json::to_writer(&mut output, &value).is_err() {
return output.into_string().map(|text| (text, passed, true));
}
}
if trailing_newline && output.write_all(b"\n").is_err() {
return output.into_string().map(|text| (text, passed, true));
}
output.into_string().map(|text| (text, passed, false))
}