cbor_core/strictness.rs
1//! Per-decode policy for accepting non-deterministic CBOR encodings.
2//!
3//! See [`Strictness`].
4
5/// Policy for accepting non-deterministic CBOR encodings during a decode.
6///
7/// CBOR::Core requires every value to be encoded in a single canonical
8/// form. The default decoder enforces that and rejects any deviation
9/// with [`Error::NonDeterministic`](crate::Error::NonDeterministic).
10/// Some producers (legacy encoders, bridges from other formats, hand
11/// written test vectors) emit valid CBOR that violates one or more of
12/// these rules. `Strictness` selects which violations the decoder
13/// tolerates so that such input can still be read.
14///
15/// Each tolerated violation is normalized while decoding: the resulting
16/// [`Value`](crate::Value) is the same value the canonical encoder
17/// would produce, and re-encoding it always yields a CBOR::Core
18/// compliant byte sequence. The original wire bytes are not preserved.
19///
20/// The default, [`Strictness::STRICT`], matches the CBOR::Core draft
21/// exactly. [`Strictness::LENIENT`] accepts every supported deviation.
22/// Set individual fields for a custom mix.
23///
24/// # Examples
25///
26/// ```
27/// use cbor_core::{DecodeOptions, Strictness, Value};
28///
29/// // 255 wrongly encoded with a two byte argument (canonical: 0x18 0xff).
30/// let bytes = [0x19, 0x00, 0xff];
31///
32/// // Default: rejected.
33/// assert!(DecodeOptions::new().decode(&bytes).is_err());
34///
35/// // Lenient: accepted and normalized.
36/// let v = DecodeOptions::new()
37/// .strictness(Strictness::LENIENT)
38/// .decode(&bytes)
39/// .unwrap();
40/// assert_eq!(v, Value::from(255));
41/// assert_eq!(v.encode(), vec![0x18, 0xff]);
42/// ```
43#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
44pub struct Strictness {
45 /// Accept integers, lengths, and tag numbers encoded in a wider
46 /// argument than necessary (for example `0x19 0x00 0xff` for the
47 /// value 255 instead of `0x18 0xff`).
48 pub allow_non_shortest_integers: bool,
49
50 /// Accept floating point values encoded in a wider form than
51 /// necessary (for example an f32 that fits exactly in f16). The
52 /// decoded [`Float`](crate::Float) is re-stored in the shortest
53 /// form that preserves the value bit for bit, including NaN
54 /// payloads.
55 pub allow_non_shortest_floats: bool,
56
57 /// Accept big integer tags (tag 2 / tag 3) whose payload has
58 /// leading zero bytes or fits into a `u64`. Leading zeros are
59 /// stripped; a value that fits is downcast to
60 /// [`Value::Unsigned`](crate::Value::Unsigned) or
61 /// [`Value::Negative`](crate::Value::Negative).
62 pub allow_oversized_bigints: bool,
63
64 /// Accept maps whose keys are not in CBOR canonical (length and
65 /// then bytewise) order. Keys are sorted by [`Value`](crate::Value)
66 /// after decoding, which is equivalent to canonical order once each
67 /// value has been re-encoded in shortest form. With
68 /// [`allow_non_shortest_integers`](Self::allow_non_shortest_integers)
69 /// off, the two orders coincide; with it on, the by-value order is
70 /// the only well-defined choice because the original byte lengths
71 /// are normalized away.
72 pub allow_unsorted_map_keys: bool,
73
74 /// Accept maps that contain the same key more than once. The last
75 /// occurrence wins, matching
76 /// [`Map::from_pairs`](crate::Map::from_pairs).
77 pub allow_duplicate_map_keys: bool,
78
79 /// Accept indefinite-length encodings (RFC 8949 §3.2.2) for byte
80 /// strings, text strings, arrays, and maps. The chunks of an
81 /// indefinite-length string are concatenated; an indefinite-length
82 /// array or map is read until the break code. The resulting
83 /// [`Value`](crate::Value) is the same that a definite-length
84 /// encoding would produce, so re-encoding emits canonical bytes.
85 ///
86 /// In [`Format::Diagnostic`](crate::Format::Diagnostic) input, the
87 /// flag also enables the matching RFC 8949 §8 spellings:
88 /// `[_ ...]`, `{_ ...}`, and `(_ chunk, ...)`.
89 pub allow_indefinite_length: bool,
90}
91
92impl Strictness {
93 /// Reject every form of non-deterministic encoding. Default for
94 /// [`DecodeOptions`](crate::DecodeOptions).
95 pub const STRICT: Self = Self {
96 allow_non_shortest_integers: false,
97 allow_non_shortest_floats: false,
98 allow_oversized_bigints: false,
99 allow_unsorted_map_keys: false,
100 allow_duplicate_map_keys: false,
101 allow_indefinite_length: false,
102 };
103
104 /// Accept every non-deterministic encoding the decoder knows how to
105 /// normalize. The resulting [`Value`](crate::Value) is canonical;
106 /// re-encoding it produces CBOR::Core compliant bytes.
107 pub const LENIENT: Self = Self {
108 allow_non_shortest_integers: true,
109 allow_non_shortest_floats: true,
110 allow_oversized_bigints: true,
111 allow_unsorted_map_keys: true,
112 allow_duplicate_map_keys: true,
113 allow_indefinite_length: true,
114 };
115}
116
117impl Default for Strictness {
118 fn default() -> Self {
119 Self::STRICT
120 }
121}