Skip to main content

wire/
limits.rs

1//! Configurable limits for bounded decoding.
2
3/// Wire-level limits for packet decoding.
4///
5/// These limits are enforced during decoding to prevent resource exhaustion
6/// attacks and ensure bounded memory usage. Section body parsing limits
7/// belong to higher layers (codec/schema).
8#[derive(Debug, Clone, PartialEq, Eq)]
9pub struct Limits {
10    /// Maximum packet size in bytes.
11    pub max_packet_bytes: usize,
12
13    /// Maximum number of sections in a packet.
14    pub max_sections: usize,
15
16    /// Maximum length of a single section body in bytes.
17    pub max_section_len: usize,
18}
19
20impl Default for Limits {
21    fn default() -> Self {
22        Self {
23            // 64 KB is generous for most realtime scenarios
24            max_packet_bytes: 64 * 1024,
25
26            // Typically only 3 sections (create, update, destroy)
27            max_sections: 16,
28            max_section_len: 32 * 1024,
29        }
30    }
31}
32
33impl Limits {
34    /// Creates limits suitable for testing with smaller values.
35    #[must_use]
36    pub const fn for_testing() -> Self {
37        Self {
38            max_packet_bytes: 4096,
39            max_sections: 8,
40            max_section_len: 1024,
41        }
42    }
43
44    /// Creates limits with no restrictions (use with caution).
45    #[must_use]
46    pub const fn unlimited() -> Self {
47        Self {
48            max_packet_bytes: usize::MAX,
49            max_sections: usize::MAX,
50            max_section_len: usize::MAX,
51        }
52    }
53}
54
55#[cfg(test)]
56mod tests {
57    use super::*;
58
59    #[test]
60    fn default_limits_packet_bytes() {
61        let limits = Limits::default();
62        assert_eq!(limits.max_packet_bytes, 64 * 1024);
63    }
64
65    #[test]
66    fn default_limits_sections() {
67        let limits = Limits::default();
68        assert_eq!(limits.max_sections, 16);
69    }
70
71    #[test]
72    fn testing_limits_smaller() {
73        let test_limits = Limits::for_testing();
74        let default_limits = Limits::default();
75
76        assert!(test_limits.max_packet_bytes < default_limits.max_packet_bytes);
77        assert!(test_limits.max_sections < default_limits.max_sections);
78        assert!(test_limits.max_section_len < default_limits.max_section_len);
79    }
80
81    #[test]
82    fn testing_limits_values() {
83        let limits = Limits::for_testing();
84        assert_eq!(limits.max_packet_bytes, 4096);
85        assert_eq!(limits.max_sections, 8);
86        assert_eq!(limits.max_section_len, 1024);
87    }
88
89    #[test]
90    fn unlimited_limits() {
91        let limits = Limits::unlimited();
92        assert_eq!(limits.max_packet_bytes, usize::MAX);
93        assert_eq!(limits.max_sections, usize::MAX);
94        assert_eq!(limits.max_section_len, usize::MAX);
95    }
96
97    #[test]
98    fn limits_equality() {
99        let l1 = Limits::default();
100        let l2 = Limits::default();
101        let l3 = Limits::for_testing();
102
103        assert_eq!(l1, l2);
104        assert_ne!(l1, l3);
105    }
106
107    #[test]
108    fn limits_clone() {
109        let limits = Limits::default();
110        let cloned = limits.clone();
111        assert_eq!(limits, cloned);
112    }
113
114    #[test]
115    fn limits_debug() {
116        let limits = Limits::default();
117        let debug = format!("{limits:?}");
118        assert!(debug.contains("Limits"));
119        assert!(debug.contains("max_packet_bytes"));
120    }
121
122    #[test]
123    fn limits_const_constructible() {
124        const LIMITS: Limits = Limits::for_testing();
125        assert_eq!(LIMITS.max_packet_bytes, 4096);
126    }
127}