1use std::fmt;
10use std::marker::PhantomData;
11
12use serde::de::{Deserialize, DeserializeSeed, Deserializer, Error as _, SeqAccess, Visitor};
13use serde_json::{Map, Value};
14
15pub struct BoundedStr {
18 pub what: &'static str,
19 pub max_bytes: usize,
20}
21
22impl Visitor<'_> for BoundedStr {
23 type Value = String;
24
25 fn expecting(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
26 write!(
27 formatter,
28 "a {} of at most {} bytes",
29 self.what, self.max_bytes
30 )
31 }
32
33 fn visit_str<E: serde::de::Error>(self, value: &str) -> Result<String, E> {
34 if value.len() > self.max_bytes {
35 return Err(E::custom(format!(
36 "a stored {} exceeds {} bytes",
37 self.what, self.max_bytes
38 )));
39 }
40 Ok(value.to_owned())
41 }
42
43 fn visit_string<E: serde::de::Error>(self, value: String) -> Result<String, E> {
44 if value.len() > self.max_bytes {
45 return Err(E::custom(format!(
46 "a stored {} exceeds {} bytes",
47 self.what, self.max_bytes
48 )));
49 }
50 Ok(value)
51 }
52}
53
54impl<'de> DeserializeSeed<'de> for BoundedStr {
55 type Value = String;
56
57 fn deserialize<D: Deserializer<'de>>(self, deserializer: D) -> Result<String, D::Error> {
58 deserializer.deserialize_str(self)
59 }
60}
61
62pub struct TruncatedStr {
66 pub max_bytes: usize,
67}
68
69impl Visitor<'_> for TruncatedStr {
70 type Value = String;
71
72 fn expecting(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
73 write!(
74 formatter,
75 "a string retained up to {} bytes",
76 self.max_bytes
77 )
78 }
79
80 fn visit_str<E: serde::de::Error>(self, value: &str) -> Result<String, E> {
81 if value.len() <= self.max_bytes {
82 return Ok(value.to_owned());
83 }
84 let mut end = self.max_bytes;
85 while !value.is_char_boundary(end) {
86 end -= 1;
87 }
88 Ok(value[..end].to_owned())
89 }
90
91 fn visit_string<E: serde::de::Error>(self, mut value: String) -> Result<String, E> {
92 if value.len() > self.max_bytes {
93 let mut end = self.max_bytes;
94 while !value.is_char_boundary(end) {
95 end -= 1;
96 }
97 value.truncate(end);
98 }
99 Ok(value)
100 }
101}
102
103struct BoundedSeq<T> {
106 what: &'static str,
107 max_len: usize,
108 marker: PhantomData<T>,
109}
110
111impl<'de, T: Deserialize<'de>> Visitor<'de> for BoundedSeq<T> {
112 type Value = Vec<T>;
113
114 fn expecting(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
115 write!(
116 formatter,
117 "a sequence of at most {} {}",
118 self.max_len, self.what
119 )
120 }
121
122 fn visit_seq<A: SeqAccess<'de>>(self, mut seq: A) -> Result<Vec<T>, A::Error> {
123 let mut values = Vec::with_capacity(seq.size_hint().unwrap_or(0).min(self.max_len));
124 while let Some(value) = seq.next_element::<T>()? {
125 if values.len() == self.max_len {
126 return Err(A::Error::custom(format!(
127 "a stored record carries more than {} {}",
128 self.max_len, self.what
129 )));
130 }
131 values.push(value);
132 }
133 Ok(values)
134 }
135}
136
137pub fn bounded_vec<'de, T: Deserialize<'de>, D: Deserializer<'de>>(
138 deserializer: D,
139 what: &'static str,
140 max_len: usize,
141) -> Result<Vec<T>, D::Error> {
142 deserializer.deserialize_seq(BoundedSeq {
143 what,
144 max_len,
145 marker: PhantomData,
146 })
147}
148
149struct BoundedJsonMap {
153 what: &'static str,
154 max_keys: usize,
155 max_key_bytes: usize,
156 valid_key: fn(&str) -> bool,
157}
158
159impl<'de> Visitor<'de> for BoundedJsonMap {
160 type Value = Map<String, Value>;
161
162 fn expecting(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
163 write!(
164 formatter,
165 "an object of at most {} {}",
166 self.max_keys, self.what
167 )
168 }
169
170 fn visit_map<A: serde::de::MapAccess<'de>>(
171 self,
172 mut access: A,
173 ) -> Result<Map<String, Value>, A::Error> {
174 let mut map = Map::new();
175 while let Some(key) = access.next_key_seed(BoundedStr {
176 what: self.what,
177 max_bytes: self.max_key_bytes,
178 })? {
179 if !(self.valid_key)(&key) {
180 return Err(A::Error::custom(format!(
181 "a stored record carries an invalid {} key",
182 self.what
183 )));
184 }
185 if map.len() == self.max_keys {
186 return Err(A::Error::custom(format!(
187 "a stored record carries more than {} {}",
188 self.max_keys, self.what
189 )));
190 }
191 map.insert(key, access.next_value()?);
192 }
193 Ok(map)
194 }
195}
196
197pub fn bounded_json_map<'de, D: Deserializer<'de>>(
198 deserializer: D,
199 what: &'static str,
200 max_keys: usize,
201 max_key_bytes: usize,
202 valid_key: fn(&str) -> bool,
203) -> Result<Map<String, Value>, D::Error> {
204 deserializer.deserialize_map(BoundedJsonMap {
205 what,
206 max_keys,
207 max_key_bytes,
208 valid_key,
209 })
210}
211
212#[cfg(test)]
213mod tests {
214 use serde::de::DeserializeSeed;
215 use serde::de::IntoDeserializer;
216
217 use super::*;
218
219 fn json_de(text: &str) -> serde_json::Deserializer<serde_json::de::StrRead<'_>> {
220 serde_json::Deserializer::from_str(text)
221 }
222
223 #[test]
224 fn oversized_strings_are_refused_before_retention() {
225 let seed = BoundedStr {
226 what: "identifier",
227 max_bytes: 4,
228 };
229 assert_eq!(
230 seed.deserialize(String::from("abcd").into_deserializer()
231 as serde::de::value::StringDeserializer<serde_json::Error>)
232 .unwrap(),
233 "abcd"
234 );
235 let seed = BoundedStr {
236 what: "identifier",
237 max_bytes: 4,
238 };
239 assert!(
240 seed.deserialize(String::from("abcde").into_deserializer()
241 as serde::de::value::StringDeserializer<serde_json::Error>)
242 .is_err()
243 );
244 }
245
246 #[test]
247 fn truncated_strings_stop_at_a_character_boundary() {
248 let visitor = TruncatedStr { max_bytes: 4 };
249 let text = "aééé";
250 let kept = visitor.visit_str::<serde_json::Error>(text).unwrap();
251 assert_eq!(kept, "aé");
252 assert!(kept.len() <= 4);
253 }
254
255 #[test]
256 fn a_sequence_fails_at_the_first_excess_element() {
257 let mut deserializer = json_de("[1,2,3,4]");
258 let result: Result<Vec<u32>, _> = bounded_vec(&mut deserializer, "entries", 3);
259 assert!(result.unwrap_err().to_string().contains("more than 3"));
260
261 let mut deserializer = json_de("[1,2,3]");
262 let values: Vec<u32> = bounded_vec(&mut deserializer, "entries", 3).unwrap();
263 assert_eq!(values, [1, 2, 3]);
264 }
265
266 #[test]
267 fn a_map_checks_key_count_length_and_text_while_decoding() {
268 let accept = |_: &str| true;
269 let mut deserializer = json_de(r#"{"a":1,"b":2}"#);
270 let map = bounded_json_map(&mut deserializer, "detail keys", 2, 8, accept).unwrap();
271 assert_eq!(map.len(), 2);
272
273 let mut deserializer = json_de(r#"{"a":1,"b":2,"c":3}"#);
274 assert!(bounded_json_map(&mut deserializer, "detail keys", 2, 8, accept).is_err());
275
276 let mut deserializer = json_de(r#"{"toolong":1}"#);
277 assert!(bounded_json_map(&mut deserializer, "detail keys", 8, 4, accept).is_err());
278
279 let mut deserializer = json_de(r#"{"":1}"#);
281 assert!(
282 bounded_json_map(&mut deserializer, "detail keys", 8, 8, |key| !key
283 .is_empty())
284 .is_err()
285 );
286 }
287}