server: much improved xmls pretty printer

This commit is contained in:
2025-08-12 17:00:58 -07:00
parent 5c9955a89e
commit 3a41ab1767
4 changed files with 72 additions and 469 deletions

View File

@@ -2,7 +2,7 @@ use std::{
collections::{HashMap, HashSet},
fs::File,
io::{Cursor, Read},
str::FromStr,
};
use askama::Template;
@@ -14,7 +14,7 @@ use memmap::MmapOptions;
use quick_xml::de::from_str as xml_from_str;
use sqlx::{types::Json, PgPool};
use tracing::{error, info, info_span, instrument, warn};
use xmlem::{display, Document};
use zip::ZipArchive;
use crate::{
@@ -407,15 +407,12 @@ pub async fn thread(
} else {
// DMARC reports are XML
// Pretty print XML
let doc_result = Document::from_str(&raw_content);
if let Ok(doc) = doc_result {
doc.to_string_pretty_with_config(&display::Config::default_pretty())
} else {
error!(
"Failed to parse XML for pretty printing: {:?}",
doc_result.unwrap_err()
);
raw_content
match pretty_print_xml_with_trimming(&raw_content) {
Ok(pretty_xml) => pretty_xml,
Err(e) => {
error!("Failed to pretty print XML: {:?}", e);
raw_content
}
}
};
current_html.push_str(&format!(
@@ -897,15 +894,12 @@ fn extract_mixed(m: &ParsedMail, part_addr: &mut Vec<String>) -> Result<Body, Se
} else {
// DMARC reports are XML
// Pretty print XML
let doc_result = Document::from_str(&xml);
if let Ok(doc) = doc_result {
doc.to_string_pretty_with_config(&display::Config::default_pretty())
} else {
error!(
"Failed to parse XML for pretty printing: {:?}",
doc_result.unwrap_err()
);
xml
match pretty_print_xml_with_trimming(&xml) {
Ok(pretty_xml) => pretty_xml,
Err(e) => {
error!("Failed to pretty print XML: {:?}", e);
xml
}
}
};
parts.push(Body::html(format!("\n<pre>{}</pre>", html_escape::encode_text(&pretty_printed_content))));
@@ -1864,6 +1858,37 @@ pub fn parse_dmarc_report(xml: &str) -> Result<String, ServerError> {
Ok(html)
}
fn pretty_print_xml_with_trimming(xml_input: &str) -> Result<String, ServerError> {
use quick_xml::events::{Event, BytesText};
use quick_xml::reader::Reader;
use quick_xml::writer::Writer;
use std::io::Cursor;
let mut reader = Reader::from_str(xml_input);
reader.config_mut().trim_text(true);
let mut writer = Writer::new_with_indent(Cursor::new(Vec::new()), b' ', 4);
let mut buf = Vec::new();
loop {
match reader.read_event_into(&mut buf) {
Ok(Event::Eof) => break,
Ok(Event::Text(e)) => {
let trimmed_text = e.decode()?.trim().to_string();
writer.write_event(Event::Text(BytesText::new(&trimmed_text)))?;
},
Ok(event) => {
writer.write_event(event)?;
},
Err(e) => return Err(ServerError::StringError(format!("XML parsing error: {}", e))),
}
buf.clear();
}
let result = writer.into_inner().into_inner();
Ok(String::from_utf8(result)?)
}
#[cfg(test)]
mod tests {
use super::*;