Skip to main content

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}