pub struct DecodeOptions { /* private fields */ }Expand description
Configuration for CBOR decoding.
DecodeOptions controls the input format (Binary,
Hex, or Diagnostic) and the
limits the decoder enforces against hostile or malformed input.
Construct it with DecodeOptions::new (or Default), adjust
settings with the builder methods, and call decode
or read_from for a single item, or
sequence_decoder / sequence_reader
for a CBOR sequence.
The convenience methods on Value (decode,
decode_hex, read_from,
read_hex_from) all forward to a default
DecodeOptions. Use this type directly when you need to decode
diagnostic notation, iterate a sequence, relax a limit for a known
input, or tighten one for untrusted input.
§Options
| Option | Default | Purpose |
|---|---|---|
format | Binary | Input syntax: binary, hex text, or diagnostic notation. |
recursion_limit | 200 | Maximum nesting depth of arrays, maps, and tags. |
length_limit | 1,000,000,000 | Maximum declared element count of a single array, map, byte string, or text string. |
oom_mitigation | 100,000,000 | Byte budget for speculative pre-allocation. |
§recursion_limit
Each array, map, or tag consumes one unit of recursion budget for
its contents. Exceeding the limit returns Error::NestingTooDeep.
The limit protects against stack overflow on adversarial input and
should be well below the stack a thread has available.
§length_limit
Applies to the length field in the CBOR head of arrays, maps, byte
strings, and text strings. It caps the declared size before any
bytes are read, so a malicious header claiming a petabyte-long
string is rejected immediately with Error::LengthTooLarge. The
limit does not restrict total input size; a valid document may
contain many items each up to the limit.
§oom_mitigation
CBOR encodes lengths in the head, so a decoder is tempted to
pre-allocate a Vec of the declared capacity. On hostile input
that is a trivial amplification attack: a few bytes on the wire
reserve gigabytes of memory. oom_mitigation is a byte budget,
shared across the current decode, that caps the total amount of
speculative capacity the decoder may reserve for array backing
storage. Once the budget is exhausted, further arrays start empty
and grow on demand. Decoding still succeeds if the input is
well-formed; only the up-front reservation is bounded.
The budget is consumed, not refilled: a deeply nested structure with many small arrays can drain it early and decode the tail with zero pre-allocation. That is the intended behavior.
§Examples
Decode binary CBOR with default limits:
use cbor_core::DecodeOptions;
let v = DecodeOptions::new().decode([0x18, 42]).unwrap();
assert_eq!(v.to_u32().unwrap(), 42);Switch the input format to hex text or diagnostic notation:
use cbor_core::{DecodeOptions, Format};
let v = DecodeOptions::new().format(Format::Hex).decode("182a").unwrap();
assert_eq!(v.to_u32().unwrap(), 42);
let v = DecodeOptions::new().format(Format::Diagnostic).decode("42").unwrap();
assert_eq!(v.to_u32().unwrap(), 42);Tighten limits for input from an untrusted source:
use cbor_core::DecodeOptions;
let strict = DecodeOptions::new()
.recursion_limit(16)
.length_limit(4096)
.oom_mitigation(64 * 1024);
assert!(strict.decode([0x18, 42]).is_ok());Implementations§
Source§impl DecodeOptions
impl DecodeOptions
Sourcepub const fn new() -> Self
pub const fn new() -> Self
Create a new set of options with the crate defaults.
use cbor_core::DecodeOptions;
let opts = DecodeOptions::new();
let v = opts.decode([0x18, 42]).unwrap();
assert_eq!(v.to_u32().unwrap(), 42);Sourcepub const fn format(self, format: Format) -> Self
pub const fn format(self, format: Format) -> Self
Select the input format: Binary,
Hex, or Diagnostic.
Default: Format::Binary.
use cbor_core::{DecodeOptions, Format};
let hex = DecodeOptions::new().format(Format::Hex).decode("182a").unwrap();
let bin = DecodeOptions::new().decode([0x18, 0x2a]).unwrap();
assert_eq!(hex, bin);
let v = DecodeOptions::new().format(Format::Diagnostic).decode("42").unwrap();
assert_eq!(v.to_u32().unwrap(), 42);Sourcepub const fn recursion_limit(self, limit: u16) -> Self
pub const fn recursion_limit(self, limit: u16) -> Self
Set the maximum nesting depth of arrays, maps, and tags.
Default: 200. Input that exceeds the limit returns
Error::NestingTooDeep.
use cbor_core::{DecodeOptions, Error};
// Two nested one-element arrays: 0x81 0x81 0x00
let err = DecodeOptions::new()
.recursion_limit(1)
.decode([0x81, 0x81, 0x00])
.unwrap_err();
assert_eq!(err, Error::NestingTooDeep);Sourcepub const fn length_limit(self, limit: u64) -> Self
pub const fn length_limit(self, limit: u64) -> Self
Set the maximum declared length for byte strings, text strings, arrays, and maps.
Default: 1,000,000,000. Checked against the length field in the
CBOR head before any bytes are consumed; an oversized declaration
returns Error::LengthTooLarge.
use cbor_core::{DecodeOptions, Error};
// A five-byte text string: 0x65 'h' 'e' 'l' 'l' 'o'
let err = DecodeOptions::new()
.length_limit(4)
.decode(b"\x65hello")
.unwrap_err();
assert_eq!(err, Error::LengthTooLarge);Sourcepub const fn oom_mitigation(self, bytes: usize) -> Self
pub const fn oom_mitigation(self, bytes: usize) -> Self
Set the byte budget for speculative pre-allocation of array backing storage.
Default: 100,000,000. Lower values trade a small amount of decoding throughput for stronger resistance to memory-amplification attacks. Valid input decodes regardless; only the up-front reservation is bounded.
use cbor_core::DecodeOptions;
// A two-element array: 0x82 0x01 0x02
let v = DecodeOptions::new()
.oom_mitigation(0)
.decode([0x82, 0x01, 0x02])
.unwrap();
assert_eq!(v.len(), Some(2));Sourcepub fn decode(&self, bytes: impl AsRef<[u8]>) -> Result<Value>
pub fn decode(&self, bytes: impl AsRef<[u8]>) -> Result<Value>
Decode exactly one CBOR data item from an in-memory buffer.
Accepts any AsRef<[u8]>: &[u8], Vec<u8>, &str, String,
and so on. The input must contain exactly one value: any
bytes remaining after a successful decode cause
Error::InvalidFormat. In Format::Diagnostic mode
trailing whitespace and comments are accepted, but nothing
else. Use sequence_decoder when the input is a CBOR
sequence.
An empty buffer (and, for diagnostic notation, one containing
only whitespace and comments) returns Error::UnexpectedEof.
A partial value returns Error::UnexpectedEof too.
use cbor_core::{DecodeOptions, Format};
let v = DecodeOptions::new().decode([0x18, 42]).unwrap();
assert_eq!(v.to_u32().unwrap(), 42);
let v = DecodeOptions::new().format(Format::Hex).decode("182a").unwrap();
assert_eq!(v.to_u32().unwrap(), 42);
let v = DecodeOptions::new()
.format(Format::Diagnostic)
.decode("42 / trailing comment is fine /")
.unwrap();
assert_eq!(v.to_u32().unwrap(), 42);Sourcepub fn read_from(&self, reader: impl Read) -> IoResult<Value>
pub fn read_from(&self, reader: impl Read) -> IoResult<Value>
Read a single CBOR data item from a stream.
Designed to be called repeatedly to pull successive elements of a CBOR sequence:
- In
Format::BinaryandFormat::Hexthe reader is consumed only up to the end of the item; any bytes after remain in the stream. - In
Format::Diagnostictrailing whitespace and comments are consumed up to either end of stream or a top-level separator comma (the comma is also consumed). Anything else after the value fails withError::InvalidFormat.
I/O failures are returned as IoError::Io;
malformed or oversized input as IoError::Data.
use cbor_core::{DecodeOptions, Format};
let mut bytes: &[u8] = &[0x18, 42];
let v = DecodeOptions::new().read_from(&mut bytes).unwrap();
assert_eq!(v.to_u32().unwrap(), 42);
let mut hex: &[u8] = b"182a";
let v = DecodeOptions::new().format(Format::Hex).read_from(&mut hex).unwrap();
assert_eq!(v.to_u32().unwrap(), 42);
// Diagnostic: repeated read_from pulls successive sequence items.
let mut diag: &[u8] = b"1, 2, 3";
let opts = DecodeOptions::new().format(Format::Diagnostic);
let a = opts.read_from(&mut diag).unwrap();
let b = opts.read_from(&mut diag).unwrap();
let c = opts.read_from(&mut diag).unwrap();
assert_eq!(a.to_u32().unwrap(), 1);
assert_eq!(b.to_u32().unwrap(), 2);
assert_eq!(c.to_u32().unwrap(), 3);Sourcepub fn sequence_decoder<'a, B: AsRef<[u8]> + ?Sized>(
&self,
input: &'a B,
) -> SequenceDecoder<'a> ⓘ
pub fn sequence_decoder<'a, B: AsRef<[u8]> + ?Sized>( &self, input: &'a B, ) -> SequenceDecoder<'a> ⓘ
Create an iterator over a CBOR sequence stored in memory.
The returned SequenceDecoder yields each successive item of the
sequence as Result<Value>. The iterator captures a snapshot
of these options; subsequent changes to self do not affect
it.
use cbor_core::{DecodeOptions, Format};
let opts = DecodeOptions::new().format(Format::Diagnostic);
let items: Vec<_> = opts
.sequence_decoder(b"1, 2, 3,")
.collect::<Result<_, _>>()
.unwrap();
assert_eq!(items.len(), 3);Sourcepub fn sequence_reader<R: Read>(&self, reader: R) -> SequenceReader<R> ⓘ
pub fn sequence_reader<R: Read>(&self, reader: R) -> SequenceReader<R> ⓘ
Create an iterator over a CBOR sequence read from a stream.
The returned SequenceReader yields each successive item as
IoResult<Value>. None indicates a clean end between items;
a truncated item produces Some(Err(_)).
use cbor_core::DecodeOptions;
// Binary CBOR sequence: three one-byte items 0x01 0x02 0x03.
let bytes: &[u8] = &[0x01, 0x02, 0x03];
let items: Vec<_> = DecodeOptions::new()
.sequence_reader(bytes)
.collect::<Result<_, _>>()
.unwrap();
assert_eq!(items.len(), 3);Trait Implementations§
Source§impl Clone for DecodeOptions
impl Clone for DecodeOptions
Source§fn clone(&self) -> DecodeOptions
fn clone(&self) -> DecodeOptions
1.0.0 · Source§fn clone_from(&mut self, source: &Self)
fn clone_from(&mut self, source: &Self)
source. Read more