easypdf_core/io/
resource_limits.rs1#[derive(Clone, Copy, Debug, PartialEq, Eq)]
16#[allow(clippy::struct_field_names)]
17pub struct ResourceLimits {
18 max_input_bytes: u64,
19 max_pages: usize,
20 max_extracted_text_bytes: usize,
21 max_decompressed_size: u64,
22 max_compression_ratio: u32,
23 max_element_count: usize,
24}
25
26impl ResourceLimits {
27 #[must_use]
33 pub const fn new() -> Self {
34 Self {
35 max_input_bytes: 256 * 1024 * 1024,
36 max_pages: 10_000,
37 max_extracted_text_bytes: 128 * 1024 * 1024,
38 max_decompressed_size: 2 * 1024 * 1024 * 1024,
39 max_compression_ratio: 100,
40 max_element_count: 5_000_000,
41 }
42 }
43
44 #[must_use]
48 pub const fn strict() -> Self {
49 Self {
50 max_input_bytes: 64 * 1024 * 1024,
51 max_pages: 2_500,
52 max_extracted_text_bytes: 32 * 1024 * 1024,
53 max_decompressed_size: 512 * 1024 * 1024,
54 max_compression_ratio: 50,
55 max_element_count: 1_000_000,
56 }
57 }
58
59 #[must_use]
63 pub const fn permissive() -> Self {
64 Self {
65 max_input_bytes: 1024 * 1024 * 1024,
66 max_pages: 100_000,
67 max_extracted_text_bytes: 512 * 1024 * 1024,
68 max_decompressed_size: 8 * 1024 * 1024 * 1024,
69 max_compression_ratio: 400,
70 max_element_count: 20_000_000,
71 }
72 }
73
74 #[must_use]
78 pub const fn with_max_input_bytes(mut self, value: u64) -> Self {
79 self.max_input_bytes = value;
80 self
81 }
82
83 #[must_use]
85 pub const fn with_max_pages(mut self, value: usize) -> Self {
86 self.max_pages = value;
87 self
88 }
89
90 #[must_use]
92 pub const fn with_max_extracted_text_bytes(mut self, value: usize) -> Self {
93 self.max_extracted_text_bytes = value;
94 self
95 }
96
97 #[must_use]
99 pub const fn with_max_decompressed_size(mut self, value: u64) -> Self {
100 self.max_decompressed_size = value;
101 self
102 }
103
104 #[must_use]
106 pub const fn with_max_compression_ratio(mut self, value: u32) -> Self {
107 self.max_compression_ratio = value;
108 self
109 }
110
111 #[must_use]
113 pub const fn with_max_element_count(mut self, value: usize) -> Self {
114 self.max_element_count = value;
115 self
116 }
117
118 #[must_use]
122 pub const fn max_input_bytes(self) -> u64 {
123 self.max_input_bytes
124 }
125
126 #[must_use]
128 pub const fn max_pages(self) -> usize {
129 self.max_pages
130 }
131
132 #[must_use]
134 pub const fn max_extracted_text_bytes(self) -> usize {
135 self.max_extracted_text_bytes
136 }
137
138 #[must_use]
140 pub const fn max_decompressed_size(self) -> u64 {
141 self.max_decompressed_size
142 }
143
144 #[must_use]
146 pub const fn max_compression_ratio(self) -> u32 {
147 self.max_compression_ratio
148 }
149
150 #[must_use]
152 pub const fn max_element_count(self) -> usize {
153 self.max_element_count
154 }
155}
156
157impl Default for ResourceLimits {
158 fn default() -> Self {
159 Self::new()
160 }
161}
162
163#[cfg(test)]
164mod tests {
165 use super::*;
166
167 #[test]
168 fn default_limits_are_sensible() {
169 let limits = ResourceLimits::default();
170 assert_eq!(limits.max_input_bytes(), 256 * 1024 * 1024);
171 assert_eq!(limits.max_pages(), 10_000);
172 assert_eq!(limits.max_decompressed_size(), 2 * 1024 * 1024 * 1024);
173 assert_eq!(limits.max_compression_ratio(), 100);
174 assert_eq!(limits.max_element_count(), 5_000_000);
175 }
176
177 #[test]
178 fn strict_is_more_restrictive() {
179 let default = ResourceLimits::default();
180 let strict = ResourceLimits::strict();
181 assert!(strict.max_input_bytes() < default.max_input_bytes());
182 assert!(strict.max_pages() < default.max_pages());
183 assert!(strict.max_decompressed_size() < default.max_decompressed_size());
184 assert!(strict.max_compression_ratio() < default.max_compression_ratio());
185 assert!(strict.max_element_count() < default.max_element_count());
186 }
187
188 #[test]
189 fn permissive_is_more_relaxed() {
190 let default = ResourceLimits::default();
191 let permissive = ResourceLimits::permissive();
192 assert!(permissive.max_input_bytes() > default.max_input_bytes());
193 assert!(permissive.max_pages() > default.max_pages());
194 assert!(permissive.max_decompressed_size() > default.max_decompressed_size());
195 assert!(permissive.max_compression_ratio() > default.max_compression_ratio());
196 assert!(permissive.max_element_count() > default.max_element_count());
197 }
198
199 #[test]
200 fn builder_overrides_all_fields() {
201 let limits = ResourceLimits::new()
202 .with_max_input_bytes(1024)
203 .with_max_pages(5)
204 .with_max_extracted_text_bytes(2048)
205 .with_max_decompressed_size(4096)
206 .with_max_compression_ratio(10)
207 .with_max_element_count(100);
208 assert_eq!(limits.max_input_bytes(), 1024);
209 assert_eq!(limits.max_pages(), 5);
210 assert_eq!(limits.max_extracted_text_bytes(), 2048);
211 assert_eq!(limits.max_decompressed_size(), 4096);
212 assert_eq!(limits.max_compression_ratio(), 10);
213 assert_eq!(limits.max_element_count(), 100);
214 }
215}