1use crate::buffer::{Reader, Writer};
19use crate::config::Config;
20use crate::error::Error;
21use crate::meta::TypeMeta;
22use crate::resolver::type_resolver::NO_USER_TYPE_ID;
23use crate::resolver::{TypeInfo, TypeResolver};
24use std::collections::HashMap;
25use std::rc::Rc;
26
27#[derive(Default)]
32pub struct MetaWriterResolver {
33 type_info_index_map: HashMap<*const TypeInfo, usize>,
36 type_index_index_map: Vec<usize>,
37 next_index: usize,
38}
39
40const MIN_REMOTE_TYPE_META_LIMIT: usize = 8192;
41const NO_WRITTEN_TYPE_INDEX: usize = usize::MAX;
42
43#[allow(dead_code)]
44impl MetaWriterResolver {
45 #[inline(always)]
48 pub fn write_type_meta(
49 &mut self,
50 writer: &mut Writer,
51 provider_type_id: std::any::TypeId,
52 type_resolver: &TypeResolver,
53 ) -> Result<(), Error> {
54 let type_info = type_resolver.get_provider_type_info(&provider_type_id)?;
55 self.write_resolved_type_meta(writer, &type_info)
56 }
57
58 #[inline(always)]
59 pub(crate) fn write_resolved_type_meta(
60 &mut self,
61 writer: &mut Writer,
62 type_info: &Rc<TypeInfo>,
63 ) -> Result<(), Error> {
64 let identity = Rc::as_ptr(type_info);
65 match self.type_info_index_map.get(&identity) {
66 Some(&index) => {
67 writer.write_var_u32(((index as u32) << 1) | 1);
69 }
70 None => {
71 let index = self.next_index;
73 self.next_index += 1;
74 writer.write_var_u32((index as u32) << 1);
75 self.type_info_index_map.insert(identity, index);
76 let type_def = type_info.get_type_def();
77 writer.write_bytes(&type_def);
78 }
79 }
80 Ok(())
81 }
82
83 #[inline(always)]
85 pub fn write_type_meta_fast(
86 &mut self,
87 writer: &mut Writer,
88 type_id: std::any::TypeId,
89 type_index: u32,
90 type_resolver: &TypeResolver,
91 ) -> Result<(), Error> {
92 let type_index = type_index as usize;
93 if let Some(&index) = self.type_index_index_map.get(type_index) {
94 if index != NO_WRITTEN_TYPE_INDEX {
95 writer.write_var_u32(((index as u32) << 1) | 1);
96 return Ok(());
97 }
98 }
99
100 let index = self.next_index;
101 self.next_index += 1;
102 writer.write_var_u32((index as u32) << 1);
103 if type_index >= self.type_index_index_map.len() {
104 self.type_index_index_map
105 .resize(type_index + 1, NO_WRITTEN_TYPE_INDEX);
106 }
107 self.type_index_index_map[type_index] = index;
108 let type_meta = type_resolver.get_type_meta_by_index_ref(&type_id, type_index as u32)?;
109 writer.write_bytes(type_meta.get_bytes());
110 Ok(())
111 }
112
113 #[inline(always)]
114 pub fn reset(&mut self) {
115 self.type_info_index_map.clear();
116 self.type_index_index_map.clear();
117 self.next_index = 0;
118 }
119}
120
121#[derive(Default)]
126pub struct MetaReaderResolver {
127 pub reading_type_infos: Vec<Rc<TypeInfo>>,
128 parsed_type_infos: HashMap<i64, Rc<TypeInfo>>,
129 remote_schema_versions_by_type: HashMap<String, usize>,
130 total_accepted_schema_versions: usize,
131 cached_meta_header: i64,
132 cached_type_info: Option<Rc<TypeInfo>>,
133}
134
135impl MetaReaderResolver {
136 #[inline(always)]
137 pub fn get(&self, index: usize) -> Option<&Rc<TypeInfo>> {
138 self.reading_type_infos.get(index)
139 }
140
141 #[inline(always)]
144 pub fn read_type_meta(
145 &mut self,
146 reader: &mut Reader,
147 type_resolver: &TypeResolver,
148 config: &Config,
149 ) -> Result<Rc<TypeInfo>, Error> {
150 let index_marker = reader.read_var_u32()?;
151 let is_ref = (index_marker & 1) == 1;
152 let index = (index_marker >> 1) as usize;
153
154 if is_ref {
155 self.reading_type_infos.get(index).cloned().ok_or_else(|| {
157 Error::type_error(format!("TypeInfo not found for type index: {}", index))
158 })
159 } else {
160 let meta_header = reader.read_i64()?;
162 if let Some(type_info) = self
163 .cached_type_info
164 .as_ref()
165 .filter(|_| self.cached_meta_header == meta_header)
166 {
167 self.reading_type_infos.push(type_info.clone());
172 TypeMeta::skip_bytes_for_validated_header(reader, meta_header)?;
173 return Ok(type_info.clone());
174 }
175 if let Some(type_info) = self.parsed_type_infos.get(&meta_header) {
176 self.cached_meta_header = meta_header;
181 self.cached_type_info = Some(type_info.clone());
182 self.reading_type_infos.push(type_info.clone());
183 TypeMeta::skip_bytes_for_validated_header(reader, meta_header)?;
184 Ok(type_info.clone())
185 } else {
186 let type_def_start = reader.get_cursor() - std::mem::size_of::<i64>();
187 self.read_remote_type_meta(
188 reader,
189 type_resolver,
190 config,
191 meta_header,
192 type_def_start,
193 )
194 }
195 }
196 }
197
198 #[cold]
199 #[inline(never)]
200 fn read_remote_type_meta(
201 &mut self,
202 reader: &mut Reader,
203 type_resolver: &TypeResolver,
204 config: &Config,
205 meta_header: i64,
206 type_def_start: usize,
207 ) -> Result<Rc<TypeInfo>, Error> {
208 let type_meta = Rc::new(TypeMeta::from_bytes_with_header(
209 reader,
210 type_resolver,
211 meta_header,
212 config.max_type_fields(),
213 config.max_type_meta_bytes(),
214 )?);
215 let remote_type_def = reader.sub_slice(type_def_start, reader.get_cursor())?;
216
217 let namespace = type_meta.get_namespace();
218 let type_name = type_meta.get_type_name();
219 let register_by_name = !namespace.original.is_empty() || !type_name.original.is_empty();
220 let mut remote_schema_key = None;
221 let type_info = if register_by_name {
222 if let Some(local_type_info) =
223 type_resolver.get_type_info_by_name(&namespace.original, &type_name.original)
224 {
225 if local_type_info.get_type_meta_ref().get_bytes() == remote_type_def {
226 local_type_info
227 } else {
228 remote_schema_key =
229 Some(self.check_remote_type_meta_limit(&type_meta, config)?);
230 Rc::new(TypeInfo::from_remote_meta(
231 type_meta.clone(),
232 Some(local_type_info.get_harness()),
233 Some(local_type_info.get_type_id() as u32),
234 Some(local_type_info.get_user_type_id()),
235 ))
236 }
237 } else {
238 remote_schema_key = Some(self.check_remote_type_meta_limit(&type_meta, config)?);
239 Rc::new(TypeInfo::from_remote_meta(
240 type_meta.clone(),
241 None,
242 None,
243 None,
244 ))
245 }
246 } else {
247 let type_id = type_meta.get_type_id();
248 let user_type_id = type_meta.get_user_type_id();
249 let local_type_info = if user_type_id != NO_USER_TYPE_ID {
250 type_resolver.get_user_type_info_by_id(user_type_id)
251 } else {
252 type_resolver.get_type_info_by_id(type_id)
253 };
254 if let Some(local_type_info) = local_type_info {
255 if local_type_info.get_type_meta_ref().get_bytes() == remote_type_def {
256 local_type_info
257 } else {
258 remote_schema_key =
259 Some(self.check_remote_type_meta_limit(&type_meta, config)?);
260 Rc::new(TypeInfo::from_remote_meta(
261 type_meta.clone(),
262 Some(local_type_info.get_harness()),
263 Some(local_type_info.get_type_id() as u32),
264 Some(local_type_info.get_user_type_id()),
265 ))
266 }
267 } else {
268 remote_schema_key = Some(self.check_remote_type_meta_limit(&type_meta, config)?);
269 Rc::new(TypeInfo::from_remote_meta(
270 type_meta.clone(),
271 None,
272 None,
273 None,
274 ))
275 }
276 };
277
278 self.parsed_type_infos
279 .insert(meta_header, type_info.clone());
280 self.cached_meta_header = meta_header;
281 self.cached_type_info = Some(type_info.clone());
282 self.reading_type_infos.push(type_info.clone());
283 if let Some(remote_schema_key) = remote_schema_key {
284 self.record_remote_type_meta(remote_schema_key);
285 }
286 Ok(type_info)
287 }
288
289 #[cold]
290 #[inline(never)]
291 fn check_remote_type_meta_limit(
292 &self,
293 type_meta: &TypeMeta,
294 config: &Config,
295 ) -> Result<String, Error> {
296 let namespace = type_meta.get_namespace();
297 let type_name = type_meta.get_type_name();
298 let key = if !namespace.original.is_empty() || !type_name.original.is_empty() {
299 format!("n{}\0{}", namespace.original, type_name.original)
300 } else {
301 format!("i{}", type_meta.get_user_type_id())
302 };
303
304 let versions_for_type = self
305 .remote_schema_versions_by_type
306 .get(&key)
307 .copied()
308 .unwrap_or(0);
309 if versions_for_type >= config.max_schema_versions_per_type() {
310 return Err(Error::invalid_data(format!(
311 "remote schema version limit exceeded for one type. The data may be malicious. If the data is not malicious, please increase max_schema_versions_per_type={}",
312 config.max_schema_versions_per_type()
313 )));
314 }
315
316 let accepted_type_count =
317 self.remote_schema_versions_by_type.len() + if versions_for_type == 0 { 1 } else { 0 };
318 let global_limit = usize::max(
319 MIN_REMOTE_TYPE_META_LIMIT,
320 accepted_type_count * config.max_average_schema_versions_per_type(),
321 );
322 if self.total_accepted_schema_versions >= global_limit {
323 return Err(Error::invalid_data(format!(
324 "remote schema version limit exceeded globally. The data may be malicious. If the data is not malicious, please increase max_average_schema_versions_per_type={}",
325 config.max_average_schema_versions_per_type()
326 )));
327 }
328
329 Ok(key)
330 }
331
332 fn record_remote_type_meta(&mut self, key: String) {
333 let versions_for_type = self
334 .remote_schema_versions_by_type
335 .get(&key)
336 .copied()
337 .unwrap_or(0);
338 self.remote_schema_versions_by_type
339 .insert(key, versions_for_type + 1);
340 self.total_accepted_schema_versions += 1;
341 }
342
343 #[inline(always)]
344 pub fn reset(&mut self) {
345 self.reading_type_infos.clear();
346 }
347}
348
349#[cfg(test)]
350mod tests {
351 use super::*;
352 use crate::config::Config;
353 use crate::context::{ReadContext, WriteContext};
354 use crate::meta::{
355 FieldInfo, FieldType, MetaString, NAMESPACE_ENCODER, NAMESPACE_ENCODINGS,
356 TYPE_NAME_ENCODER, TYPE_NAME_ENCODINGS,
357 };
358 use crate::serializer::Serializer;
359 use crate::TypeId;
360
361 struct LocalExt;
362
363 impl Serializer for LocalExt {
364 type Target = Self;
365
366 fn write_data(_value: &Self, _context: &mut WriteContext) -> Result<(), Error> {
367 Ok(())
368 }
369
370 fn read_data(_context: &mut ReadContext) -> Result<Self, Error> {
371 Ok(LocalExt)
372 }
373 }
374
375 fn read_type_def(
376 resolver: &mut MetaReaderResolver,
377 config: &Config,
378 type_def: &[u8],
379 ) -> Result<Rc<TypeInfo>, Error> {
380 let type_resolver = TypeResolver::default();
381 read_type_def_with_type_resolver(resolver, config, &type_resolver, type_def)
382 }
383
384 fn read_type_def_with_type_resolver(
385 resolver: &mut MetaReaderResolver,
386 config: &Config,
387 type_resolver: &TypeResolver,
388 type_def: &[u8],
389 ) -> Result<Rc<TypeInfo>, Error> {
390 let mut bytes = vec![];
391 let mut writer = Writer::from_buffer(&mut bytes);
392 writer.write_var_u32(0);
393 writer.write_bytes(type_def);
394 let mut reader = Reader::new(&bytes);
395 resolver.read_type_meta(&mut reader, type_resolver, config)
396 }
397
398 #[test]
399 fn type_meta_field_limit_rejects_large_struct() {
400 let meta = TypeMeta::new(
401 TypeId::STRUCT as u32,
402 9001,
403 MetaString::get_empty().clone(),
404 MetaString::get_empty().clone(),
405 false,
406 vec![
407 FieldInfo::new("a", FieldType::new(crate::type_id::INT32, false, vec![])),
408 FieldInfo::new("b", FieldType::new(crate::type_id::INT32, false, vec![])),
409 ],
410 )
411 .unwrap();
412 let config = Config {
413 max_type_fields: 1,
414 ..Default::default()
415 };
416 let err = read_type_def(
417 &mut MetaReaderResolver::default(),
418 &config,
419 meta.get_bytes(),
420 )
421 .unwrap_err()
422 .to_string();
423 assert!(err.contains("max_type_fields"));
424 }
425
426 #[test]
427 fn type_meta_body_limit_rejects_large_metadata() {
428 let meta = TypeMeta::new(
429 TypeId::STRUCT as u32,
430 9001,
431 MetaString::get_empty().clone(),
432 MetaString::get_empty().clone(),
433 false,
434 vec![FieldInfo::new(
435 "a",
436 FieldType::new(crate::type_id::INT32, false, vec![]),
437 )],
438 )
439 .unwrap();
440 let config = Config {
441 max_type_meta_bytes: 1,
442 ..Default::default()
443 };
444 let err = read_type_def(
445 &mut MetaReaderResolver::default(),
446 &config,
447 meta.get_bytes(),
448 )
449 .unwrap_err()
450 .to_string();
451 assert!(err.contains("max_type_meta_bytes"));
452 }
453
454 #[test]
455 fn schema_limit_tracks_unknown_struct_types_separately() {
456 fn type_def(user_type_id: u32, field_name: &str) -> Vec<u8> {
457 TypeMeta::new(
458 TypeId::STRUCT as u32,
459 user_type_id,
460 MetaString::get_empty().clone(),
461 MetaString::get_empty().clone(),
462 false,
463 vec![FieldInfo::new(
464 field_name,
465 FieldType::new(crate::type_id::INT32, false, vec![]),
466 )],
467 )
468 .unwrap()
469 .get_bytes()
470 .to_vec()
471 }
472
473 let config = Config {
474 max_schema_versions_per_type: 1,
475 ..Default::default()
476 };
477
478 let mut resolver = MetaReaderResolver::default();
479 read_type_def(&mut resolver, &config, &type_def(9001, "a")).unwrap();
480 read_type_def(&mut resolver, &config, &type_def(9002, "a")).unwrap();
481
482 let err = read_type_def(&mut resolver, &config, &type_def(9001, "b"))
483 .unwrap_err()
484 .to_string();
485 assert!(err.contains("max_schema_versions_per_type"));
486 }
487
488 #[test]
489 fn schema_limit_rejects_extra_versions_for_type() {
490 let meta = TypeMeta::new(
491 TypeId::STRUCT as u32,
492 9001,
493 MetaString::get_empty().clone(),
494 MetaString::get_empty().clone(),
495 false,
496 vec![FieldInfo::new(
497 "a",
498 FieldType::new(crate::type_id::INT32, false, vec![]),
499 )],
500 )
501 .unwrap();
502 let type_def = meta.get_bytes().to_vec();
503
504 let config = Config {
505 max_schema_versions_per_type: 1,
506 ..Default::default()
507 };
508 let mut resolver = MetaReaderResolver::default();
509 let mut bytes = vec![];
510 let mut writer = Writer::from_buffer(&mut bytes);
511 writer.write_var_u32(0);
512 writer.write_bytes(&type_def);
513 let mut reader = Reader::new(&bytes);
514 resolver
515 .read_type_meta(&mut reader, &TypeResolver::default(), &config)
516 .unwrap();
517
518 let changed = TypeMeta::new(
519 TypeId::STRUCT as u32,
520 9001,
521 MetaString::get_empty().clone(),
522 MetaString::get_empty().clone(),
523 false,
524 vec![FieldInfo::new(
525 "b",
526 FieldType::new(crate::type_id::INT32, false, vec![]),
527 )],
528 )
529 .unwrap();
530 let mut bytes = vec![];
531 let mut writer = Writer::from_buffer(&mut bytes);
532 writer.write_var_u32(0);
533 writer.write_bytes(changed.get_bytes());
534 let mut reader = Reader::new(&bytes);
535 let err = resolver
536 .read_type_meta(&mut reader, &TypeResolver::default(), &config)
537 .unwrap_err()
538 .to_string();
539 assert!(err.contains("max_schema_versions_per_type"));
540 }
541
542 #[test]
543 fn schema_limit_check_is_not_recorded() {
544 let config = Config {
545 max_schema_versions_per_type: 1,
546 ..Default::default()
547 };
548 let mut resolver = MetaReaderResolver::default();
549 let checked = TypeMeta::new(
550 TypeId::STRUCT as u32,
551 9001,
552 MetaString::get_empty().clone(),
553 MetaString::get_empty().clone(),
554 false,
555 vec![FieldInfo::new(
556 "a",
557 FieldType::new(crate::type_id::INT32, false, vec![]),
558 )],
559 )
560 .unwrap();
561 let accepted = TypeMeta::new(
562 TypeId::STRUCT as u32,
563 9001,
564 MetaString::get_empty().clone(),
565 MetaString::get_empty().clone(),
566 false,
567 vec![FieldInfo::new(
568 "b",
569 FieldType::new(crate::type_id::INT32, false, vec![]),
570 )],
571 )
572 .unwrap();
573
574 resolver
575 .check_remote_type_meta_limit(&checked, &config)
576 .unwrap();
577
578 let mut bytes = vec![];
579 let mut writer = Writer::from_buffer(&mut bytes);
580 writer.write_var_u32(0);
581 writer.write_bytes(accepted.get_bytes());
582 let mut reader = Reader::new(&bytes);
583 resolver
584 .read_type_meta(&mut reader, &TypeResolver::default(), &config)
585 .unwrap();
586 }
587
588 #[test]
589 fn non_struct_type_meta_uses_limit() {
590 let config = Config {
591 max_schema_versions_per_type: 1,
592 ..Default::default()
593 };
594 let mut resolver = MetaReaderResolver::default();
595 let namespace = NAMESPACE_ENCODER
596 .encode_with_encodings("example", NAMESPACE_ENCODINGS)
597 .unwrap();
598 let type_name = TYPE_NAME_ENCODER
599 .encode_with_encodings("RemoteEnum", TYPE_NAME_ENCODINGS)
600 .unwrap();
601 let first = TypeMeta::new(
602 TypeId::NAMED_ENUM as u32,
603 NO_USER_TYPE_ID,
604 namespace.clone(),
605 type_name.clone(),
606 true,
607 vec![],
608 )
609 .unwrap();
610 let second = TypeMeta::new(
611 TypeId::NAMED_EXT as u32,
612 NO_USER_TYPE_ID,
613 namespace,
614 type_name,
615 true,
616 vec![],
617 )
618 .unwrap();
619
620 let key = resolver
621 .check_remote_type_meta_limit(&first, &config)
622 .unwrap();
623 resolver.record_remote_type_meta(key);
624
625 let err = resolver
626 .check_remote_type_meta_limit(&second, &config)
627 .unwrap_err()
628 .to_string();
629 assert!(err.contains("max_schema_versions_per_type"));
630 }
631
632 #[test]
633 fn exact_local_non_struct_type_meta_bypasses_limit() {
634 let config = Config {
635 max_schema_versions_per_type: 1,
636 ..Default::default()
637 };
638 let mut type_resolver = TypeResolver::default();
639 type_resolver
640 .register_serializer_by_name::<LocalExt>("example.SharedExt")
641 .unwrap();
642 let type_resolver = type_resolver.build_final_type_resolver().unwrap();
643 let local_info = type_resolver
644 .get_type_info_by_name("example", "SharedExt")
645 .unwrap();
646 let exact = local_info.get_type_meta_ref().get_bytes().to_vec();
647
648 let mut resolver = MetaReaderResolver::default();
649 read_type_def_with_type_resolver(&mut resolver, &config, &type_resolver, &exact).unwrap();
650
651 let namespace = NAMESPACE_ENCODER
652 .encode_with_encodings("example", NAMESPACE_ENCODINGS)
653 .unwrap();
654 let type_name = TYPE_NAME_ENCODER
655 .encode_with_encodings("SharedExt", TYPE_NAME_ENCODINGS)
656 .unwrap();
657 let second = TypeMeta::new(
658 TypeId::NAMED_ENUM as u32,
659 NO_USER_TYPE_ID,
660 namespace,
661 type_name,
662 true,
663 vec![],
664 )
665 .unwrap();
666 resolver
667 .check_remote_type_meta_limit(&second, &config)
668 .unwrap();
669 }
670}