1use super::{u64_from_index, DecodeContext, ScopedReservation};
5use crate::CodecError;
6
7const NODE_RECORD_BOUND: u64 = 128;
10const ATTRIBUTE_RECORD_BOUND: u64 = 128;
13const NAMESPACE_RECORD_BOUND: u64 = 64;
16const XML_PREFIX_BYTES: u64 = 3;
18const XML_NAMESPACE_URI_BYTES: u64 = 36;
19
20#[derive(Debug)]
22pub struct AdmittedXml<'input, 'ctx> {
23 document: roxmltree::Document<'input>,
24 _reservation: ScopedReservation<'ctx>,
25}
26
27impl<'input> AdmittedXml<'input, '_> {
28 pub fn document(&self) -> &roxmltree::Document<'input> {
30 &self.document
31 }
32}
33
34#[derive(Clone, Copy)]
35enum XmlScan<'input> {
36 Text,
37 Tag(XmlTag<'input>),
38 Comment,
39 Cdata,
40 Instruction,
41 Declaration,
42}
43
44#[derive(Clone, Copy)]
45struct XmlTag<'input> {
46 closing: bool,
47 quote: u8,
48 last: u8,
49 attributes: u64,
50 name_bytes: u64,
51 name_complete: bool,
52 attribute_name_bytes: u64,
53 namespace_key_bytes: u64,
54 prefixed_attributes: u64,
55 namespaces: u64,
56 start: usize,
57 undo_start: usize,
58 namespace_prefix: Option<&'input str>,
59 quote_start: usize,
60}
61
62#[derive(Clone, Copy)]
64struct XmlNamespaceScope {
65 element_depth: u64,
66 undo_start: usize,
67 count: u64,
68 max_prefix: u64,
69 max_uri: u64,
70}
71
72impl Default for XmlNamespaceScope {
73 fn default() -> Self {
74 Self {
75 element_depth: 0,
76 undo_start: 0,
77 count: 0,
78 max_prefix: XML_PREFIX_BYTES,
79 max_uri: XML_NAMESPACE_URI_BYTES,
80 }
81 }
82}
83
84struct XmlNamespaces<'ctx, 'input> {
87 prefixes: std::collections::HashMap<&'input str, u64>,
88 bindings: std::collections::HashSet<(&'input str, &'input str)>,
89 undo: Vec<(&'input str, Option<u64>)>,
90 scopes: Vec<XmlNamespaceScope>,
91 storage: ScopedReservation<'ctx>,
92 ctx: &'ctx DecodeContext<'ctx>,
93}
94
95impl<'ctx, 'input> XmlNamespaces<'ctx, 'input> {
96 fn new(ctx: &'ctx DecodeContext<'_>, operation: &'static str) -> Result<Self, CodecError> {
97 Ok(Self {
98 prefixes: std::collections::HashMap::new(),
99 bindings: std::collections::HashSet::new(),
100 undo: Vec::new(),
101 scopes: Vec::new(),
102 storage: ctx.reserve_scoped(0, operation)?,
103 ctx,
104 })
105 }
106
107 fn parent(&self) -> XmlNamespaceScope {
108 self.scopes.last().copied().unwrap_or_default()
109 }
110
111 fn declare(&mut self, prefix: &'input str, operation: &'static str) -> Result<(), CodecError> {
112 self.ctx.charge_work(
113 u64_from_index(prefix.len())
114 .checked_mul(6)
115 .and_then(|work| work.checked_add(1))
116 .ok_or_else(|| self.ctx.tree_overflow(operation))?,
117 operation,
118 )?;
119 let previous = self.prefixes.get(prefix).copied();
120 if previous.is_none() && self.prefixes.len() == self.prefixes.capacity() {
121 for stored in self.prefixes.keys() {
122 self.ctx.charge_work(
123 u64_from_index(stored.len())
124 .checked_add(1)
125 .ok_or_else(|| self.ctx.tree_overflow(operation))?,
126 operation,
127 )?;
128 }
129 }
130 self.storage.with_storage(|| {
131 self.ctx
132 .push_vec(&mut self.undo, (prefix, previous), operation)?;
133 self.ctx
134 .insert_hash_map(&mut self.prefixes, prefix, 0, operation)?;
135 Ok::<_, CodecError>(())
136 })
137 }
138
139 fn value(
140 &mut self,
141 prefix: &'input str,
142 uri: &'input str,
143 operation: &'static str,
144 ) -> Result<(), CodecError> {
145 self.ctx.charge_work(
146 u64_from_index(prefix.len())
147 .checked_mul(4)
148 .and_then(|work| work.checked_add(u64_from_index(uri.len()).checked_mul(2)?))
149 .and_then(|work| work.checked_add(1))
150 .ok_or_else(|| self.ctx.tree_overflow(operation))?,
151 operation,
152 )?;
153 if let Some(value) = self.prefixes.get_mut(prefix) {
154 *value = u64_from_index(uri.len());
155 }
156 if self.bindings.contains(&(prefix, uri)) {
157 return Ok(());
158 }
159 if self.bindings.len() == self.bindings.capacity() {
160 for (stored_prefix, stored_uri) in &self.bindings {
161 self.ctx.charge_work(
162 u64_from_index(stored_prefix.len())
163 .checked_add(u64_from_index(stored_uri.len()))
164 .and_then(|work| work.checked_add(1))
165 .ok_or_else(|| self.ctx.tree_overflow(operation))?,
166 operation,
167 )?;
168 }
169 }
170 self.storage.with_storage(|| {
171 self.ctx.reserve_set(&mut self.bindings, 1, operation)?;
172 self.bindings.insert((prefix, uri));
173 Ok::<_, CodecError>(())
174 })
175 }
176
177 fn scope(
178 &self,
179 tag: &XmlTag<'_>,
180 operation: &'static str,
181 ) -> Result<XmlNamespaceScope, CodecError> {
182 let mut scope = self.parent();
183 scope.undo_start = tag.undo_start;
184 if tag.namespaces != 0 {
185 scope = XmlNamespaceScope {
186 undo_start: tag.undo_start,
187 count: u64_from_index(self.prefixes.len())
190 .checked_add(tag.namespaces)
191 .ok_or_else(|| self.ctx.tree_overflow(operation))?,
192 ..XmlNamespaceScope::default()
193 };
194 for (prefix, uri_bytes) in &self.prefixes {
195 self.ctx.charge_work(1, operation)?;
196 scope.max_prefix = scope.max_prefix.max(u64_from_index(prefix.len()));
197 scope.max_uri = scope.max_uri.max(*uri_bytes);
198 }
199 }
200 Ok(scope)
201 }
202
203 fn restore(&mut self, start: usize, operation: &'static str) -> Result<(), CodecError> {
204 while self.undo.len() > start {
205 if let Some((prefix, previous)) = self.undo.pop() {
206 self.ctx.charge_work(
207 u64_from_index(prefix.len())
208 .checked_mul(2)
209 .and_then(|work| work.checked_add(1))
210 .ok_or_else(|| self.ctx.tree_overflow(operation))?,
211 operation,
212 )?;
213 match previous {
214 Some(previous) => {
215 self.prefixes.insert(prefix, previous);
216 }
217 None => {
218 self.prefixes.remove(prefix);
219 }
220 }
221 }
222 }
223 Ok(())
224 }
225
226 fn finish(
227 &mut self,
228 tag: &XmlTag<'_>,
229 mut scope: XmlNamespaceScope,
230 depth: Option<u64>,
231 operation: &'static str,
232 ) -> Result<(), CodecError> {
233 if tag.closing {
234 if self
235 .scopes
236 .last()
237 .is_some_and(|parent| Some(parent.element_depth) == depth)
238 {
239 if let Some(parent) = self.scopes.pop() {
240 self.restore(parent.undo_start, operation)?;
241 }
242 }
243 } else if tag.last == b'/' {
244 self.restore(tag.undo_start, operation)?;
245 } else if tag.namespaces != 0 {
246 scope.element_depth = depth
247 .unwrap_or(0)
248 .checked_add(1)
249 .ok_or_else(|| self.ctx.tree_overflow(operation))?;
250 self.storage
251 .with_storage(|| self.ctx.push_vec(&mut self.scopes, scope, operation))?;
252 }
253 Ok(())
254 }
255}
256
257struct XmlBound {
258 nodes: u64,
259 attributes: u64,
260 namespace_references: Option<u64>,
261 depth: u64,
262 local_comparisons: Option<u64>,
263 namespace_unique: u64,
264 namespace_bytes: u64,
265}
266
267impl XmlBound {
268 fn tag(&mut self, tag: &XmlTag<'_>, parent: XmlNamespaceScope, scope: XmlNamespaceScope) {
269 self.namespace_bytes += tag.namespace_key_bytes;
270 if tag.namespaces != 0 {
271 self.namespace_references = self
272 .namespace_references
273 .and_then(|references| references.checked_add(scope.count));
274 }
275 self.local_comparisons = self.local_comparisons.and_then(|work| {
276 let attributes = tag
277 .attribute_name_bytes
278 .checked_add(tag.attributes)?
279 .checked_mul(tag.attributes.checked_add(1)?)?;
280 let lookups = tag
281 .name_bytes
282 .checked_add(tag.attribute_name_bytes)?
283 .checked_add(tag.attributes.checked_add(1)?)?
284 .checked_mul(scope.count.checked_add(1)?)?;
285 let uris = tag
286 .prefixed_attributes
287 .checked_mul(tag.prefixed_attributes)?
288 .checked_mul(scope.max_uri.checked_add(1)?)?;
289 let namespaces = if tag.namespaces == 0 {
290 0
291 } else {
292 parent
295 .count
296 .checked_mul(parent.count.checked_add(tag.namespaces)?)?
297 .checked_add(tag.namespaces.checked_mul(tag.namespaces)?)?
298 .checked_mul(scope.max_prefix.checked_add(1)?)?
299 };
300 work.checked_add(attributes)?
301 .checked_add(lookups)?
302 .checked_add(uris)?
303 .checked_add(namespaces)
304 });
305 }
306
307 fn comparison_work(&self) -> Option<u64> {
308 let namespaces = self.namespace_unique.checked_add(1)?;
309 let levels = u64::from(u64::BITS - namespaces.leading_zeros()) + 1;
310 let insertion = self
313 .namespace_bytes
314 .checked_mul(levels)?
315 .checked_add(namespaces.checked_mul(namespaces)?.checked_mul(2)?)?;
316 self.local_comparisons?.checked_add(insertion)
317 }
318}
319
320fn xml_bound(
323 text: &str,
324 ctx: &DecodeContext<'_>,
325 operation: &'static str,
326) -> Result<XmlBound, CodecError> {
327 let bytes = text.as_bytes();
328 let mut depth = Some(0_u64);
329 let mut maximum = 0;
330 let mut bound = XmlBound {
331 nodes: 0,
332 attributes: 0,
333 namespace_references: Some(0),
334 depth: 0,
335 local_comparisons: Some(0),
336 namespace_unique: 0,
337 namespace_bytes: 0,
338 };
339 let mut namespaces = XmlNamespaces::new(ctx, operation)?;
340 let mut state = XmlScan::Text;
341 for (index, &byte) in bytes.iter().enumerate() {
342 bound.nodes += u64::from(byte == b'<');
343 bound.attributes += u64::from(byte == b'=');
344 let tail = &bytes[index..];
345 state = match state {
346 XmlScan::Text if byte == b'<' => {
347 if tail.starts_with(b"<!--") {
348 XmlScan::Comment
349 } else if tail.starts_with(b"<![CDATA[") {
350 XmlScan::Cdata
351 } else if tail.starts_with(b"<?") {
352 XmlScan::Instruction
353 } else if tail.starts_with(b"<!") {
354 XmlScan::Declaration
355 } else {
356 XmlScan::Tag(XmlTag {
357 closing: tail.starts_with(b"</"),
358 quote: 0,
359 last: byte,
360 attributes: 0,
361 name_bytes: 0,
362 name_complete: false,
363 attribute_name_bytes: 0,
364 namespace_key_bytes: 0,
365 prefixed_attributes: 0,
366 namespaces: 0,
367 start: index,
368 undo_start: namespaces.undo.len(),
369 namespace_prefix: None,
370 quote_start: index,
371 })
372 }
373 }
374 XmlScan::Tag(mut tag) => {
375 if !(tag.name_complete || byte == b'/' && tag.closing && tag.name_bytes == 0) {
377 if byte.is_ascii_whitespace() || matches!(byte, b'/' | b'>') {
378 tag.name_complete = true;
379 } else {
380 tag.name_bytes += 1;
381 }
382 }
383 if tag.quote != 0 {
384 if byte == tag.quote {
385 if let Some(prefix) = tag.namespace_prefix {
386 tag.namespace_key_bytes = tag
387 .namespace_key_bytes
388 .checked_add(u64_from_index(index - tag.quote_start))
389 .ok_or_else(|| ctx.tree_overflow(operation))?;
390 namespaces.value(prefix, &text[tag.quote_start..index], operation)?;
391 }
392 tag.quote = 0;
393 }
394 } else if matches!(byte, b'\'' | b'"') {
395 tag.quote = byte;
396 tag.quote_start = index + 1;
397 } else if byte == b'>' {
398 let scope = namespaces.scope(&tag, operation)?;
399 bound.tag(&tag, namespaces.parent(), scope);
400 namespaces.finish(&tag, scope, depth, operation)?;
401 if tag.closing {
402 depth = depth.and_then(|depth| depth.checked_sub(1));
403 } else if let Some(parent_depth) = depth {
404 let element_depth = parent_depth + 1;
405 maximum = maximum.max(element_depth);
406 if tag.last != b'/' {
407 depth = Some(element_depth);
408 }
409 }
410 state = XmlScan::Text;
411 continue;
412 } else {
413 if byte == b'=' {
414 let mut end = index;
415 while end > tag.start && bytes[end - 1].is_ascii_whitespace() {
416 end -= 1;
417 }
418 let mut begin = end;
419 while begin > tag.start
420 && !bytes[begin - 1].is_ascii_whitespace()
421 && !matches!(bytes[begin - 1], b'<' | b'>' | b'=' | b'\'' | b'"' | b'/')
422 {
423 begin -= 1;
424 }
425 let name = &text[begin..end];
426 tag.attribute_name_bytes = tag
427 .attribute_name_bytes
428 .checked_add(u64_from_index(name.len()))
429 .ok_or_else(|| ctx.tree_overflow(operation))?;
430 tag.namespace_prefix = if name == "xmlns" {
431 Some("")
432 } else {
433 name.strip_prefix("xmlns:")
434 };
435 if let Some(prefix) = tag.namespace_prefix {
436 tag.namespaces += 1;
437 tag.namespace_key_bytes = tag
438 .namespace_key_bytes
439 .checked_add(u64_from_index(name.len()))
440 .ok_or_else(|| ctx.tree_overflow(operation))?;
441 namespaces.declare(prefix, operation)?;
442 } else {
443 tag.prefixed_attributes += u64::from(name.contains(':'));
444 }
445 tag.attributes += 1;
446 }
447 tag.last = byte;
448 }
449 XmlScan::Tag(tag)
450 }
451 XmlScan::Comment if tail.starts_with(b"-->") => XmlScan::Text,
452 XmlScan::Cdata if tail.starts_with(b"]]>") => XmlScan::Text,
453 XmlScan::Instruction if tail.starts_with(b"?>") => XmlScan::Text,
454 XmlScan::Declaration if byte == b'>' => XmlScan::Text,
455 other => other,
456 };
457 }
458 if let XmlScan::Tag(tag) = state {
459 let scope = namespaces.scope(&tag, operation)?;
460 bound.tag(&tag, namespaces.parent(), scope);
461 }
462 bound.depth = maximum;
463 bound.namespace_unique = u64_from_index(namespaces.bindings.len());
464 Ok(bound)
465}
466
467fn at_depth<T>(
470 ctx: &DecodeContext<'_>,
471 depth: u64,
472 operation: &'static str,
473 parse: impl FnOnce() -> Result<T, CodecError>,
474) -> Result<T, CodecError> {
475 if depth == 0 {
476 return parse();
477 }
478 ctx.charge_work(depth, operation)?;
479 ctx.charge_collection_items(depth, operation)?;
480 let count =
481 usize::try_from(depth).map_err(|_| ctx.refuse_codec_limit(operation, u64::MAX, depth))?;
482 let capacity = count
483 .checked_add(4)
484 .ok_or_else(|| ctx.refuse_codec_limit(operation, u64::MAX, depth))?;
485 let (_reservation, mut guards) = {
486 let (guards, reservation) = ctx.scoped_vector_storage(capacity, operation)?;
487 (reservation, guards)
488 };
489 for _ in 0..count {
490 guards.push(ctx.enter_nested(operation)?);
491 }
492 let result = parse();
493 drop(guards);
494 result
495}
496
497impl DecodeContext<'_> {
498 fn tree_malformed(&self, error: impl std::fmt::Display, operation: &'static str) -> CodecError {
499 match self.format_retained(format_args!("{error}"), operation) {
500 Ok(message) => CodecError::Malformed(message),
501 Err(error) => error,
502 }
503 }
504
505 fn tree_overflow(&self, operation: &'static str) -> CodecError {
506 self.refuse_codec_limit(operation, u64::MAX, u64::MAX)
507 }
508
509 pub fn parse_xml<'input>(
529 &self,
530 text: &'input str,
531 operation: &'static str,
532 ) -> Result<AdmittedXml<'input, '_>, CodecError> {
533 let length = u64_from_index(text.len());
534 self.charge_work(length, operation)?;
535 let bound = xml_bound(text, self, operation)?;
536 let nodes = bound
537 .nodes
538 .checked_mul(2)
539 .and_then(|n| n.checked_add(2))
540 .ok_or_else(|| self.tree_overflow(operation))?;
541 let namespaces = bound
542 .namespace_unique
543 .checked_add(1)
544 .ok_or_else(|| self.tree_overflow(operation))?;
545 let namespace_references = bound
546 .namespace_references
547 .ok_or_else(|| self.tree_overflow(operation))?;
548 let capacity = |n: u64, minimum: u64| n.checked_mul(2).and_then(|n| n.checked_add(minimum));
549 let bytes = (|| {
550 let node_bytes = capacity(nodes, 4)?.checked_mul(NODE_RECORD_BOUND + 64)?;
551 let attribute_bytes =
552 capacity(bound.attributes, 16)?.checked_mul(ATTRIBUTE_RECORD_BOUND * 2)?;
553 let namespace_bytes =
554 capacity(namespaces, 4)?.checked_mul(NAMESPACE_RECORD_BOUND + 2)?;
555 let namespace_indices = namespace_references
556 .checked_mul(3)?
557 .checked_add(4)?
558 .checked_mul(2)?;
559 let strings = nodes
560 .checked_add(bound.attributes)?
561 .checked_add(namespaces)?
562 .checked_mul(32)?;
563 node_bytes
564 .checked_add(attribute_bytes)?
565 .checked_add(namespace_bytes)?
566 .checked_add(namespace_indices)?
567 .checked_add(strings)?
568 .checked_add(length.checked_mul(8)?)?
569 .checked_add(1024)
570 })()
571 .ok_or_else(|| self.tree_overflow(operation))?;
572 let work = length
573 .checked_mul(4)
574 .and_then(|n| n.checked_add(nodes))
575 .and_then(|n| n.checked_add(bound.comparison_work()?))
576 .ok_or_else(|| self.tree_overflow(operation))?;
577 self.charge_collection_items(nodes, operation)?;
578 self.charge_collection_items(bound.attributes, operation)?;
579 self.charge_collection_items(namespaces, operation)?;
580 let scratch_items = nodes
581 .checked_mul(3)
582 .and_then(|n| n.checked_add(bound.attributes))
583 .and_then(|n| n.checked_add(namespaces))
584 .and_then(|n| n.checked_add(namespace_references))
585 .ok_or_else(|| self.tree_overflow(operation))?;
586 self.charge_collection_items(scratch_items, operation)?;
587 self.charge_work(work, operation)?;
588 let reservation = self.reserve_scoped(bytes, operation)?;
589 let nodes_limit = u32::try_from(nodes).map_err(|_| self.tree_overflow(operation))?;
590 let document = at_depth(self, bound.depth, operation, || {
591 roxmltree::Document::parse_with_options(
592 text,
593 roxmltree::ParsingOptions {
594 nodes_limit,
595 ..roxmltree::ParsingOptions::default()
596 },
597 )
598 .map_err(|error| match error {
599 roxmltree::Error::NodesLimitReached => {
600 self.refuse_codec_limit(operation, u64::from(nodes_limit), nodes)
601 }
602 other => self.tree_malformed(other, operation),
603 })
604 })?;
605 Ok(AdmittedXml {
606 document,
607 _reservation: reservation,
608 })
609 }
610}
611
612const JSON_MAP_ENTRY_BOUND: u64 = 4096;
617const RAW_VALUE_TOKEN: &[u8] = b"$serde_json::private::RawValue";
618
619#[derive(Default)]
620struct JsonStringScan {
621 active: bool,
622 escaped: bool,
623 unicode_digits: u8,
624 unicode_value: u32,
625 matched: usize,
626 possible: bool,
627}
628
629impl JsonStringScan {
630 fn decoded(&mut self, byte: Option<u8>) {
631 if byte.is_some() && byte == RAW_VALUE_TOKEN.get(self.matched).copied() {
632 self.matched += 1;
633 } else {
634 self.possible = false;
635 }
636 }
637
638 fn byte(&mut self, byte: u8) -> bool {
640 if self.unicode_digits != 0 {
641 if let Some(digit) = char::from(byte).to_digit(16) {
642 self.unicode_value = self.unicode_value * 16 + digit;
643 } else {
644 self.possible = false;
645 }
646 self.unicode_digits -= 1;
647 if self.unicode_digits == 0 {
648 self.decoded(u8::try_from(self.unicode_value).ok());
649 }
650 } else if self.escaped {
651 self.escaped = false;
652 if byte == b'u' {
653 self.unicode_digits = 4;
654 self.unicode_value = 0;
655 } else {
656 self.decoded(match byte {
657 b'"' | b'\\' | b'/' => Some(byte),
658 b'b' => Some(8),
659 b'f' => Some(12),
660 b'n' => Some(b'\n'),
661 b'r' => Some(b'\r'),
662 b't' => Some(b'\t'),
663 _ => None,
664 });
665 }
666 } else if byte == b'\\' {
667 self.escaped = true;
668 } else if byte == b'"' {
669 self.active = false;
670 return self.possible && self.matched == RAW_VALUE_TOKEN.len();
671 } else {
672 self.decoded(Some(byte));
673 }
674 false
675 }
676}
677
678struct PlainJson;
682
683impl<'de> serde::de::DeserializeSeed<'de> for PlainJson {
684 type Value = serde_json::Value;
685 fn deserialize<D: serde::Deserializer<'de>>(self, parser: D) -> Result<Self::Value, D::Error> {
686 parser.deserialize_any(self)
687 }
688}
689
690impl<'de> serde::de::Visitor<'de> for PlainJson {
691 type Value = serde_json::Value;
692 fn expecting(&self, formatter: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
693 formatter.write_str("a JSON value")
694 }
695 fn visit_unit<E: serde::de::Error>(self) -> Result<Self::Value, E> {
696 Ok(serde_json::Value::Null)
697 }
698 fn visit_bool<E: serde::de::Error>(self, value: bool) -> Result<Self::Value, E> {
699 Ok(serde_json::Value::Bool(value))
700 }
701 fn visit_i64<E: serde::de::Error>(self, value: i64) -> Result<Self::Value, E> {
702 Ok(serde_json::Value::Number(value.into()))
703 }
704 fn visit_u64<E: serde::de::Error>(self, value: u64) -> Result<Self::Value, E> {
705 Ok(serde_json::Value::Number(value.into()))
706 }
707 fn visit_f64<E: serde::de::Error>(self, value: f64) -> Result<Self::Value, E> {
708 serde_json::Number::from_f64(value)
709 .map(serde_json::Value::Number)
710 .ok_or_else(|| E::custom("JSON number is not finite"))
711 }
712 fn visit_str<E: serde::de::Error>(self, value: &str) -> Result<Self::Value, E> {
713 Ok(serde_json::Value::String(value.to_owned()))
714 }
715 fn visit_string<E: serde::de::Error>(self, value: String) -> Result<Self::Value, E> {
716 Ok(serde_json::Value::String(value))
717 }
718 fn visit_seq<A: serde::de::SeqAccess<'de>>(
719 self,
720 mut sequence: A,
721 ) -> Result<Self::Value, A::Error> {
722 let mut values = Vec::new();
723 while let Some(value) = sequence.next_element_seed(PlainJson)? {
724 values.push(value);
725 }
726 Ok(serde_json::Value::Array(values))
727 }
728 fn visit_map<A: serde::de::MapAccess<'de>>(self, mut map: A) -> Result<Self::Value, A::Error> {
729 let mut values = serde_json::Map::new();
730 while let Some(key) = map.next_key::<String>()? {
731 let value = map.next_value_seed(PlainJson)?;
732 drop(values.insert(key, value));
733 }
734 Ok(serde_json::Value::Object(values))
735 }
736}
737
738struct JsonBound {
739 values: u64,
740 entries: u64,
741 depth: u64,
742 bytes: u64,
743}
744
745impl DecodeContext<'_> {
746 fn json_bound(&self, text: &str, operation: &'static str) -> Result<JsonBound, CodecError> {
757 let length = u64_from_index(text.len());
758 self.charge_work(length, operation)?;
759 let mut values = 0_u64;
760 let mut entries = 0_u64;
761 let mut depth = 0_u64;
762 let mut maximum = 0_u64;
763 let mut openings = 0_u64;
764 let mut escapes = 0_u64;
765 let mut raw = false;
766 let mut string = JsonStringScan::default();
767 for &byte in text.as_bytes() {
768 values += u64::from(matches!(byte, b'[' | b'{' | b',' | b':'));
769 entries += u64::from(byte == b':');
770 openings += u64::from(matches!(byte, b'[' | b'{'));
771 escapes += u64::from(byte == b'\\');
772 if string.active {
773 raw |= string.byte(byte);
774 continue;
775 }
776 match byte {
777 b'"' => {
778 string = JsonStringScan {
779 active: true,
780 possible: true,
781 ..JsonStringScan::default()
782 }
783 }
784 b'[' | b'{' => {
785 depth += 1;
786 maximum = maximum.max(depth);
787 }
788 b']' | b'}' if depth != 0 => depth -= 1,
789 _ => {}
790 }
791 }
792 values = values
793 .checked_add(1)
794 .ok_or_else(|| self.tree_overflow(operation))?;
795 let levels = if raw {
796 maximum = openings
797 .checked_add(escapes)
798 .ok_or_else(|| self.tree_overflow(operation))?;
799 values = values
800 .checked_add(escapes)
801 .ok_or_else(|| self.tree_overflow(operation))?;
802 entries = entries
803 .checked_add(escapes)
804 .ok_or_else(|| self.tree_overflow(operation))?;
805 maximum
806 .checked_add(1)
807 .ok_or_else(|| self.tree_overflow(operation))?
808 } else {
809 1
810 };
811 let bytes = (|| {
812 values
813 .checked_mul(6)?
814 .checked_mul(u64_from_index(std::mem::size_of::<serde_json::Value>()))?
815 .checked_add(entries.checked_mul(JSON_MAP_ENTRY_BOUND)?)?
816 .checked_add(length.checked_mul(8)?.checked_mul(levels)?)?
817 .checked_add(1024)
818 })()
819 .ok_or_else(|| self.tree_overflow(operation))?;
820 Ok(JsonBound {
821 values,
822 entries,
823 depth: maximum,
824 bytes,
825 })
826 }
827
828 fn parse_json_tree(
829 &self,
830 text: &str,
831 operation: &'static str,
832 interpret_raw: bool,
833 ) -> Result<(serde_json::Value, ScopedReservation<'_>, JsonBound), CodecError> {
834 let bound = self.json_bound(text, operation)?;
835 self.charge_collection_items(bound.values, operation)?;
836 let work = u64_from_index(text.len())
837 .checked_mul(
838 bound
839 .entries
840 .checked_add(1)
841 .ok_or_else(|| self.tree_overflow(operation))?,
842 )
843 .and_then(|n| n.checked_mul(bound.depth.checked_add(1)?))
844 .ok_or_else(|| self.tree_overflow(operation))?;
845 self.charge_work(work, operation)?;
846 let reservation = self.reserve_scoped(bound.bytes, operation)?;
847 let value = at_depth(self, bound.depth, operation, || {
848 if interpret_raw {
849 serde_json::from_str(text).map_err(|error| self.tree_malformed(error, operation))
850 } else {
851 use serde::de::DeserializeSeed;
852 let mut parser = serde_json::Deserializer::from_str(text);
853 PlainJson
854 .deserialize(&mut parser)
855 .and_then(|value| {
856 parser.end()?;
857 Ok(value)
858 })
859 .map_err(|error| self.tree_malformed(error, operation))
860 }
861 })?;
862 Ok((value, reservation, bound))
863 }
864
865 pub fn parse_json_value(
869 &self,
870 text: &str,
871 operation: &'static str,
872 ) -> Result<(serde_json::Value, ScopedReservation<'_>), CodecError> {
873 let (value, reservation, _) = self.parse_json_tree(text, operation, true)?;
874 Ok((value, reservation))
875 }
876
877 pub fn parse_json<T: serde::de::DeserializeOwned>(
887 &self,
888 text: &str,
889 operation: &'static str,
890 ) -> Result<T, CodecError> {
891 let (_reservation, value, bound) = {
892 let (value, reservation, bound) = self.parse_json_tree(text, operation, false)?;
893 (reservation, value, bound)
894 };
895 let retained = bound
896 .bytes
897 .checked_mul(2)
898 .and_then(|n| n.checked_add(u64_from_index(std::mem::size_of::<T>())))
899 .ok_or_else(|| self.tree_overflow(operation))?;
900 let validation_work = u64_from_index(text.len())
901 .checked_mul(bound.values)
902 .and_then(|n| n.checked_mul(bound.depth.checked_add(1)?))
903 .ok_or_else(|| self.tree_overflow(operation))?;
904 self.charge_work(validation_work, operation)?;
905 self.charge_collection_items(bound.values, operation)?;
906 {
907 let _validation = self.reserve_scoped(retained, operation)?;
908 at_depth(self, bound.depth, operation, || {
909 let validated: T = serde_json::from_str(text)
910 .map_err(|error| self.tree_malformed(error, operation))?;
911 drop(validated);
912 Ok(())
913 })?;
914 }
915 self.charge_retained(retained, operation)?;
916 self.charge_collection_items(bound.values, operation)?;
917 self.charge_work(bound.values, operation)?;
918 at_depth(self, bound.depth, operation, || {
919 serde_json::from_value(value).map_err(|error| self.tree_malformed(error, operation))
920 })
921 }
922}
923
924#[cfg(test)]
925mod tests {
926 use super::ATTRIBUTE_RECORD_BOUND;
927 use crate::decode::{
928 u64_from_index, DecodeArena, DecodeContext, DecodePolicy, ResourceDimension,
929 };
930 use crate::CodecError;
931
932 #[test]
933 fn tree_xml_success_and_capacity_rounding() {
934 let arena = DecodeArena::new();
935 let (ctx, _) = DecodeContext::from_root_bytes(b"", &arena, &DecodePolicy::default())
936 .expect("valid fixture");
937 let tree = ctx.parse_xml("<r/>", "XML tree").expect("valid fixture");
938 assert_eq!(tree.document().root_element().tag_name().name(), "r");
939 let mut policy = DecodePolicy::default();
940 policy.limits.max_materialized_bytes = 0;
941 let (limited, _) =
942 DecodeContext::from_root_bytes(b"", &arena, &policy).expect("valid fixture");
943 let CodecError::ResourceLimit(limit) = limited
944 .parse_xml("<r/>", "XML tree")
945 .expect_err("fixture must refuse")
946 else {
947 panic!("byte refusal");
948 };
949 assert!(limit.additional >= 16 * ATTRIBUTE_RECORD_BOUND);
950 }
951
952 #[test]
953 fn tree_xml_work_compares_attributes_within_each_tag() {
954 let text = format!("<r>{}</r>", "<a x='0'/>".repeat(16));
955 let arena = DecodeArena::new();
956 let mut policy = DecodePolicy::default();
957 policy.limits.max_work_units = 32 * u64_from_index(text.len());
958 let (ctx, _) = DecodeContext::from_root_bytes(b"", &arena, &policy).expect("valid fixture");
959 let tree = ctx.parse_xml(&text, "XML tree").expect("valid fixture");
960 assert_eq!(tree.document().root_element().children().count(), 16);
961 }
962
963 #[test]
964 fn tree_xml_large_text_does_not_pay_attribute_comparison_work() {
965 let mut text = String::from("<r");
966 for index in 0..64 {
967 std::fmt::Write::write_fmt(&mut text, format_args!(" a{index}='0'"))
968 .expect("fixture string");
969 }
970 text.push('>');
971 text.push_str(&"ordinary text ".repeat(16_000));
972 text.push_str("</r>");
973 let arena = DecodeArena::new();
974 let mut policy = DecodePolicy::service();
975 policy.limits.max_work_units = 8 * u64_from_index(text.len());
976 let (ctx, _) = DecodeContext::from_root_bytes(&[], &arena, &policy).expect("empty input");
977 let tree = ctx
978 .parse_xml(&text, "local XML comparisons")
979 .expect("text scanning is linear");
980 assert_eq!(tree.document().root_element().attributes().len(), 64);
981 drop(tree);
982 ctx.finish_session().expect("unfused session");
983 }
984
985 #[test]
986 fn tree_xml_large_attribute_values_do_not_pay_key_comparison_work() {
987 let value = "value text ".repeat(16_000);
988 let mut text = String::from("<r xmlns:p='urn:shared'");
989 for index in 0..64 {
990 std::fmt::Write::write_fmt(&mut text, format_args!(" a{index}='0'"))
991 .expect("fixture string");
992 }
993 std::fmt::Write::write_fmt(&mut text, format_args!(" data='{value}'/>"))
994 .expect("fixture string");
995 let arena = DecodeArena::new();
996 let mut policy = DecodePolicy::service();
997 policy.limits.max_work_units = 8 * u64_from_index(text.len());
998 let (ctx, _) = DecodeContext::from_root_bytes(&[], &arena, &policy).expect("empty input");
999 let tree = ctx
1000 .parse_xml(&text, "XML attribute value scanning")
1001 .expect("values are not comparison keys");
1002 assert_eq!(tree.document().root_element().attributes().len(), 65);
1003 assert_eq!(
1004 tree.document().root_element().attribute("data"),
1005 Some(value.as_str())
1006 );
1007 drop(tree);
1008 ctx.finish_session().expect("unfused session");
1009 }
1010
1011 #[test]
1012 fn tree_xml_namespace_comparisons_are_separate_from_text() {
1013 let text = format!(
1014 "<r xmlns:p='urn:shared' xmlns:q='urn:shared'><s p:a='1' q:b='2'>{}</s></r>",
1015 "text ".repeat(8_000)
1016 );
1017 let arena = DecodeArena::new();
1018 let mut policy = DecodePolicy::service();
1019 policy.limits.max_work_units = 8 * u64_from_index(text.len());
1020 let (ctx, _) = DecodeContext::from_root_bytes(&[], &arena, &policy).expect("empty input");
1021 let tree = ctx
1022 .parse_xml(&text, "namespace XML comparisons")
1023 .expect("local namespaces");
1024 let child = tree
1025 .document()
1026 .root_element()
1027 .first_element_child()
1028 .expect("s element");
1029 assert_eq!(child.attribute(("urn:shared", "a")), Some("1"));
1030 assert_eq!(child.attribute(("urn:shared", "b")), Some("2"));
1031 drop(tree);
1032 ctx.finish_session().expect("unfused session");
1033 }
1034
1035 #[test]
1036 fn tree_xml_repeated_sibling_namespaces_use_local_uri_bounds() {
1037 let text = format!(
1038 "<r><a xmlns:p='{}'/>{}</r>",
1039 "u".repeat(8_192),
1040 "<b xmlns:p='urn:small'><p:t p:x='1' p:y='2'/></b>".repeat(128)
1041 );
1042 let arena = DecodeArena::new();
1043 let mut policy = DecodePolicy::service();
1044 policy.limits.max_work_units = 32 * u64_from_index(text.len());
1045 let (ctx, _) = DecodeContext::from_root_bytes(&[], &arena, &policy).expect("empty input");
1046 let tree = ctx
1047 .parse_xml(&text, "scoped XML namespaces")
1048 .expect("sibling namespace work is local");
1049 assert_eq!(
1050 tree.document()
1051 .root_element()
1052 .children()
1053 .filter(roxmltree::Node::is_element)
1054 .count(),
1055 129
1056 );
1057 let last = tree
1058 .document()
1059 .root_element()
1060 .last_element_child()
1061 .expect("b element");
1062 let child = last.first_element_child().expect("p:t element");
1063 assert_eq!(child.attribute(("urn:small", "x")), Some("1"));
1064 drop(tree);
1065 ctx.finish_session().expect("unfused session");
1066 }
1067
1068 #[test]
1069 fn tree_xml_sibling_namespace_storage_is_linear_in_declarations() {
1070 let text = format!(
1071 "<r>{}</r>",
1072 "<b xmlns:p='urn:shared'><p:t p:x='1'/></b>".repeat(5_000)
1073 );
1074 let arena = DecodeArena::new();
1075 let mut policy = DecodePolicy::service();
1076 policy.limits.max_collection_items = 200_000;
1077 policy.limits.max_materialized_bytes = 32 * 1024 * 1024;
1078 policy.limits.max_work_units = 16 * u64_from_index(text.len());
1079 let (ctx, _) =
1080 DecodeContext::from_root_bytes(text.as_bytes(), &arena, &policy).expect("XML root");
1081 let tree = ctx
1082 .parse_xml(&text, "linear XML namespace storage")
1083 .expect("sibling namespace ranges fit the collection and storage limits");
1084 assert_eq!(
1085 tree.document()
1086 .root_element()
1087 .children()
1088 .filter(roxmltree::Node::is_element)
1089 .count(),
1090 5_000
1091 );
1092 let last = tree
1093 .document()
1094 .root_element()
1095 .last_element_child()
1096 .expect("b element");
1097 assert_eq!(
1098 last.first_element_child()
1099 .expect("p:t element")
1100 .attribute(("urn:shared", "x")),
1101 Some("1")
1102 );
1103 drop(tree);
1104 drop(
1105 ctx.reserve_scoped(policy.limits.max_materialized_bytes, "XML storage released")
1106 .expect("all temporary storage released"),
1107 );
1108 ctx.finish_session().expect("unfused session");
1109 }
1110
1111 #[test]
1112 fn tree_xml_shadowed_namespace_bounds_restore_at_element_depth() {
1113 let text = format!(
1114 "<r xmlns:p='urn:root'>{}{}<p:last p:x='1'/></r>",
1115 "<a xmlns:p='u'>".repeat(16),
1116 "</a>".repeat(16)
1117 );
1118 let arena = DecodeArena::new();
1119 let mut policy = DecodePolicy::service();
1120 policy.limits.max_materialized_bytes = 65_536;
1121 policy.limits.max_work_units = 64 * u64_from_index(text.len());
1122 let (ctx, _) = DecodeContext::from_root_bytes(&[], &arena, &policy).expect("empty input");
1123 let tree = ctx
1124 .parse_xml(&text, "shadowed XML namespaces")
1125 .expect("shadowing keeps a local namespace count");
1126 let last = tree
1127 .document()
1128 .root_element()
1129 .last_element_child()
1130 .expect("p:last element");
1131 assert_eq!(last.tag_name().namespace(), Some("urn:root"));
1132 assert_eq!(last.attribute(("urn:root", "x")), Some("1"));
1133 drop(tree);
1134 drop(
1135 ctx.reserve_scoped(policy.limits.max_materialized_bytes, "XML storage released")
1136 .expect("all temporary storage released"),
1137 );
1138 ctx.finish_session().expect("unfused session");
1139 }
1140
1141 #[test]
1142 fn tree_xml_unterminated_tag_keeps_attribute_work_bound() {
1143 let mut attributes = String::new();
1144 for index in 0..16 {
1145 std::fmt::Write::write_fmt(&mut attributes, format_args!(" x{index}='0'"))
1146 .expect("fixture string write");
1147 }
1148 let text = format!("<r{attributes}");
1149 let arena = DecodeArena::new();
1150 let (ctx, _) = DecodeContext::from_root_bytes(&[], &arena, &DecodePolicy::service())
1151 .expect("empty input");
1152 let bound = super::xml_bound(&text, &ctx, "XML bound").expect("finite bound");
1153 let name_bytes = (0..16)
1154 .map(|index| format!("x{index}").len())
1155 .sum::<usize>();
1156 assert!(
1157 bound.local_comparisons.expect("finite bound")
1158 >= 17 * (u64_from_index(name_bytes) + 16)
1159 );
1160 }
1161
1162 #[test]
1163 fn tree_xml_resource_dimensions() {
1164 for dimension in [
1165 ResourceDimension::CollectionItems,
1166 ResourceDimension::MaterializedBytes,
1167 ResourceDimension::WorkUnits,
1168 ResourceDimension::RecursionDepth,
1169 ] {
1170 let mut policy = DecodePolicy::default();
1171 match dimension {
1172 ResourceDimension::CollectionItems => policy.limits.max_collection_items = 0,
1173 ResourceDimension::MaterializedBytes => policy.limits.max_materialized_bytes = 0,
1174 ResourceDimension::WorkUnits => policy.limits.max_work_units = 0,
1175 ResourceDimension::RecursionDepth => policy.limits.max_recursion_depth = 0,
1176 _ => panic!("test dimension"),
1177 }
1178 let arena = DecodeArena::new();
1179 let (ctx, _) =
1180 DecodeContext::from_root_bytes(b"", &arena, &policy).expect("valid fixture");
1181 let CodecError::ResourceLimit(limit) = ctx
1182 .parse_xml("<r/>", "XML tree")
1183 .expect_err("fixture must refuse")
1184 else {
1185 panic!("resource refusal");
1186 };
1187 assert_eq!(limit.dimension, dimension);
1188 assert_eq!(ctx.resource_refusal(), Some(limit));
1189 }
1190 }
1191
1192 #[test]
1193 fn tree_xml_malformed_and_lexical_depth() {
1194 let arena = DecodeArena::new();
1195 let mut policy = DecodePolicy::default();
1196 policy.limits.max_recursion_depth = 1;
1197 let (ctx, _) = DecodeContext::from_root_bytes(b"", &arena, &policy).expect("valid fixture");
1198 assert!(matches!(
1199 ctx.parse_xml("<r>", "XML tree"),
1200 Err(CodecError::Malformed(_))
1201 ));
1202 assert!(ctx.resource_refusal().is_none());
1203 ctx.parse_xml(
1204 "<r a='>'><!-- <a> --><![CDATA[<b>]]><?pi <c> ?></r>",
1205 "XML tree",
1206 )
1207 .expect("valid fixture");
1208 assert!(
1209 matches!(ctx.parse_xml("<r><s/></r>", "XML tree"), Err(CodecError::ResourceLimit(limit)) if limit.dimension == ResourceDimension::RecursionDepth)
1210 );
1211 }
1212 #[test]
1213 fn tree_malformed_diagnostic_preserves_retained_refusal() {
1214 for json in [false, true] {
1215 let arena = DecodeArena::new();
1216 let mut policy = DecodePolicy::default();
1217 policy.limits.max_retained_bytes = 0;
1218 let (ctx, _) =
1219 DecodeContext::from_root_bytes(b"", &arena, &policy).expect("valid fixture");
1220 let error = if json {
1221 ctx.parse_json_value("[", "JSON tree")
1222 .expect_err("fixture must refuse")
1223 } else {
1224 ctx.parse_xml("<r>", "XML tree")
1225 .expect_err("fixture must refuse")
1226 };
1227 let CodecError::ResourceLimit(limit) = error else {
1228 panic!("diagnostic admission must refuse");
1229 };
1230 assert_eq!(limit.dimension, ResourceDimension::RetainedBytes);
1231 assert_eq!(ctx.resource_refusal(), Some(limit));
1232 }
1233 }
1234
1235 #[test]
1236 fn invalid_json_prefix_preserves_collection_refusal() {
1237 let mut policy = DecodePolicy::service();
1238 policy.limits.max_collection_items = 2;
1239 let arena = DecodeArena::new();
1240 let (ctx, _) = DecodeContext::from_root_bytes(b"", &arena, &policy).expect("valid fixture");
1241 let error = ctx
1242 .parse_json_value("[0,0,0,", "JSON nodes")
1243 .expect_err("fixture must refuse");
1244 let CodecError::ResourceLimit(limit) = error else {
1245 panic!("invalid prefix must preserve its admission refusal");
1246 };
1247 assert_eq!(limit.operation, "JSON nodes");
1248 assert_eq!(Some(limit), ctx.resource_refusal());
1249 }
1250
1251 #[derive(Debug, serde::Deserialize, PartialEq)]
1252 struct JsonRecord {
1253 name: String,
1254 values: Vec<u64>,
1255 }
1256
1257 #[test]
1258 fn tree_json_value_success_and_capacity_rounding() {
1259 let arena = DecodeArena::new();
1260 let (ctx, _) = DecodeContext::from_root_bytes(b"", &arena, &DecodePolicy::default())
1261 .expect("valid fixture");
1262 for text in ["[0]", "{}", "0", "\"a\""] {
1263 let (value, _scope) = ctx
1264 .parse_json_value(text, "JSON tree")
1265 .expect("valid fixture");
1266 assert_eq!(
1267 value,
1268 serde_json::from_str::<serde_json::Value>(text).expect("valid fixture")
1269 );
1270 let bound = ctx.json_bound(text, "JSON bound").expect("valid fixture");
1271 assert!(
1272 bound.bytes >= 4 * u64_from_index(std::mem::size_of::<serde_json::Value>()) + 1024
1273 );
1274 }
1275 }
1276
1277 #[test]
1278 fn tree_json_typed_success() {
1279 let ctx = crate::decode::DecodeArena::new();
1280 let (ctx, _) = DecodeContext::from_root_bytes(b"", &ctx, &DecodePolicy::default())
1281 .expect("valid fixture");
1282 let record: JsonRecord = ctx
1283 .parse_json(r#"{"name":"r","values":[0]}"#, "typed JSON tree")
1284 .expect("valid fixture");
1285 assert_eq!(
1286 record,
1287 JsonRecord {
1288 name: "r".into(),
1289 values: vec![0]
1290 }
1291 );
1292 }
1293
1294 #[test]
1295 fn tree_json_resource_dimensions() {
1296 for typed in [false, true] {
1297 for dimension in [
1298 ResourceDimension::CollectionItems,
1299 ResourceDimension::MaterializedBytes,
1300 ResourceDimension::WorkUnits,
1301 ResourceDimension::RecursionDepth,
1302 ResourceDimension::RetainedBytes,
1303 ] {
1304 if !typed && dimension == ResourceDimension::RetainedBytes {
1305 continue;
1306 }
1307 let mut policy = DecodePolicy::default();
1308 match dimension {
1309 ResourceDimension::CollectionItems => policy.limits.max_collection_items = 0,
1310 ResourceDimension::MaterializedBytes => {
1311 policy.limits.max_materialized_bytes = 0;
1312 }
1313 ResourceDimension::WorkUnits => policy.limits.max_work_units = 0,
1314 ResourceDimension::RecursionDepth => policy.limits.max_recursion_depth = 0,
1315 ResourceDimension::RetainedBytes => policy.limits.max_retained_bytes = 0,
1316 _ => panic!("test dimension"),
1317 }
1318 let arena = DecodeArena::new();
1319 let (ctx, _) =
1320 DecodeContext::from_root_bytes(b"", &arena, &policy).expect("valid fixture");
1321 let error = if typed {
1322 ctx.parse_json::<Vec<u64>>("[0]", "typed JSON tree")
1323 .expect_err("fixture must refuse")
1324 } else {
1325 ctx.parse_json_value("[0]", "JSON tree")
1326 .expect_err("fixture must refuse")
1327 };
1328 let CodecError::ResourceLimit(limit) = error else {
1329 panic!("resource refusal");
1330 };
1331 assert_eq!(limit.dimension, dimension);
1332 assert_eq!(ctx.resource_refusal(), Some(limit));
1333 }
1334 }
1335 }
1336
1337 #[test]
1338 fn tree_json_malformed_preserves_parse_route() {
1339 let arena = DecodeArena::new();
1340 let (ctx, _) = DecodeContext::from_root_bytes(b"", &arena, &DecodePolicy::default())
1341 .expect("valid fixture");
1342 assert!(matches!(
1343 ctx.parse_json_value("[", "JSON tree"),
1344 Err(CodecError::Malformed(_))
1345 ));
1346 assert!(matches!(
1347 ctx.parse_json::<JsonRecord>("[", "typed JSON tree"),
1348 Err(CodecError::Malformed(_))
1349 ));
1350 assert!(matches!(
1351 ctx.parse_json::<JsonRecord>("{}", "typed JSON tree"),
1352 Err(CodecError::Malformed(_))
1353 ));
1354 assert!(ctx.resource_refusal().is_none());
1355 }
1356
1357 #[test]
1358 fn tree_json_typed_preserves_ignored_raw_carrier_extensions() {
1359 let arena = DecodeArena::new();
1360 let (ctx, _) = DecodeContext::from_root_bytes(b"", &arena, &DecodePolicy::default())
1361 .expect("valid fixture");
1362 let text =
1363 r#"{"name":"r","values":[],"extension":{"$serde_json::private::RawValue":"not-json"}}"#;
1364 let record: JsonRecord = ctx
1365 .parse_json(text, "typed JSON tree")
1366 .expect("valid fixture");
1367 assert_eq!(
1368 record,
1369 JsonRecord {
1370 name: "r".into(),
1371 values: Vec::new()
1372 }
1373 );
1374 }
1375
1376 #[test]
1377 fn tree_json_typed_preserves_duplicate_field_errors() {
1378 let arena = DecodeArena::new();
1379 let (ctx, _) = DecodeContext::from_root_bytes(b"", &arena, &DecodePolicy::default())
1380 .expect("valid fixture");
1381 let text = r#"{"name":"a","name":"b","values":[]}"#;
1382 assert!(matches!(
1383 ctx.parse_json::<JsonRecord>(text, "typed JSON tree"),
1384 Err(CodecError::Malformed(_))
1385 ));
1386 assert!(ctx.resource_refusal().is_none());
1387 let (value, _scope) = ctx
1388 .parse_json_value(text, "JSON tree")
1389 .expect("valid fixture");
1390 assert_eq!(value["name"], "b");
1391 }
1392
1393 #[test]
1394 fn tree_json_lexical_and_raw_carrier_depth() {
1395 let arena = DecodeArena::new();
1396 let mut policy = DecodePolicy::default();
1397 policy.limits.max_recursion_depth = 1;
1398 let (ctx, _) = DecodeContext::from_root_bytes(b"", &arena, &policy).expect("valid fixture");
1399 ctx.parse_json_value(r#"["[[["]"#, "JSON tree")
1400 .expect("valid fixture");
1401 let text = r#"{"$serde_json::private::RawValue":"\u005b0\u005d"}"#;
1402 assert!(
1403 matches!(ctx.parse_json_value(text, "JSON tree"), Err(CodecError::ResourceLimit(limit)) if limit.dimension == ResourceDimension::RecursionDepth)
1404 );
1405 let (ctx, _) = DecodeContext::from_root_bytes(b"", &arena, &DecodePolicy::default())
1406 .expect("valid fixture");
1407 let (value, _scope) = ctx
1408 .parse_json_value(text, "JSON tree")
1409 .expect("valid fixture");
1410 assert_eq!(value, serde_json::json!([0]));
1411 let escaped_key = r#"{"\u0024serde_json::private::RawValue":"[0]"}"#;
1412 let bound = ctx
1413 .json_bound(escaped_key, "JSON bound")
1414 .expect("valid fixture");
1415 assert!(bound.depth >= 2);
1416 }
1417}