1use std::borrow::Cow;
4use std::io::{Read, Write};
5use std::num::NonZeroU32;
6use std::ops::Range;
7use std::sync::Arc;
8
9use aster_forge_utils::numbers::{u32_to_usize, u64_to_usize, usize_to_u32, usize_to_u64};
10use quick_xml::Reader;
11use quick_xml::XmlVersion;
12use quick_xml::escape::unescape;
13use quick_xml::events::{BytesStart, Event};
14
15use crate::syntax::{
16 XML_NAMESPACE_URI, map_quick_xml_error_at, split_qualified_name, utf8,
17 validate_namespace_binding, validate_qualified_name,
18};
19use crate::{Error, ParseOptions, XmlSafetyError, XmlSafetyPolicy};
20
21const OWNED_VALUE_OFFSET: u64 = u64::MAX;
22
23#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
25pub struct NodeId(NonZeroU32);
26
27impl NodeId {
28 fn from_index(index: usize) -> Result<Self, Error> {
29 let value = usize_to_u32(index, "XML node index")
30 .ok()
31 .and_then(|index| index.checked_add(1))
32 .and_then(NonZeroU32::new)
33 .ok_or(XmlSafetyError::TooManyElements)?;
34 Ok(Self(value))
35 }
36
37 fn index(self) -> usize {
38 stored_index(self.0.get() - 1, "XML node index")
39 }
40}
41
42#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
43struct ScopeId(NonZeroU32);
44
45impl ScopeId {
46 fn from_index(index: usize) -> Result<Self, Error> {
47 let value = usize_to_u32(index, "XML namespace scope index")
48 .ok()
49 .and_then(|index| index.checked_add(1))
50 .and_then(NonZeroU32::new)
51 .ok_or_else(|| Error::InvalidXml("too many namespace scopes".into()))?;
52 Ok(Self(value))
53 }
54
55 fn index(self) -> usize {
56 stored_index(self.0.get() - 1, "XML namespace scope index")
57 }
58}
59
60#[derive(Debug, Clone, Copy, PartialEq, Eq)]
62pub struct SourceSpan {
63 pub start: u64,
64 pub end: u64,
65}
66
67impl SourceSpan {
68 fn as_range(self, source_len: usize) -> Option<Range<usize>> {
69 let start = u64_to_usize(self.start, "XML source span start").ok()?;
70 let end = u64_to_usize(self.end, "XML source span end").ok()?;
71 (start <= end && end <= source_len).then_some(start..end)
72 }
73}
74
75#[derive(Debug, Clone, Copy)]
76struct ValueRef {
77 offset: u64,
78 length: u32,
79 owned_index: u32,
80}
81
82impl ValueRef {
83 fn source(offset: u64, length: u32) -> Self {
84 Self {
85 offset,
86 length,
87 owned_index: 0,
88 }
89 }
90
91 fn owned(index: u32, length: u32) -> Self {
92 Self {
93 offset: OWNED_VALUE_OFFSET,
94 length,
95 owned_index: index,
96 }
97 }
98}
99
100#[derive(Debug)]
101struct ArenaNode {
102 parent: Option<NodeId>,
103 first_child: Option<NodeId>,
104 last_child: Option<NodeId>,
105 next_sibling: Option<NodeId>,
106 kind: NodeKind,
107}
108
109#[derive(Debug)]
110enum NodeKind {
111 Element(ElementData),
112 Text(ValueRef),
113 CData(ValueRef),
114 Comment(ValueRef),
115 ProcessingInstruction {
116 target: ValueRef,
117 content: Option<ValueRef>,
118 },
119}
120
121#[derive(Debug)]
122struct ElementData {
123 qualified_name: ValueRef,
124 attributes: Range<u32>,
125 namespace_scope: Option<ScopeId>,
126 source: SourceSpan,
127}
128
129#[derive(Debug)]
130struct AttributeData {
131 qualified_name: ValueRef,
132 value: ValueRef,
133}
134
135#[derive(Debug)]
136struct NamespaceScope {
137 parent: Option<ScopeId>,
138 bindings: Range<u32>,
139}
140
141#[derive(Debug)]
142struct NamespaceBinding {
143 prefix: ValueRef,
144 uri: Option<ValueRef>,
145}
146
147#[derive(Clone, Copy)]
148struct ArenaView<'a> {
149 source: &'a [u8],
150 namespace_scopes: &'a [NamespaceScope],
151 namespace_bindings: &'a [NamespaceBinding],
152 owned_values: &'a [Box<str>],
153}
154
155impl<'a> ArenaView<'a> {
156 fn value(self, value: ValueRef) -> &'a str {
157 let resolved = self.checked_value(value);
158 debug_assert!(resolved.is_some(), "invalid internal XML value reference");
159 resolved.unwrap_or("")
160 }
161
162 fn checked_value(self, value: ValueRef) -> Option<&'a str> {
163 let length = u32_to_usize(value.length, "XML value length").ok()?;
164 if value.offset == OWNED_VALUE_OFFSET {
165 let index = u32_to_usize(value.owned_index, "owned XML value index").ok()?;
166 let value = self.owned_values.get(index)?.as_ref();
167 return (value.len() == length).then_some(value);
168 }
169
170 let start = u64_to_usize(value.offset, "XML value offset").ok()?;
171 let end = start.checked_add(length)?;
172 std::str::from_utf8(self.source.get(start..end)?).ok()
173 }
174
175 fn resolve_namespace(self, scope: Option<ScopeId>, prefix: &str) -> Option<&'a str> {
176 match self.checked_resolve_namespace(scope, prefix) {
177 Ok(namespace) => namespace,
178 Err(()) => {
179 debug_assert!(false, "invalid internal XML namespace reference");
180 None
181 }
182 }
183 }
184
185 fn checked_resolve_namespace(
186 self,
187 mut scope: Option<ScopeId>,
188 prefix: &str,
189 ) -> Result<Option<&'a str>, ()> {
190 if prefix == "xml" {
191 return Ok(Some(XML_NAMESPACE_URI));
192 }
193 while let Some(scope_id) = scope {
194 let scope_data = self.namespace_scopes.get(scope_id.index()).ok_or(())?;
195 for binding_index in scope_data.bindings.clone().rev() {
196 let binding_index =
197 u32_to_usize(binding_index, "XML namespace binding index").map_err(|_| ())?;
198 let binding = self.namespace_bindings.get(binding_index).ok_or(())?;
199 if self.checked_value(binding.prefix).ok_or(())? == prefix {
200 return binding
201 .uri
202 .map(|uri| self.checked_value(uri).ok_or(()))
203 .transpose();
204 }
205 }
206 scope = scope_data.parent;
207 }
208 Ok(None)
209 }
210}
211
212#[derive(Debug)]
216pub struct XmlDocument<S> {
217 source: S,
218 nodes: Box<[ArenaNode]>,
219 attributes: Box<[AttributeData]>,
220 namespace_scopes: Box<[NamespaceScope]>,
221 namespace_bindings: Box<[NamespaceBinding]>,
222 owned_values: Box<[Box<str>]>,
223 root: NodeId,
224}
225
226pub type BorrowedDocument<'a> = XmlDocument<&'a [u8]>;
228
229pub type OwnedDocument = XmlDocument<Arc<[u8]>>;
231
232impl<S: AsRef<[u8]>> XmlDocument<S> {
233 pub fn parse(source: S) -> Result<Self, Error> {
235 Self::parse_with_options(source, &ParseOptions::default())
236 }
237
238 pub fn parse_with_options(source: S, options: &ParseOptions) -> Result<Self, Error> {
240 options.safety.validate()?;
241 if source.as_ref().len() > options.safety.max_input_bytes {
242 return Err(XmlSafetyError::InputTooLarge.into());
243 }
244
245 let (nodes, attributes, namespace_scopes, namespace_bindings, owned_values, root) = {
246 let mut builder = DocumentBuilder::new(source.as_ref(), options);
247 builder.parse()?;
248 let root = builder.root.ok_or(XmlSafetyError::Malformed)?;
249 (
250 builder.nodes.into_boxed_slice(),
251 builder.attributes.into_boxed_slice(),
252 builder.namespace_scopes.into_boxed_slice(),
253 builder.namespace_bindings.into_boxed_slice(),
254 builder.owned_values.into_boxed_slice(),
255 root,
256 )
257 };
258 Ok(Self {
259 source,
260 nodes,
261 attributes,
262 namespace_scopes,
263 namespace_bindings,
264 owned_values,
265 root,
266 })
267 }
268
269 pub fn source(&self) -> &[u8] {
270 self.source.as_ref()
271 }
272
273 pub fn into_source(self) -> S {
274 self.source
275 }
276
277 pub fn root(&self) -> ElementRef<'_, S> {
278 ElementRef {
279 document: self,
280 id: self.root,
281 }
282 }
283
284 pub fn node(&self, id: NodeId) -> Option<NodeRef<'_, S>> {
285 let node = self.nodes.get(id.index())?;
286 Some(match &node.kind {
287 NodeKind::Element(_) => NodeRef::Element(ElementRef { document: self, id }),
288 NodeKind::Text(value) => NodeRef::Text(self.value(*value)),
289 NodeKind::CData(value) => NodeRef::CData(self.value(*value)),
290 NodeKind::Comment(value) => NodeRef::Comment(self.value(*value)),
291 NodeKind::ProcessingInstruction { target, content } => {
292 NodeRef::ProcessingInstruction(ProcessingInstructionRef {
293 target: self.value(*target),
294 content: content.map(|value| self.value(value)),
295 })
296 }
297 })
298 }
299
300 pub fn node_count(&self) -> usize {
301 self.nodes.len()
302 }
303
304 pub fn allocated_value_count(&self) -> usize {
305 self.owned_values.len()
306 }
307
308 pub fn write_original<W: Write>(&self, mut writer: W) -> Result<(), Error> {
309 writer.write_all(self.source())?;
310 Ok(())
311 }
312
313 fn value(&self, value: ValueRef) -> &str {
314 self.arena_view().value(value)
315 }
316
317 fn element_data(&self, id: NodeId) -> Option<&ElementData> {
318 match &self.nodes.get(id.index())?.kind {
319 NodeKind::Element(element) => Some(element),
320 _ => None,
321 }
322 }
323
324 fn resolve_namespace(&self, scope: Option<ScopeId>, prefix: &str) -> Option<&str> {
325 self.arena_view().resolve_namespace(scope, prefix)
326 }
327
328 fn arena_view(&self) -> ArenaView<'_> {
329 ArenaView {
330 source: self.source.as_ref(),
331 namespace_scopes: &self.namespace_scopes,
332 namespace_bindings: &self.namespace_bindings,
333 owned_values: &self.owned_values,
334 }
335 }
336}
337
338impl XmlDocument<Arc<[u8]>> {
339 pub fn from_reader<R: Read>(reader: R) -> Result<Self, Error> {
341 Self::from_reader_with_options(reader, &ParseOptions::default())
342 }
343
344 pub fn from_reader_with_options<R: Read>(
346 reader: R,
347 options: &ParseOptions,
348 ) -> Result<Self, Error> {
349 options.safety.validate()?;
350 let read_limit = options.safety.max_input_bytes.saturating_add(1);
351 let read_limit = usize_to_u64(read_limit, "XML reader byte limit").unwrap_or(u64::MAX);
352 let mut reader = reader.take(read_limit);
353 let mut source = Vec::new();
354 reader.read_to_end(&mut source)?;
355 if source.len() > options.safety.max_input_bytes {
356 return Err(XmlSafetyError::InputTooLarge.into());
357 }
358 Self::parse_with_options(Arc::from(source), options)
359 }
360}
361
362#[derive(Debug, Clone)]
364pub struct ValidatedXml(Arc<OwnedDocument>);
365
366impl ValidatedXml {
367 pub fn new(bytes: impl Into<Arc<[u8]>>) -> Result<Self, Error> {
368 Self::with_policy(bytes, XmlSafetyPolicy::untrusted())
369 }
370
371 pub fn with_policy(
372 bytes: impl Into<Arc<[u8]>>,
373 policy: XmlSafetyPolicy,
374 ) -> Result<Self, Error> {
375 let source = bytes.into();
376 let document =
377 XmlDocument::parse_with_options(source, &ParseOptions::new().safety_policy(policy))?;
378 Ok(Self(Arc::new(document)))
379 }
380
381 pub fn from_reader<R: Read>(reader: R) -> Result<Self, Error> {
382 let document = OwnedDocument::from_reader(reader)?;
383 Ok(Self(Arc::new(document)))
384 }
385
386 pub fn as_bytes(&self) -> &[u8] {
387 self.0.source()
388 }
389
390 pub fn document(&self) -> &OwnedDocument {
391 &self.0
392 }
393}
394
395pub struct ElementRef<'document, S> {
397 document: &'document XmlDocument<S>,
398 id: NodeId,
399}
400
401impl<S> Copy for ElementRef<'_, S> {}
402
403impl<S> Clone for ElementRef<'_, S> {
404 fn clone(&self) -> Self {
405 *self
406 }
407}
408
409impl<'document, S: AsRef<[u8]>> ElementRef<'document, S> {
410 pub fn id(self) -> NodeId {
411 self.id
412 }
413
414 pub fn parent(self) -> Option<ElementRef<'document, S>> {
415 self.document.nodes[self.id.index()]
416 .parent
417 .map(|id| ElementRef {
418 document: self.document,
419 id,
420 })
421 }
422
423 pub fn qualified_name(self) -> &'document str {
424 let Some(data) = self.document.element_data(self.id) else {
425 return "";
426 };
427 self.document.value(data.qualified_name)
428 }
429
430 pub fn prefix(self) -> Option<&'document str> {
431 split_qualified_name(self.qualified_name()).0
432 }
433
434 pub fn name(self) -> &'document str {
435 split_qualified_name(self.qualified_name()).1
436 }
437
438 pub fn namespace(self) -> Option<&'document str> {
439 let data = self.document.element_data(self.id)?;
440 self.document
441 .resolve_namespace(data.namespace_scope, self.prefix().unwrap_or(""))
442 }
443
444 pub fn raw_xml(self) -> &'document [u8] {
445 let Some(data) = self.document.element_data(self.id) else {
446 return &[];
447 };
448 let Some(range) = data.source.as_range(self.document.source().len()) else {
449 return &[];
450 };
451 &self.document.source()[range]
452 }
453
454 pub fn attributes(self) -> Attributes<'document, S> {
455 let range = self
456 .document
457 .element_data(self.id)
458 .map(|data| data.attributes.clone())
459 .unwrap_or(0..0);
460 Attributes {
461 element: self,
462 next: range.start,
463 end: range.end,
464 }
465 }
466
467 pub fn attribute(self, qualified_name: &str) -> Option<&'document str> {
468 self.attributes()
469 .find(|attribute| attribute.qualified_name() == qualified_name)
470 .map(AttributeRef::value)
471 }
472
473 pub fn attribute_ns(self, name: &str, namespace: Option<&str>) -> Option<&'document str> {
474 self.attributes()
475 .find(|attribute| attribute.name() == name && attribute.namespace() == namespace)
476 .map(AttributeRef::value)
477 }
478
479 pub fn children(self) -> Children<'document, S> {
480 Children {
481 document: self.document,
482 next: self.document.nodes[self.id.index()].first_child,
483 }
484 }
485
486 pub fn child_elements(self) -> ChildElements<'document, S> {
487 ChildElements {
488 children: self.children(),
489 }
490 }
491
492 pub fn get_child(self, name: &str) -> Option<ElementRef<'document, S>> {
493 self.child_elements().find(|element| element.name() == name)
494 }
495
496 pub fn get_child_ns(self, name: &str, namespace: &str) -> Option<ElementRef<'document, S>> {
497 self.child_elements()
498 .find(|element| element.name() == name && element.namespace() == Some(namespace))
499 }
500
501 pub fn descendants(self) -> DescendantElements<'document, S> {
502 DescendantElements { stack: vec![self] }
503 }
504
505 pub fn text(self) -> Option<Cow<'document, str>> {
506 let mut values = self.children().filter_map(|node| match node {
507 NodeRef::Text(text) | NodeRef::CData(text) => Some(text),
508 _ => None,
509 });
510 let first = values.next()?;
511 match values.next() {
512 None => Some(Cow::Borrowed(first)),
513 Some(second) => {
514 let mut output = String::with_capacity(first.len() + second.len());
515 output.push_str(first);
516 output.push_str(second);
517 values.for_each(|value| output.push_str(value));
518 Some(Cow::Owned(output))
519 }
520 }
521 }
522}
523
524pub enum NodeRef<'document, S> {
526 Element(ElementRef<'document, S>),
527 Text(&'document str),
528 CData(&'document str),
529 Comment(&'document str),
530 ProcessingInstruction(ProcessingInstructionRef<'document>),
531}
532
533impl<S> Copy for NodeRef<'_, S> {}
534
535impl<S> Clone for NodeRef<'_, S> {
536 fn clone(&self) -> Self {
537 *self
538 }
539}
540
541#[derive(Debug, Clone, Copy, PartialEq, Eq)]
542pub struct ProcessingInstructionRef<'a> {
543 pub target: &'a str,
544 pub content: Option<&'a str>,
545}
546
547pub struct Children<'document, S> {
548 document: &'document XmlDocument<S>,
549 next: Option<NodeId>,
550}
551
552impl<'document, S: AsRef<[u8]>> Iterator for Children<'document, S> {
553 type Item = NodeRef<'document, S>;
554
555 fn next(&mut self) -> Option<Self::Item> {
556 let id = self.next?;
557 self.next = self.document.nodes[id.index()].next_sibling;
558 self.document.node(id)
559 }
560}
561
562pub struct ChildElements<'document, S> {
563 children: Children<'document, S>,
564}
565
566impl<'document, S: AsRef<[u8]>> Iterator for ChildElements<'document, S> {
567 type Item = ElementRef<'document, S>;
568
569 fn next(&mut self) -> Option<Self::Item> {
570 self.children.find_map(|node| match node {
571 NodeRef::Element(element) => Some(element),
572 _ => None,
573 })
574 }
575}
576
577pub struct DescendantElements<'document, S> {
578 stack: Vec<ElementRef<'document, S>>,
579}
580
581impl<'document, S: AsRef<[u8]>> Iterator for DescendantElements<'document, S> {
582 type Item = ElementRef<'document, S>;
583
584 fn next(&mut self) -> Option<Self::Item> {
585 let element = self.stack.pop()?;
586 let child_start = self.stack.len();
587 self.stack.extend(element.child_elements());
588 self.stack[child_start..].reverse();
589 Some(element)
590 }
591}
592
593pub struct Attributes<'document, S> {
594 element: ElementRef<'document, S>,
595 next: u32,
596 end: u32,
597}
598
599impl<'document, S: AsRef<[u8]>> Iterator for Attributes<'document, S> {
600 type Item = AttributeRef<'document, S>;
601
602 fn next(&mut self) -> Option<Self::Item> {
603 if self.next >= self.end {
604 return None;
605 }
606 let index = self.next;
607 self.next += 1;
608 Some(AttributeRef {
609 element: self.element,
610 index,
611 })
612 }
613}
614
615pub struct AttributeRef<'document, S> {
616 element: ElementRef<'document, S>,
617 index: u32,
618}
619
620impl<S> Copy for AttributeRef<'_, S> {}
621
622impl<S> Clone for AttributeRef<'_, S> {
623 fn clone(&self) -> Self {
624 *self
625 }
626}
627
628impl<'document, S: AsRef<[u8]>> AttributeRef<'document, S> {
629 fn data(self) -> Option<&'document AttributeData> {
630 let data = self.checked_data();
631 debug_assert!(data.is_some(), "invalid internal XML attribute index");
632 data
633 }
634
635 fn checked_data(self) -> Option<&'document AttributeData> {
636 self.document()
637 .attributes
638 .get(stored_index(self.index, "XML attribute index"))
639 }
640
641 fn document(self) -> &'document XmlDocument<S> {
642 self.element.document
643 }
644
645 pub fn qualified_name(self) -> &'document str {
646 self.data()
647 .map(|data| self.document().value(data.qualified_name))
648 .unwrap_or("")
649 }
650
651 pub fn prefix(self) -> Option<&'document str> {
652 split_qualified_name(self.qualified_name()).0
653 }
654
655 pub fn name(self) -> &'document str {
656 split_qualified_name(self.qualified_name()).1
657 }
658
659 pub fn namespace(self) -> Option<&'document str> {
660 let prefix = self.prefix()?;
661 let scope = self
662 .document()
663 .element_data(self.element.id)
664 .and_then(|element| element.namespace_scope);
665 self.document().resolve_namespace(scope, prefix)
666 }
667
668 pub fn value(self) -> &'document str {
669 self.data()
670 .map(|data| self.document().value(data.value))
671 .unwrap_or("")
672 }
673}
674
675struct DocumentBuilder<'a> {
676 source: &'a [u8],
677 options: &'a ParseOptions,
678 nodes: Vec<ArenaNode>,
679 attributes: Vec<AttributeData>,
680 namespace_scopes: Vec<NamespaceScope>,
681 namespace_bindings: Vec<NamespaceBinding>,
682 owned_values: Vec<Box<str>>,
683 open: Vec<NodeId>,
684 root: Option<NodeId>,
685 root_complete: bool,
686 element_count: usize,
687 text_bytes: usize,
688 event_count: usize,
689}
690
691impl<'a> DocumentBuilder<'a> {
692 fn new(source: &'a [u8], options: &'a ParseOptions) -> Self {
693 Self {
694 source,
695 options,
696 nodes: Vec::new(),
697 attributes: Vec::new(),
698 namespace_scopes: Vec::new(),
699 namespace_bindings: Vec::new(),
700 owned_values: Vec::new(),
701 open: Vec::new(),
702 root: None,
703 root_complete: false,
704 element_count: 0,
705 text_bytes: 0,
706 event_count: 0,
707 }
708 }
709
710 fn parse(&mut self) -> Result<(), Error> {
711 let mut reader = Reader::from_reader(self.source);
712 reader.config_mut().trim_text(false);
713 reader.config_mut().check_end_names = true;
714 loop {
715 let event_start = reader.buffer_position();
716 let event = reader.read_event().map_err(|error| {
717 let error_position =
718 usize::try_from(reader.error_position()).unwrap_or(self.source.len());
719 map_quick_xml_error_at(
720 error,
721 error_position,
722 self.source,
723 self.options.safety.reject_doctype,
724 )
725 })?;
726 let event_end = reader.buffer_position();
727 if !matches!(event, Event::Eof) {
728 self.count_event()?;
729 }
730 match event {
731 Event::Start(start) => {
732 self.start_element(&reader, &start, event_start, event_end)?
733 }
734 Event::Empty(start) => {
735 self.empty_element(&reader, &start, event_start, event_end)?
736 }
737 Event::End(_) => self.end_element(event_end)?,
738 Event::Text(text) => {
739 let raw = utf8(text.as_ref())?;
740 let value =
741 unescape(raw).map_err(|error| Error::InvalidXml(error.to_string()))?;
742 self.text_node(value, false)?;
743 }
744 Event::CData(text) => self.text_node(Cow::Borrowed(utf8(text.as_ref())?), true)?,
745 Event::Comment(comment) => {
746 let value = self.source_value(utf8(comment.as_ref())?)?;
747 self.push_content(NodeKind::Comment(value))?;
748 }
749 Event::PI(pi) => {
750 let target = self.source_value(utf8(pi.target())?)?;
751 let content = utf8(pi.content())?
752 .trim_start_matches(|character: char| character.is_ascii_whitespace());
753 let content = (!content.is_empty())
754 .then(|| self.source_value(content))
755 .transpose()?;
756 self.push_content(NodeKind::ProcessingInstruction { target, content })?;
757 }
758 Event::GeneralRef(reference) => {
759 let value = if let Some(character) = reference
760 .resolve_char_ref()
761 .map_err(|error| Error::InvalidXml(error.to_string()))?
762 {
763 Cow::Owned(character.to_string())
764 } else {
765 Cow::Owned(
766 match utf8(reference.as_ref())? {
767 "amp" => "&",
768 "lt" => "<",
769 "gt" => ">",
770 "apos" => "'",
771 "quot" => "\"",
772 _ => return Err(XmlSafetyError::ExternalEntity.into()),
773 }
774 .to_owned(),
775 )
776 };
777 self.text_node(value, false)?;
778 }
779 Event::Decl(_) => {
780 if self.root.is_some() || !self.open.is_empty() || self.root_complete {
781 return Err(XmlSafetyError::Malformed.into());
782 }
783 }
784 Event::DocType(_) => {
785 if self.options.safety.reject_doctype {
786 return Err(XmlSafetyError::ExternalEntity.into());
787 }
788 if self.root.is_some() || !self.open.is_empty() || self.root_complete {
789 return Err(XmlSafetyError::Malformed.into());
790 }
791 }
792 Event::Eof => {
793 if !self.open.is_empty() || !self.root_complete {
794 return Err(XmlSafetyError::Malformed.into());
795 }
796 return Ok(());
797 }
798 }
799 }
800 }
801
802 fn start_element(
803 &mut self,
804 reader: &Reader<&[u8]>,
805 start: &BytesStart<'a>,
806 source_start: u64,
807 source_end: u64,
808 ) -> Result<(), Error> {
809 self.check_element()?;
810 let id = self.build_element(reader, start, source_start, source_end)?;
811 self.open.push(id);
812 Ok(())
813 }
814
815 fn empty_element(
816 &mut self,
817 reader: &Reader<&[u8]>,
818 start: &BytesStart<'a>,
819 source_start: u64,
820 source_end: u64,
821 ) -> Result<(), Error> {
822 self.check_element()?;
823 self.build_element(reader, start, source_start, source_end)?;
824 if self.open.is_empty() {
825 self.root_complete = true;
826 }
827 Ok(())
828 }
829
830 fn end_element(&mut self, source_end: u64) -> Result<(), Error> {
831 let id = self.open.pop().ok_or(XmlSafetyError::Malformed)?;
832 let NodeKind::Element(element) = &mut self.nodes[id.index()].kind else {
833 return Err(XmlSafetyError::Malformed.into());
834 };
835 element.source.end = source_end;
836 if self.open.is_empty() {
837 self.root_complete = true;
838 }
839 Ok(())
840 }
841
842 fn build_element(
843 &mut self,
844 reader: &Reader<&[u8]>,
845 start: &BytesStart<'a>,
846 source_start: u64,
847 source_end: u64,
848 ) -> Result<NodeId, Error> {
849 if self.open.is_empty() && self.root_complete {
850 return Err(XmlSafetyError::Malformed.into());
851 }
852 let start_name = start.name();
853 let qualified_name = utf8(start_name.as_ref())?;
854 let (prefix, _) = validate_qualified_name(qualified_name)?;
855 let parent_scope = self.open.last().and_then(|id| {
856 let NodeKind::Element(element) = &self.nodes[id.index()].kind else {
857 return None;
858 };
859 element.namespace_scope
860 });
861 let binding_start = arena_len(self.namespace_bindings.len(), "namespace bindings")?;
862 let mut attribute_count = 0usize;
863 for attribute in start.attributes() {
864 attribute_count = attribute_count
865 .checked_add(1)
866 .ok_or(XmlSafetyError::TooManyAttributes)?;
867 if attribute_count > self.options.safety.max_attributes_per_element {
868 return Err(XmlSafetyError::TooManyAttributes.into());
869 }
870 let attribute = attribute.map_err(|error| Error::InvalidXml(error.to_string()))?;
871 let name = utf8(attribute.key.as_ref())?;
872 validate_qualified_name(name)?;
873 if name == "xmlns" || name.starts_with("xmlns:") {
874 let namespace_prefix = name.strip_prefix("xmlns:").unwrap_or("");
875 let uri = attribute
876 .decoded_and_normalized_value(XmlVersion::Explicit1_0, reader.decoder())
877 .map_err(|error| Error::InvalidXml(error.to_string()))?;
878 validate_namespace_binding(namespace_prefix, &uri)?;
879 let prefix_value = if namespace_prefix.is_empty() {
880 ValueRef::source(0, 0)
881 } else {
882 self.source_value(namespace_prefix)?
883 };
884 let uri_value = if uri.is_empty() {
885 None
886 } else {
887 Some(self.cow_value(uri)?)
888 };
889 self.namespace_bindings.push(NamespaceBinding {
890 prefix: prefix_value,
891 uri: uri_value,
892 });
893 }
894 }
895 let binding_end = arena_len(self.namespace_bindings.len(), "namespace bindings")?;
896 let namespace_scope = if binding_start == binding_end {
897 parent_scope
898 } else {
899 let id = ScopeId::from_index(self.namespace_scopes.len())?;
900 self.namespace_scopes.push(NamespaceScope {
901 parent: parent_scope,
902 bindings: binding_start..binding_end,
903 });
904 Some(id)
905 };
906 if let Some(prefix) = prefix
907 && self
908 .arena_view()
909 .resolve_namespace(namespace_scope, prefix)
910 .is_none()
911 {
912 return Err(XmlSafetyError::Malformed.into());
913 }
914
915 let attribute_start = arena_len(self.attributes.len(), "attributes")?;
916 for attribute in start.attributes() {
917 let attribute = attribute.map_err(|error| Error::InvalidXml(error.to_string()))?;
918 let name = utf8(attribute.key.as_ref())?;
919 if name == "xmlns" || name.starts_with("xmlns:") {
920 continue;
921 }
922 let (prefix, _) = split_qualified_name(name);
923 if let Some(prefix) = prefix
924 && prefix != "xml"
925 && self
926 .arena_view()
927 .resolve_namespace(namespace_scope, prefix)
928 .is_none()
929 {
930 return Err(XmlSafetyError::Malformed.into());
931 }
932 let value = attribute
933 .decoded_and_normalized_value(XmlVersion::Explicit1_0, reader.decoder())
934 .map_err(|error| Error::InvalidXml(error.to_string()))?;
935 let qualified_name = self.source_value(name)?;
936 let value = self.cow_value(value)?;
937 self.attributes.push(AttributeData {
938 qualified_name,
939 value,
940 });
941 }
942 let attribute_end = arena_len(self.attributes.len(), "attributes")?;
943 let qualified_name = self.source_value(qualified_name)?;
944 let id = self.push_node(NodeKind::Element(ElementData {
945 qualified_name,
946 attributes: attribute_start..attribute_end,
947 namespace_scope,
948 source: SourceSpan {
949 start: source_start,
950 end: source_end,
951 },
952 }))?;
953 if self.root.is_none() {
954 self.root = Some(id);
955 }
956 Ok(id)
957 }
958
959 fn check_element(&mut self) -> Result<(), Error> {
960 let depth = self
961 .open
962 .len()
963 .checked_add(1)
964 .ok_or(XmlSafetyError::TooDeep)?;
965 if depth > self.options.safety.max_depth {
966 return Err(XmlSafetyError::TooDeep.into());
967 }
968 self.element_count = self
969 .element_count
970 .checked_add(1)
971 .ok_or(XmlSafetyError::TooManyElements)?;
972 if self.element_count > self.options.safety.max_elements {
973 return Err(XmlSafetyError::TooManyElements.into());
974 }
975 Ok(())
976 }
977
978 fn count_event(&mut self) -> Result<(), Error> {
979 self.event_count = self
980 .event_count
981 .checked_add(1)
982 .ok_or(XmlSafetyError::TooManyEvents)?;
983 if self.event_count > self.options.safety.max_events {
984 return Err(XmlSafetyError::TooManyEvents.into());
985 }
986 Ok(())
987 }
988
989 fn text_node(&mut self, value: Cow<'_, str>, cdata: bool) -> Result<(), Error> {
990 self.text_bytes = self
991 .text_bytes
992 .checked_add(value.len())
993 .ok_or(XmlSafetyError::TextTooLarge)?;
994 if self.text_bytes > self.options.safety.max_text_bytes {
995 return Err(XmlSafetyError::TextTooLarge.into());
996 }
997 let value = if self.options.trim_whitespace {
998 match value {
999 Cow::Borrowed(value) => Cow::Borrowed(value.trim()),
1000 Cow::Owned(value) => Cow::Owned(value.trim().to_owned()),
1001 }
1002 } else {
1003 value
1004 };
1005 if value.is_empty() {
1006 return Ok(());
1007 }
1008 if self.open.is_empty() {
1009 if value.chars().all(char::is_whitespace) {
1010 return Ok(());
1011 }
1012 return Err(XmlSafetyError::Malformed.into());
1013 }
1014 let value = self.cow_value(value)?;
1015 self.push_content(if cdata {
1016 NodeKind::CData(value)
1017 } else {
1018 NodeKind::Text(value)
1019 })?;
1020 Ok(())
1021 }
1022
1023 fn push_content(&mut self, kind: NodeKind) -> Result<(), Error> {
1024 if self.open.is_empty() {
1025 return Ok(());
1026 }
1027 self.push_node(kind).map(|_| ())
1028 }
1029
1030 fn push_node(&mut self, kind: NodeKind) -> Result<NodeId, Error> {
1031 let id = NodeId::from_index(self.nodes.len())?;
1032 let parent = self.open.last().copied();
1033 self.nodes.push(ArenaNode {
1034 parent,
1035 first_child: None,
1036 last_child: None,
1037 next_sibling: None,
1038 kind,
1039 });
1040 if let Some(parent) = parent {
1041 if let Some(previous) = self.nodes[parent.index()].last_child {
1042 self.nodes[previous.index()].next_sibling = Some(id);
1043 } else {
1044 self.nodes[parent.index()].first_child = Some(id);
1045 }
1046 self.nodes[parent.index()].last_child = Some(id);
1047 }
1048 Ok(id)
1049 }
1050
1051 fn source_value(&self, value: &str) -> Result<ValueRef, Error> {
1052 let source_start = self.source.as_ptr() as usize;
1053 let value_start = value.as_ptr() as usize;
1054 let offset = value_start
1055 .checked_sub(source_start)
1056 .filter(|offset| offset.saturating_add(value.len()) <= self.source.len())
1057 .ok_or_else(|| Error::InvalidXml("borrowed value is outside XML source".into()))?;
1058 Ok(ValueRef::source(
1059 usize_to_u64(offset, "XML value offset").map_err(|_| XmlSafetyError::InputTooLarge)?,
1060 usize_to_u32(value.len(), "XML value length")
1061 .map_err(|_| XmlSafetyError::InputTooLarge)?,
1062 ))
1063 }
1064
1065 fn cow_value(&mut self, value: Cow<'_, str>) -> Result<ValueRef, Error> {
1066 match value {
1067 Cow::Borrowed(value) => self.source_value(value),
1068 Cow::Owned(value) => {
1069 let index = arena_len(self.owned_values.len(), "owned XML values")?;
1070 let length = usize_to_u32(value.len(), "owned XML value length")
1071 .map_err(|_| XmlSafetyError::InputTooLarge)?;
1072 self.owned_values.push(value.into_boxed_str());
1073 Ok(ValueRef::owned(index, length))
1074 }
1075 }
1076 }
1077
1078 fn arena_view(&self) -> ArenaView<'_> {
1079 ArenaView {
1080 source: self.source,
1081 namespace_scopes: &self.namespace_scopes,
1082 namespace_bindings: &self.namespace_bindings,
1083 owned_values: &self.owned_values,
1084 }
1085 }
1086}
1087
1088fn arena_len(length: usize, label: &str) -> Result<u32, Error> {
1089 usize_to_u32(length, label).map_err(|_| Error::InvalidXml(format!("too many {label}")))
1090}
1091
1092fn stored_index(value: u32, label: &str) -> usize {
1093 u32_to_usize(value, label).unwrap_or(usize::MAX)
1096}
1097
1098#[cfg(test)]
1099mod layout_tests {
1100 use std::mem::size_of_val;
1101
1102 use super::*;
1103
1104 fn arena_payload_bytes<S>(document: &XmlDocument<S>) -> usize {
1105 size_of_val(document.nodes.as_ref())
1106 + size_of_val(document.attributes.as_ref())
1107 + size_of_val(document.namespace_scopes.as_ref())
1108 + size_of_val(document.namespace_bindings.as_ref())
1109 + size_of_val(document.owned_values.as_ref())
1110 + document
1111 .owned_values
1112 .iter()
1113 .map(|value| value.len())
1114 .sum::<usize>()
1115 }
1116
1117 #[test]
1118 fn arena_view_rejects_invalid_value_ranges_and_namespace_indices() {
1119 let source = b"value\xFF";
1120 let owned_values = [Box::<str>::from("owned")];
1121 let scope = ScopeId::from_index(0).expect("scope id");
1122 let namespace_scopes = [NamespaceScope {
1123 parent: None,
1124 bindings: 0..1,
1125 }];
1126 let view = ArenaView {
1127 source,
1128 namespace_scopes: &namespace_scopes,
1129 namespace_bindings: &[],
1130 owned_values: &owned_values,
1131 };
1132
1133 assert_eq!(view.checked_value(ValueRef::source(0, 5)), Some("value"));
1134 assert_eq!(view.checked_value(ValueRef::owned(0, 5)), Some("owned"));
1135 assert_eq!(view.checked_value(ValueRef::source(5, 1)), None);
1136 assert_eq!(view.checked_value(ValueRef::source(u64::MAX, 2)), None);
1137 assert_eq!(view.checked_value(ValueRef::owned(1, 5)), None);
1138 assert_eq!(view.checked_value(ValueRef::owned(0, 4)), None);
1139 assert_eq!(view.checked_resolve_namespace(Some(scope), "p"), Err(()));
1140 }
1141
1142 #[test]
1143 fn attribute_lookup_reports_invalid_internal_indices_without_indexing() {
1144 let document = BorrowedDocument::parse(br#"<root id="7"/>"#.as_slice())
1145 .expect("document should parse");
1146 let attribute = AttributeRef {
1147 element: document.root(),
1148 index: u32::MAX,
1149 };
1150
1151 assert!(attribute.checked_data().is_none());
1152 }
1153
1154 #[test]
1155 fn large_owned_document_payload_stays_below_six_times_input() {
1156 const RESPONSES: usize = 10_000;
1157 let mut source = String::from("<D:multistatus xmlns:D=\"DAV:\">");
1158 for index in 0..RESPONSES {
1159 source.push_str(&format!(
1160 "<D:response><D:href>/files/{index}</D:href><D:propstat><D:prop><D:displayname>file-{index}</D:displayname><D:getcontentlength>{}</D:getcontentlength><D:getetag>"etag-{index}"</D:getetag></D:prop><D:status>HTTP/1.1 200 OK</D:status></D:propstat></D:response>",
1161 index * 1024
1162 ));
1163 }
1164 source.push_str("</D:multistatus>");
1165 let input_bytes = source.len();
1166 let options = ParseOptions::new()
1167 .max_size(input_bytes)
1168 .max_elements(RESPONSES * 8 + 1);
1169 let document = XmlDocument::parse_with_options(Arc::from(source.into_bytes()), &options)
1170 .expect("large document");
1171 let retained_payload = input_bytes + arena_payload_bytes(&document);
1172
1173 assert!(
1174 retained_payload <= input_bytes * 6,
1175 "retained payload {retained_payload} exceeds 6x input {input_bytes}"
1176 );
1177 }
1178}