vole_document/limits.rs
1//! Centralized resource bounds.
2//!
3//! Every decode and encode path takes a [`Limits`]. Untrusted descriptors must
4//! be rejected *before* catastrophic work is performed, so all arithmetic on
5//! declared lengths and offsets is checked against these bounds and uses
6//! checked integer operations.
7
8/// Hard upper bounds applied while parsing and materializing a descriptor.
9#[derive(Debug, Clone, Copy, PartialEq, Eq)]
10pub struct Limits {
11 /// Maximum accepted source/descriptor input size.
12 pub max_input_bytes: u64,
13 /// Maximum reconstructed output size for a single materialization.
14 pub max_output_bytes: u64,
15 /// Admission cap on the output of a single `DEFLATE_REPLAY`.
16 ///
17 /// This is a **VOLE replay-profile policy limit**, not an RFC 1951 maximum.
18 /// RFC 1951 permits arbitrarily many empty non-final stored blocks, so it
19 /// gives no finite `f(decompressed_size)` bound on `compressed_size`; a
20 /// bitstream that inflates to zero bytes may be arbitrarily large. VOLE
21 /// therefore declines to replay a descriptor whose declared output exceeds
22 /// this policy cap (see ADR-0016).
23 pub max_replay_bytes: u64,
24 /// Maximum length of a single record payload.
25 pub max_record_len: u32,
26 /// Maximum number of records in a container.
27 pub max_record_count: u32,
28 /// Maximum number of distinct byte objects (`OBJECT` records).
29 pub max_object_count: u32,
30 /// Maximum number of DRA instructions in a reconstruction graph.
31 pub max_graph_ops: u32,
32 /// Maximum repeat count for a single `REPEAT_LAST` instruction.
33 pub max_repeat_count: u64,
34 /// Maximum number of symbols in a single entropy channel.
35 pub max_channel_symbols: u64,
36 /// Maximum number of distinct entropy models (`MODEL` records).
37 pub max_model_count: u32,
38 /// Maximum number of entropy channels (`ENTROPY_CHANNEL` records).
39 pub max_channel_count: u32,
40 /// Maximum encoded size of a single entropy model payload.
41 pub max_entropy_model_bytes: u32,
42 /// Maximum number of lexical spans produced for a PDF input.
43 pub max_pdf_spans: u32,
44 /// Maximum number of selectors in a single `OBSERVATION_INDEX` record.
45 ///
46 /// Bounds the admissions of the optional partial-decode index (Phase 7.3)
47 /// before allocation: an index whose selector table would exceed this is
48 /// rejected at parse and declined by the index builder. It mirrors the
49 /// object/graph scale so the table cannot dwarf the document it describes.
50 pub max_index_selectors: u32,
51 /// Maximum accepted size of an optional `DIRECTORY` record payload.
52 ///
53 /// Bounds the seek directory (Phase 8) before allocation: a directory larger
54 /// than this is declined at decode rather than trusted. A directory is roughly
55 /// `13 * record_count` bytes, so this also caps the record count a directory
56 /// can describe.
57 pub max_directory_bytes: u32,
58 /// Maximum accepted size of an optional `CHECKPOINT` record payload.
59 ///
60 /// Bounds the byte-level partial-materialization checkpoint (Phase 13.4)
61 /// before allocation: a checkpoint larger than this is declined at decode
62 /// rather than trusted. A checkpoint is `20 + 16 * op_count` bytes, so this
63 /// also caps the op count a checkpoint can describe.
64 pub max_checkpoint_bytes: u32,
65 // The ZIP caps below mirror the threat model and DEFAULT/STRICT values frozen
66 // in `research/subagents/phase-12/I-security.md` §6 (threat ids Z1–Z15), as
67 // required by plan §DEC-3/§DEC-9.
68 /// Maximum number of ZIP members accepted in one archive (Phase 12, Z2).
69 pub max_zip_members: u32,
70 /// Maximum declared compressed size of a single ZIP member (Phase 12, Z1).
71 pub max_zip_member_compressed: u64,
72 /// Maximum declared uncompressed size of a single ZIP member (Phase 12, Z1).
73 pub max_zip_member_uncompressed: u64,
74 /// Maximum sum of declared uncompressed sizes across all members (Z2).
75 pub max_zip_aggregate_uncompressed: u64,
76 /// Maximum declared uncompressed/compressed ratio for one member (Z1).
77 pub max_zip_compression_ratio: u32,
78 /// Maximum raw name byte length of one member (Phase 12, Z13/Z14).
79 pub max_zip_name_bytes: u32,
80 /// Maximum raw extra-field byte length of one member (Z7/Z14).
81 pub max_zip_extra_bytes: u32,
82 /// Maximum per-entry comment byte length (Z14).
83 pub max_zip_entry_comment_bytes: u32,
84 /// Maximum archive comment byte length (Z14/Z15).
85 pub max_zip_archive_comment_bytes: u32,
86 /// Maximum central-directory byte length (Z14).
87 pub max_zip_central_dir_bytes: u64,
88 /// Maximum leading bytes before the first local header (Z14).
89 pub max_zip_prefix_bytes: u64,
90 /// Maximum trailing bytes after the EOCD record (Z14).
91 pub max_zip_trailing_bytes: u64,
92 // The XML/OPC caps below mirror the threat model and DEFAULT/STRICT values
93 // frozen in `research/subagents/phase-12/I-security.md` §6 (§2 XML, §3 OPC),
94 // as required by plan §DEC-4/§DEC-9. XML is derived (`Q_gen`) state only.
95 /// Maximum XML element nesting depth before a typed decline (Phase 12, §2).
96 pub max_xml_depth: u32,
97 /// Maximum decoded byte length of a single XML part (Phase 12, §2).
98 pub max_xml_part_bytes: u64,
99 /// Maximum number of XML pull events in a single part (Phase 12, §2).
100 pub max_xml_events: u64,
101 /// Maximum number of XML element nodes in a single part (Phase 12, §2).
102 pub max_xml_nodes: u64,
103 /// Maximum number of attributes on a single XML element (Phase 12, §2).
104 pub max_xml_attrs_per_element: u32,
105 /// Maximum total text bytes accepted across a single XML part (Phase 12, §2).
106 pub max_xml_text_bytes: u64,
107 /// Maximum source length admitted for byte-based standalone XML detection
108 /// (Phase 21.9). A bare XML source above this cap — whose adapter reads the
109 /// whole source as one `DocumentExact` — falls back to
110 /// [`crate::field::document_format::DocumentFormat::Opaque`].
111 pub max_xml_document_bytes: u64,
112 /// Maximum relationships across all `.rels` parts (Phase 12, §3).
113 pub max_opc_rels: u32,
114 /// Maximum internal relationship traversal depth (Phase 12 cycles, §3).
115 pub max_opc_rel_depth: u32,
116 /// Maximum `Default`+`Override` entries in `[Content_Types].xml` (Phase 12, §3).
117 pub max_opc_content_types_overrides: u32,
118 /// Maximum byte length of an OPC part name (Phase 12, §3).
119 pub max_opc_part_name_bytes: u32,
120 // The EPUB/OCF caps below mirror the threat model and DEFAULT/STRICT values
121 // frozen in `research/subagents/phase-12/I-security.md` §6 (§4 EPUB), as
122 // required by plan §DEC-5/§DEC-9. EPUB semantics are derived (`Q_gen`) only.
123 /// Maximum `rootfile` entries accepted in `META-INF/container.xml` (Phase 12, §4).
124 pub max_epub_rootfiles: u32,
125 /// Maximum Package Document manifest items accepted (Phase 12, §4).
126 pub max_epub_manifest_items: u32,
127 /// Maximum Package Document spine `itemref`s accepted (Phase 12, §4).
128 pub max_epub_spine_items: u32,
129 /// Maximum navigation-document nesting depth accepted (Phase 12, §4).
130 pub max_epub_nav_depth: u32,
131 /// Maximum manifest `fallback` chain length followed (Phase 12, §4).
132 pub max_epub_fallback_chain: u32,
133 /// Maximum XHTML element nodes accepted in one content/nav document (Phase 12, §4).
134 pub max_xhtml_nodes: u32,
135 // The ODT/ODF caps below mirror the EPUB caps above (Phase 13.3 applies the same
136 // bounded-XML policy to the OpenDocument content model). ODT semantics are derived
137 // (`Q_gen`) only.
138 /// Maximum `file-entry` elements accepted in `META-INF/manifest.xml` (Phase 13.3).
139 pub max_odt_manifest_entries: u32,
140 /// Maximum block elements accepted in one OpenDocument content part (Phase 13.3).
141 pub max_odt_blocks: u32,
142 /// Maximum notes accepted in one OpenDocument content part (Phase 13.3).
143 pub max_odt_notes: u32,
144 // The ODS/OpenDocument-Spreadsheet caps below bound the derived spreadsheet
145 // model (Phase 21.3.1). ODS semantics are derived (`Q_gen`) only.
146 /// Maximum `table:table` sheets accepted in one OpenDocument spreadsheet
147 /// content part (Phase 21.3.1).
148 pub max_ods_sheets: u32,
149 /// Maximum *expanded* grid slots accepted across one spreadsheet, after
150 /// `table:number-rows-repeated`/`table:number-columns-repeated` expansion
151 /// (Phase 21.3.1). Each expanded row charges at least one slot even when it
152 /// declares no cells, so an empty-row repeat bomb still declines. This is the
153 /// ODS analogue of the XLSX coordinate bound (ADR-0059): a repeated span is
154 /// bounded and the *expanded* count declines typed rather than allocating.
155 pub max_ods_cells: u64,
156 /// Maximum repeat count admitted for a single
157 /// `table:number-columns-repeated`/`table:number-rows-repeated` attribute
158 /// (Phase 21.3.1). A declaration above this bound is a typed resource-limit
159 /// decline, never an allocation.
160 pub max_ods_repeated_span: u32,
161 /// Maximum merged spans (`table:number-columns-spanned`>1 or
162 /// `table:number-rows-spanned`>1) accepted across one spreadsheet
163 /// (Phase 21.3.1).
164 pub max_ods_merges: u32,
165 /// Maximum named expressions
166 /// (`table:named-range`/`table:named-expression`) accepted across one
167 /// spreadsheet (Phase 21.3.1).
168 pub max_ods_named_expressions: u32,
169 /// Maximum `style:style` cell-style records accepted in one spreadsheet's
170 /// automatic styles or styles part (Phase 21.3.1).
171 pub max_ods_styles: u32,
172 /// Maximum `office:annotation` cell comments accepted across one spreadsheet
173 /// (Phase 21.3.1).
174 pub max_ods_comments: u32,
175 // The XLSX/SpreadsheetML caps below bound the derived semantic model
176 // (Phase 21.1.1). XLSX semantics are derived (`Q_gen`) only.
177 /// Maximum `<sheet>` declarations accepted in one workbook (Phase 21.1.1).
178 pub max_xlsx_sheets: u32,
179 /// Maximum cells accepted in one worksheet part (Phase 21.1.1).
180 pub max_xlsx_cells: u64,
181 /// Maximum shared strings accepted in `xl/sharedStrings.xml` (Phase 21.1.1).
182 pub max_xlsx_shared_strings: u32,
183 /// Maximum merged ranges accepted in one worksheet (Phase 21.1.1).
184 pub max_xlsx_merges: u32,
185 /// Maximum hyperlinks accepted in one worksheet (Phase 21.1.2).
186 pub max_xlsx_hyperlinks: u32,
187 /// Maximum comments accepted in one comments part (Phase 21.1.2).
188 pub max_xlsx_comments: u32,
189 /// Maximum table parts accepted across a workbook (Phase 21.1.2).
190 pub max_xlsx_tables: u32,
191 /// Maximum columns accepted in one table part (Phase 21.1.2).
192 pub max_xlsx_table_columns: u32,
193 /// Maximum defined/named ranges accepted in one workbook (Phase 21.1.2).
194 pub max_xlsx_defined_names: u32,
195 /// Maximum drawing parts accepted across a workbook (Phase 21.1.2).
196 pub max_xlsx_drawings: u32,
197 /// Maximum style records (fonts/fills/`cellXfs`) accepted in `styles.xml` (Phase 21.1.2).
198 pub max_xlsx_style_records: u32,
199 /// Maximum 0-based column index accepted in a cell reference (Phase 21.1.2).
200 ///
201 /// The Excel-conformant grid is 16,384 columns wide (A..XFD), so a valid
202 /// 0-based column is `< 16384`; a coordinate at or beyond this bound is a
203 /// typed resource-limit decline. Bounding the coordinate here keeps a single
204 /// hostile reference from driving an unbounded projection downstream.
205 pub max_xlsx_col: u32,
206 /// Maximum 0-based row index accepted in a cell/row reference (Phase 21.1.2).
207 ///
208 /// The Excel-conformant grid is 1,048,576 rows tall (1..1048576), so a valid
209 /// 0-based row is `< 1 << 20`; a coordinate at or beyond this bound is a
210 /// typed resource-limit decline.
211 pub max_xlsx_row: u32,
212 // The PPTX/PresentationML caps below bound the derived semantic model
213 // (Phase 21.2.1). PPTX semantics are derived (`Q_gen`) only.
214 /// Maximum slides accepted in one presentation (Phase 21.2.1).
215 pub max_pptx_slides: u32,
216 /// Maximum shapes accepted in one slide's shape tree, including group
217 /// descendants (Phase 21.2.1).
218 pub max_pptx_shapes_per_slide: u32,
219 /// Maximum text runs (`a:t`) accepted in one slide (Phase 21.2.1).
220 pub max_pptx_text_runs: u32,
221 /// Maximum group-shape nesting depth accepted in one slide (Phase 21.2.1).
222 pub max_pptx_group_depth: u32,
223 /// Maximum media parts (images/audio/video) exposed by one presentation
224 /// (Phase 21.2.1).
225 pub max_pptx_media: u32,
226 /// Maximum embedded tables accepted in one slide (Phase 21.2.1).
227 pub max_pptx_tables: u32,
228 /// Maximum table cells accepted across one slide's tables (Phase 21.2.1).
229 pub max_pptx_table_cells: u32,
230 /// Maximum notes-slide parts accepted in one presentation (Phase 21.2.1).
231 pub max_pptx_notes: u32,
232 /// Maximum slide-layout parts accepted in one presentation (Phase 21.2.1).
233 pub max_pptx_layouts: u32,
234 /// Maximum slide-master parts accepted in one presentation, and the bound
235 /// applied to theme parts (Phase 21.2.1).
236 pub max_pptx_masters: u32,
237 // The ODP/OpenDocument-Presentation caps below bound the derived presentation
238 // model (Phase 21.4.1). ODP semantics are derived (`Q_gen`) only.
239 /// Maximum `draw:page` slides accepted in one OpenDocument presentation
240 /// content part (Phase 21.4.1).
241 pub max_odp_slides: u32,
242 /// Maximum shapes accepted in one slide, including group descendants
243 /// (Phase 21.4.1).
244 pub max_odp_shapes_per_slide: u32,
245 /// Maximum text runs (`text:span`) accepted in one slide (Phase 21.4.1).
246 pub max_odp_text_runs: u32,
247 /// Maximum `draw:g` group nesting depth accepted in one slide (Phase 21.4.1).
248 pub max_odp_group_depth: u32,
249 /// Maximum `Pictures/*` media parts exposed by one presentation (Phase 21.4.1).
250 pub max_odp_media: u32,
251 /// Maximum embedded tables (`table:table`) accepted in one slide
252 /// (Phase 21.4.1).
253 pub max_odp_tables: u32,
254 /// Maximum table cells accepted across one slide's tables, after
255 /// `table:number-columns-repeated`/`table:number-rows-repeated` expansion
256 /// (Phase 21.4.1). An over-large repeat declines typed rather than allocating.
257 pub max_odp_table_cells: u32,
258 /// Maximum notes pages (`presentation:notes`) accepted in one presentation
259 /// (Phase 21.4.1).
260 pub max_odp_notes: u32,
261 /// Maximum `style:master-page` master pages accepted, and the bound applied to
262 /// `style:style` records, in one presentation (Phase 21.4.1).
263 pub max_odp_masters: u32,
264 // The JSON caps below bound the derived, span-preserving structured-tree model
265 // (Phase 21.5.1). JSON is not a package: the whole source parses as exactly one
266 // JSON value beneath these caps, and everything derived is `Q_gen` only.
267 /// Maximum JSON container nesting depth accepted (objects/arrays). A deeper
268 /// document is not detected as JSON (and any direct parse declines typed)
269 /// rather than risking unbounded recursion (Phase 21.5.1).
270 pub max_json_depth: u32,
271 /// Maximum JSON nodes (values plus object member keys) accepted in one
272 /// document. An over-large document declines typed rather than allocating
273 /// (Phase 21.5.1).
274 pub max_json_nodes: u32,
275 /// Maximum total raw string-token bytes accepted across one JSON document
276 /// (the bytes between the quotes, escapes included). A conservative upper
277 /// bound on the decoded text (Phase 21.5.1).
278 pub max_json_string_bytes: u64,
279 /// Maximum source length admitted for byte-based JSON detection. Larger inputs
280 /// fall back to [`crate::field::document_format::DocumentFormat::Opaque`]
281 /// (Phase 21.5.1).
282 pub max_json_document_bytes: u64,
283 // The YAML caps below bound the derived, span-preserving structured-tree model
284 // (Phase 21.6.1). Like JSON, YAML is not a package: the whole source parses as a
285 // bounded stream of documents beneath these caps, and everything derived is
286 // `Q_gen` only.
287 /// Maximum YAML container nesting depth accepted (mappings/sequences). A deeper
288 /// document is not detected as YAML (and any direct parse declines typed) rather
289 /// than risking unbounded recursion (Phase 21.6.1).
290 pub max_yaml_depth: u32,
291 /// Maximum YAML nodes (containers, scalars, aliases, empties) accepted in one
292 /// stream. An over-large document declines typed rather than allocating
293 /// (Phase 21.6.1).
294 pub max_yaml_nodes: u32,
295 /// Maximum YAML scalar nodes accepted in one stream (Phase 21.6.1).
296 pub max_yaml_scalars: u32,
297 /// Maximum YAML anchors (`&a`) accepted in one stream (Phase 21.6.1).
298 pub max_yaml_anchors: u32,
299 /// Maximum documents accepted in one YAML stream (Phase 21.6.1).
300 pub max_yaml_documents: u32,
301 /// Maximum total raw scalar-token bytes accepted across one YAML stream. A
302 /// conservative upper bound on the decoded text (Phase 21.6.1).
303 pub max_yaml_string_bytes: u64,
304 /// Maximum source length admitted for byte-based YAML detection. Larger inputs
305 /// fall back to [`crate::field::document_format::DocumentFormat::Opaque`]
306 /// (Phase 21.6.1).
307 pub max_yaml_document_bytes: u64,
308 // The CSV/TSV caps below bound the derived, span-preserving tabular model and
309 // its streaming reads (Phase 21.7.1). CSV/TSV is not a package: the whole
310 // source is the exact leaf, and everything derived is `Q_gen` only.
311 /// Maximum records accepted in one CSV/TSV table for a **built** span model
312 /// (including the header row). A larger table declines typed rather than
313 /// allocating; the streaming read selectors (`csv-row`/`csv-cell`/...) are not
314 /// bounded by this (they are bounded by one record at a time) (Phase 21.7.1).
315 pub max_csv_rows: u32,
316 /// Maximum fields accepted in a single CSV/TSV record. A record above this
317 /// bound is a typed resource-limit decline, never an allocation (Phase 21.7.1).
318 pub max_csv_cols: u32,
319 /// Maximum byte length of a single CSV/TSV record (terminator included) when a
320 /// span is retained; a longer record declines typed (Phase 21.7.1).
321 pub max_csv_record_bytes: u32,
322 /// Maximum byte length of a single CSV/TSV field (quotes included); a longer
323 /// field declines typed (Phase 21.7.1).
324 pub max_csv_field_bytes: u32,
325 /// Maximum source length admitted for byte-based CSV/TSV detection and parsing.
326 /// Larger inputs fall back to
327 /// [`crate::field::document_format::DocumentFormat::Opaque`] (Phase 21.7.1).
328 pub max_csv_document_bytes: u64,
329 /// Maximum records scanned when deciding whether a source is a CSV/TSV table.
330 /// Detection is a bounded sample, so a huge source is classified in bounded
331 /// memory (Phase 21.7.1).
332 pub max_csv_sampled_records_for_detection: u32,
333 // The Markdown caps below bound the derived, span-preserving prose model and its
334 // inline extraction (Phase 21.8.1). Markdown is not a package: the whole source
335 // is the exact leaf, and everything derived is `Q_gen` only.
336 /// Maximum container nesting depth accepted (list item depth, blockquote marker
337 /// depth). A deeper document is a typed resource-limit decline (Phase 21.8.1).
338 pub max_markdown_depth: u32,
339 /// Maximum nodes (blocks plus inline spans) accepted in one document. An
340 /// over-large document declines typed rather than allocating (Phase 21.8.1).
341 pub max_markdown_nodes: u32,
342 /// Maximum blocks accepted in one document (Phase 21.8.1).
343 pub max_markdown_blocks: u32,
344 /// Maximum inline spans accepted in one document (Phase 21.8.1).
345 pub max_markdown_inline_spans: u32,
346 /// Maximum total code content bytes accepted across one document (fenced and
347 /// indented code). A larger document declines typed (Phase 21.8.1).
348 pub max_markdown_code_bytes: u64,
349 /// Maximum source length admitted for byte-based Markdown detection and
350 /// parsing. Larger inputs fall back to
351 /// [`crate::field::document_format::DocumentFormat::Opaque`] (Phase 21.8.1).
352 pub max_markdown_document_bytes: u64,
353 // The HTML caps below bound the derived, span-preserving, error-recovering HTML
354 // model (Phase 21.10). HTML is not a package: the whole source is the exact
355 // leaf, and everything derived is `Q_gen` only. Unlike XML the HTML scanner is
356 // **error-recovering** (implicit tag closing, void elements, unquoted
357 // attributes, stray end tags), so a malformed document is recovered rather than
358 // declined — only a bound or a forbidden DOCTYPE internal subset declines.
359 /// Maximum element (and raw-text) nesting depth accepted. A deeper document is
360 /// a typed resource-limit decline (Phase 21.10).
361 pub max_html_depth: u32,
362 /// Maximum nodes (elements, text runs, comments, DOCTYPE, raw text) accepted in
363 /// one document. An over-large document declines typed rather than allocating
364 /// (Phase 21.10).
365 pub max_html_nodes: u32,
366 /// Maximum attributes accepted across one document (Phase 21.10).
367 pub max_html_attrs: u64,
368 /// Maximum total text bytes accepted across one document. A larger document
369 /// declines typed (Phase 21.10).
370 pub max_html_text_bytes: u64,
371 /// Maximum total raw `<script>`/`<style>` content bytes accepted across one
372 /// document (their raw text is captured, never executed or parsed) (Phase
373 /// 21.10).
374 pub max_html_script_bytes: u64,
375 /// Maximum source length admitted for byte-based HTML detection and parsing.
376 /// Larger inputs fall back to
377 /// [`crate::field::document_format::DocumentFormat::Opaque`] (Phase 21.10).
378 pub max_html_document_bytes: u64,
379 // The TOML caps below bound the derived, span-preserving TOML model (Phase
380 // 21.11). TOML is not a package: the whole source is the exact leaf, and
381 // everything derived is `Q_gen` only. TOML's duplicate-key and redefinition
382 // rules are enforced (a violation is a typed decline).
383 /// Maximum table/key nesting depth accepted. A deeper document is a typed
384 /// resource-limit decline (Phase 21.11).
385 pub max_toml_depth: u32,
386 /// Maximum nodes (tables, arrays, keys, scalars) accepted in one document. An
387 /// over-large document declines typed rather than allocating (Phase 21.11).
388 pub max_toml_nodes: u32,
389 /// Maximum keys accepted across one document (Phase 21.11).
390 pub max_toml_keys: u64,
391 /// Maximum total string/key bytes accepted across one document. A larger
392 /// document declines typed (Phase 21.11).
393 pub max_toml_string_bytes: u64,
394 /// Maximum source length admitted for byte-based TOML detection and parsing.
395 /// Larger inputs fall back to
396 /// [`crate::field::document_format::DocumentFormat::Opaque`] (Phase 21.11).
397 pub max_toml_document_bytes: u64,
398 // The JSONL/NDJSON caps below bound the derived, per-line span-preserving model
399 // (Phase 21.12). JSONL is not a package: the whole source is the exact leaf, and
400 // everything derived is `Q_gen` only. Each non-blank line is parsed by the
401 // shared JSON parser (never a second parser), so a line is bounded by the JSON
402 // depth cap as well.
403 /// Maximum non-blank record lines accepted in one JSONL document. A larger
404 /// document declines typed rather than allocating (Phase 21.12).
405 pub max_jsonl_records: u32,
406 /// Maximum byte length of one record line's JSON text (the terminator
407 /// excluded). A longer line declines typed (Phase 21.12).
408 pub max_jsonl_line_bytes: u64,
409 /// Maximum total JSON nodes (values plus object member keys) accepted across
410 /// **all** records of one JSONL document. This is a whole-document budget (a
411 /// single line is additionally bounded by the JSON node cap); an over-large
412 /// document declines typed rather than allocating (Phase 21.12).
413 pub max_jsonl_nodes: u32,
414 /// Maximum source length admitted for byte-based JSONL detection and parsing.
415 /// Larger inputs fall back to
416 /// [`crate::field::document_format::DocumentFormat::Opaque`] (Phase 21.12).
417 pub max_jsonl_document_bytes: u64,
418 // The EML/MIME caps below bound the derived, span-preserving message model
419 // (Phase 21.13). EML is not a package: the whole source is the exact leaf, and
420 // everything derived is `Q_gen` only. Every part is a leaf or a
421 // `multipart/*`/`message/rfc822` container, so the tree is bounded by depth and
422 // part count.
423 /// Maximum MIME part nesting depth accepted (root = 0). A deeper message is a
424 /// typed resource-limit decline (Phase 21.13).
425 pub max_eml_depth: u32,
426 /// Maximum MIME parts accepted in one message (the root counts). An over-large
427 /// message declines typed rather than allocating (Phase 21.13).
428 pub max_eml_parts: u32,
429 /// Maximum headers accepted across one message (all parts). A message with more
430 /// declines typed (Phase 21.13).
431 pub max_eml_headers: u32,
432 /// Maximum byte length of one part's entity (headers + body). A larger part
433 /// declines typed (Phase 21.13).
434 pub max_eml_part_bytes: u64,
435 /// Maximum total decoded bytes produced by a transfer-encoding decode (base64 /
436 /// quoted-printable). A larger decode declines typed (Phase 21.13).
437 pub max_eml_decoded_bytes: u64,
438 /// Maximum source length admitted for byte-based EML detection and parsing.
439 /// Larger inputs fall back to
440 /// [`crate::field::document_format::DocumentFormat::Opaque`] (Phase 21.13).
441 pub max_eml_document_bytes: u64,
442 // The Parquet caps below bound the derived, span-preserving analytical model
443 // (Phase 21.14). Parquet is not a package: the whole source is the exact leaf,
444 // and everything derived is `Q_gen` only.
445 /// Maximum number of row groups accepted in one Parquet file (Phase 21.14).
446 pub max_parquet_row_groups: u32,
447 /// Maximum number of leaf columns accepted in one Parquet file (Phase 21.14).
448 pub max_parquet_columns: u32,
449 /// Maximum number of pages accepted in one column chunk (Phase 21.14). A
450 /// page-bomb chunk declines typed rather than looping.
451 pub max_parquet_pages_per_chunk: u32,
452 /// Maximum number of decoded values across a Parquet column (Phase 21.14).
453 pub max_parquet_values: u64,
454 /// Maximum total decompressed page bytes across one decompression (Phase
455 /// 21.14). A decompression bomb declines typed.
456 pub max_parquet_decompressed_bytes: u64,
457 /// Maximum source length admitted for byte-based Parquet detection and parsing.
458 /// Larger inputs fall back to
459 /// [`crate::field::document_format::DocumentFormat::Opaque`] (Phase 21.14).
460 pub max_parquet_document_bytes: u64,
461 /// Maximum accepted Thrift-Compact footer byte length (Phase 21.14). A larger
462 /// footer declines typed before it is parsed.
463 pub max_parquet_footer_bytes: u64,
464 // The Arrow IPC caps below bound the derived, span-preserving analytical model
465 // (Phase 21.16). Arrow is not a package: the whole source is the exact leaf, and
466 // everything derived is `Q_gen` only.
467 /// Maximum number of encapsulated IPC messages (schema + dictionary + record
468 /// batches) accepted in one Arrow file/stream (Phase 21.16).
469 pub max_arrow_messages: u32,
470 /// Maximum number of schema columns (fields, flattened pre-order) accepted in
471 /// one Arrow file (Phase 21.16).
472 pub max_arrow_columns: u32,
473 /// Maximum number of record batches accepted in one Arrow file/stream (Phase
474 /// 21.16).
475 pub max_arrow_batches: u32,
476 /// Maximum number of logical rows accepted across one Arrow file/stream (Phase
477 /// 21.16). A larger file declines typed rather than allocating.
478 pub max_arrow_rows: u64,
479 /// Maximum number of buffers accepted across one record batch (Phase 21.16).
480 pub max_arrow_buffers: u64,
481 /// Maximum number of decoded values across an Arrow column (Phase 21.16).
482 pub max_arrow_values: u64,
483 /// Maximum total declared body/decompressed bytes across one decode (Phase
484 /// 21.16). A body bomb declines typed.
485 pub max_arrow_decompressed_bytes: u64,
486 /// Maximum source length admitted for byte-based Arrow detection and parsing.
487 /// Larger inputs fall back to
488 /// [`crate::field::document_format::DocumentFormat::Opaque`] (Phase 21.16).
489 pub max_arrow_document_bytes: u64,
490 /// Maximum accepted Flatbuffers metadata (footer or message) byte length (Phase
491 /// 21.16). A larger metadata declares typed before it is parsed.
492 pub max_arrow_metadata_bytes: u64,
493}
494
495impl Limits {
496 /// The default archival limits: generous, but always finite.
497 pub const DEFAULT: Limits = Limits {
498 max_input_bytes: 1 << 40, // 1 TiB
499 max_output_bytes: 1 << 40, // 1 TiB
500 max_replay_bytes: 1 << 34, // 16 GiB
501 max_record_len: 1 << 31, // 2 GiB
502 max_record_count: 1 << 20, // ~1M records
503 max_object_count: 1 << 20,
504 max_graph_ops: 1 << 20,
505 max_repeat_count: 1 << 32,
506 max_channel_symbols: 1 << 40,
507 max_model_count: 1 << 16,
508 max_channel_count: 1 << 16,
509 max_entropy_model_bytes: 4096,
510 max_pdf_spans: 1 << 26,
511 max_index_selectors: 1 << 20,
512 max_directory_bytes: 1 << 20,
513 max_checkpoint_bytes: 1 << 20,
514 max_zip_members: 1 << 20,
515 max_zip_member_compressed: 1 << 34,
516 max_zip_member_uncompressed: 1 << 34,
517 max_zip_aggregate_uncompressed: 1 << 36,
518 max_zip_compression_ratio: 1024,
519 max_zip_name_bytes: 1 << 16,
520 max_zip_extra_bytes: 1 << 16,
521 max_zip_entry_comment_bytes: 1 << 16,
522 max_zip_archive_comment_bytes: 1 << 16,
523 max_zip_central_dir_bytes: 1 << 28,
524 max_zip_prefix_bytes: 1 << 20,
525 max_zip_trailing_bytes: 1 << 20,
526 max_xml_depth: 256,
527 max_xml_part_bytes: 1 << 28,
528 max_xml_events: 1 << 24,
529 max_xml_nodes: 1 << 24,
530 max_xml_attrs_per_element: 4096,
531 max_xml_text_bytes: 1 << 28,
532 max_xml_document_bytes: 1 << 34,
533 max_opc_rels: 1 << 20,
534 max_opc_rel_depth: 64,
535 max_opc_content_types_overrides: 1 << 20,
536 max_opc_part_name_bytes: 1 << 16,
537 max_epub_rootfiles: 16,
538 max_epub_manifest_items: 1 << 20,
539 max_epub_spine_items: 1 << 20,
540 max_epub_nav_depth: 64,
541 max_epub_fallback_chain: 32,
542 max_xhtml_nodes: 1 << 24,
543 max_odt_manifest_entries: 1 << 20,
544 max_odt_blocks: 1 << 20,
545 max_odt_notes: 1 << 20,
546 max_ods_sheets: 4096,
547 max_ods_cells: 1 << 24,
548 max_ods_repeated_span: 1 << 20,
549 max_ods_merges: 1 << 20,
550 max_ods_named_expressions: 1 << 20,
551 max_ods_styles: 1 << 16,
552 max_ods_comments: 1 << 20,
553 max_xlsx_sheets: 4096,
554 max_xlsx_cells: 1 << 24,
555 max_xlsx_shared_strings: 1 << 20,
556 max_xlsx_merges: 1 << 20,
557 max_xlsx_hyperlinks: 1 << 20,
558 max_xlsx_comments: 1 << 20,
559 max_xlsx_tables: 1 << 20,
560 max_xlsx_table_columns: 1 << 16,
561 max_xlsx_defined_names: 1 << 20,
562 max_xlsx_drawings: 1 << 14,
563 max_xlsx_style_records: 1 << 16,
564 max_xlsx_col: 16384,
565 max_xlsx_row: 1 << 20,
566 max_pptx_slides: 4096,
567 max_pptx_shapes_per_slide: 1 << 20,
568 max_pptx_text_runs: 1 << 22,
569 max_pptx_group_depth: 64,
570 max_pptx_media: 1 << 14,
571 max_pptx_tables: 1 << 14,
572 max_pptx_table_cells: 1 << 20,
573 max_pptx_notes: 1 << 16,
574 max_pptx_layouts: 1 << 14,
575 max_pptx_masters: 1 << 14,
576 max_odp_slides: 4096,
577 max_odp_shapes_per_slide: 1 << 20,
578 max_odp_text_runs: 1 << 22,
579 max_odp_group_depth: 64,
580 max_odp_media: 1 << 14,
581 max_odp_tables: 1 << 14,
582 max_odp_table_cells: 1 << 20,
583 max_odp_notes: 1 << 16,
584 max_odp_masters: 1 << 14,
585 max_json_depth: 256,
586 max_json_nodes: 1 << 24,
587 max_json_string_bytes: 1 << 28,
588 max_json_document_bytes: 1 << 34,
589 max_yaml_depth: 256,
590 max_yaml_nodes: 1 << 24,
591 max_yaml_scalars: 1 << 24,
592 max_yaml_anchors: 1 << 20,
593 max_yaml_documents: 1 << 16,
594 max_yaml_string_bytes: 1 << 28,
595 max_yaml_document_bytes: 1 << 34,
596 max_csv_rows: 1 << 24,
597 max_csv_cols: 1 << 16,
598 max_csv_record_bytes: 1 << 26,
599 max_csv_field_bytes: 1 << 24,
600 max_csv_document_bytes: 1 << 34,
601 max_csv_sampled_records_for_detection: 1024,
602 max_markdown_depth: 256,
603 max_markdown_nodes: 1 << 24,
604 max_markdown_blocks: 1 << 22,
605 max_markdown_inline_spans: 1 << 24,
606 max_markdown_code_bytes: 1 << 28,
607 max_markdown_document_bytes: 1 << 34,
608 max_html_depth: 256,
609 max_html_nodes: 1 << 24,
610 max_html_attrs: 1 << 26,
611 max_html_text_bytes: 1 << 28,
612 max_html_script_bytes: 1 << 28,
613 max_html_document_bytes: 1 << 34,
614 max_toml_depth: 256,
615 max_toml_nodes: 1 << 24,
616 max_toml_keys: 1 << 22,
617 max_toml_string_bytes: 1 << 28,
618 max_toml_document_bytes: 1 << 34,
619 max_jsonl_records: 1 << 22,
620 max_jsonl_line_bytes: 1 << 26,
621 max_jsonl_nodes: 1 << 24,
622 max_jsonl_document_bytes: 1 << 34,
623 max_eml_depth: 64,
624 max_eml_parts: 1 << 20,
625 max_eml_headers: 1 << 20,
626 max_eml_part_bytes: 1 << 28,
627 max_eml_decoded_bytes: 1 << 28,
628 max_eml_document_bytes: 1 << 34,
629 max_parquet_row_groups: 1 << 20,
630 max_parquet_columns: 1 << 20,
631 max_parquet_pages_per_chunk: 1 << 20,
632 max_parquet_values: 1 << 30,
633 max_parquet_decompressed_bytes: 1 << 28,
634 max_parquet_document_bytes: 1 << 34,
635 max_parquet_footer_bytes: 1 << 26,
636 max_arrow_messages: 1 << 20,
637 max_arrow_columns: 1 << 20,
638 max_arrow_batches: 1 << 20,
639 max_arrow_rows: 1 << 40,
640 max_arrow_buffers: 1 << 26,
641 max_arrow_values: 1 << 30,
642 max_arrow_decompressed_bytes: 1 << 30,
643 max_arrow_document_bytes: 1 << 34,
644 max_arrow_metadata_bytes: 1 << 26,
645 };
646
647 /// Tight limits for hostile-input testing and fuzzing.
648 pub const STRICT: Limits = Limits {
649 max_input_bytes: 1 << 26, // 64 MiB
650 max_output_bytes: 1 << 26, // 64 MiB
651 max_replay_bytes: 1 << 26, // 64 MiB
652 max_record_len: 1 << 24, // 16 MiB
653 max_record_count: 1 << 16, // 65536
654 max_object_count: 1 << 16,
655 max_graph_ops: 1 << 16,
656 max_repeat_count: 1 << 24,
657 max_channel_symbols: 1 << 26,
658 max_model_count: 1 << 12,
659 max_channel_count: 1 << 12,
660 max_entropy_model_bytes: 4096,
661 max_pdf_spans: 1 << 16,
662 max_index_selectors: 1 << 16,
663 max_directory_bytes: 1 << 18,
664 max_checkpoint_bytes: 1 << 18,
665 max_zip_members: 1 << 16,
666 max_zip_member_compressed: 1 << 26,
667 max_zip_member_uncompressed: 1 << 26,
668 max_zip_aggregate_uncompressed: 1 << 27,
669 max_zip_compression_ratio: 256,
670 max_zip_name_bytes: 4096,
671 max_zip_extra_bytes: 4096,
672 max_zip_entry_comment_bytes: 4096,
673 max_zip_archive_comment_bytes: 4096,
674 max_zip_central_dir_bytes: 1 << 20,
675 max_zip_prefix_bytes: 1 << 16,
676 max_zip_trailing_bytes: 1 << 16,
677 max_xml_depth: 64,
678 max_xml_part_bytes: 1 << 20,
679 max_xml_events: 1 << 16,
680 max_xml_nodes: 1 << 16,
681 max_xml_attrs_per_element: 256,
682 max_xml_text_bytes: 1 << 20,
683 max_xml_document_bytes: 1 << 26,
684 max_opc_rels: 1 << 14,
685 max_opc_rel_depth: 16,
686 max_opc_content_types_overrides: 1 << 12,
687 max_opc_part_name_bytes: 4096,
688 max_epub_rootfiles: 4,
689 max_epub_manifest_items: 1 << 14,
690 max_epub_spine_items: 1 << 14,
691 max_epub_nav_depth: 16,
692 max_epub_fallback_chain: 8,
693 max_xhtml_nodes: 1 << 16,
694 max_odt_manifest_entries: 1 << 14,
695 max_odt_blocks: 1 << 14,
696 max_odt_notes: 1 << 12,
697 max_ods_sheets: 64,
698 max_ods_cells: 1 << 16,
699 max_ods_repeated_span: 1 << 14,
700 max_ods_merges: 1 << 14,
701 max_ods_named_expressions: 1 << 14,
702 max_ods_styles: 1 << 12,
703 max_ods_comments: 1 << 14,
704 max_xlsx_sheets: 64,
705 max_xlsx_cells: 1 << 16,
706 max_xlsx_shared_strings: 1 << 14,
707 max_xlsx_merges: 1 << 14,
708 max_xlsx_hyperlinks: 1 << 14,
709 max_xlsx_comments: 1 << 14,
710 max_xlsx_tables: 1 << 14,
711 max_xlsx_table_columns: 1 << 12,
712 max_xlsx_defined_names: 1 << 14,
713 max_xlsx_drawings: 1 << 12,
714 max_xlsx_style_records: 1 << 12,
715 max_xlsx_col: 16384,
716 max_xlsx_row: 1 << 20,
717 max_pptx_slides: 64,
718 max_pptx_shapes_per_slide: 1 << 16,
719 max_pptx_text_runs: 1 << 18,
720 max_pptx_group_depth: 16,
721 max_pptx_media: 1 << 12,
722 max_pptx_tables: 1 << 12,
723 max_pptx_table_cells: 1 << 16,
724 max_pptx_notes: 1 << 12,
725 max_pptx_layouts: 1 << 12,
726 max_pptx_masters: 1 << 12,
727 max_odp_slides: 64,
728 max_odp_shapes_per_slide: 1 << 16,
729 max_odp_text_runs: 1 << 18,
730 max_odp_group_depth: 16,
731 max_odp_media: 1 << 12,
732 max_odp_tables: 1 << 12,
733 max_odp_table_cells: 1 << 16,
734 max_odp_notes: 1 << 12,
735 max_odp_masters: 1 << 12,
736 max_json_depth: 64,
737 max_json_nodes: 1 << 16,
738 max_json_string_bytes: 1 << 20,
739 max_json_document_bytes: 1 << 26,
740 max_yaml_depth: 64,
741 max_yaml_nodes: 1 << 16,
742 max_yaml_scalars: 1 << 16,
743 max_yaml_anchors: 1 << 12,
744 max_yaml_documents: 1 << 10,
745 max_yaml_string_bytes: 1 << 20,
746 max_yaml_document_bytes: 1 << 26,
747 max_csv_rows: 1 << 16,
748 max_csv_cols: 1 << 12,
749 max_csv_record_bytes: 1 << 20,
750 max_csv_field_bytes: 1 << 18,
751 max_csv_document_bytes: 1 << 26,
752 max_csv_sampled_records_for_detection: 64,
753 max_markdown_depth: 64,
754 max_markdown_nodes: 1 << 16,
755 max_markdown_blocks: 1 << 14,
756 max_markdown_inline_spans: 1 << 16,
757 max_markdown_code_bytes: 1 << 20,
758 max_markdown_document_bytes: 1 << 26,
759 max_html_depth: 64,
760 max_html_nodes: 1 << 16,
761 max_html_attrs: 1 << 16,
762 max_html_text_bytes: 1 << 20,
763 max_html_script_bytes: 1 << 20,
764 max_html_document_bytes: 1 << 26,
765 max_toml_depth: 64,
766 max_toml_nodes: 1 << 16,
767 max_toml_keys: 1 << 14,
768 max_toml_string_bytes: 1 << 20,
769 max_toml_document_bytes: 1 << 26,
770 max_jsonl_records: 1 << 12,
771 max_jsonl_line_bytes: 1 << 20,
772 max_jsonl_nodes: 1 << 16,
773 max_jsonl_document_bytes: 1 << 26,
774 max_eml_depth: 16,
775 max_eml_parts: 1 << 12,
776 max_eml_headers: 1 << 12,
777 max_eml_part_bytes: 1 << 20,
778 max_eml_decoded_bytes: 1 << 20,
779 max_eml_document_bytes: 1 << 26,
780 max_parquet_row_groups: 1 << 12,
781 max_parquet_columns: 1 << 12,
782 max_parquet_pages_per_chunk: 1 << 12,
783 max_parquet_values: 1 << 16,
784 max_parquet_decompressed_bytes: 1 << 20,
785 max_parquet_document_bytes: 1 << 26,
786 max_parquet_footer_bytes: 1 << 20,
787 max_arrow_messages: 1 << 12,
788 max_arrow_columns: 1 << 12,
789 max_arrow_batches: 1 << 12,
790 max_arrow_rows: 1 << 24,
791 max_arrow_buffers: 1 << 20,
792 max_arrow_values: 1 << 16,
793 max_arrow_decompressed_bytes: 1 << 20,
794 max_arrow_document_bytes: 1 << 26,
795 max_arrow_metadata_bytes: 1 << 20,
796 };
797}
798
799impl Default for Limits {
800 fn default() -> Self {
801 Limits::DEFAULT
802 }
803}