1use core::fmt;
10
11use minicbor::Decoder;
12use minicbor::data::Type;
13
14use crate::message::{Message, Method, kind};
15
16pub const HEADER_LEN: usize = 4;
18
19pub const DEFAULT_MAX_FRAME: u32 = 16 * 1024 * 1024;
22
23pub const MIN_MAX_FRAME: u32 = 4 * 1024;
26
27const PEEK_LEN: usize = 32;
30
31pub fn write_frame(msg: &Message, limit: u32, out: &mut Vec<u8>) -> Result<(), FrameTooLarge> {
34 let start = out.len();
35 out.extend_from_slice(&[0; HEADER_LEN]);
36 msg.encode(out);
37 let size = out.len() - start - HEADER_LEN;
38 match u32::try_from(size) {
39 Ok(len) if len <= limit => {
40 out[start..start + HEADER_LEN].copy_from_slice(&len.to_be_bytes());
41 Ok(())
42 }
43 _ => {
44 out.truncate(start);
45 Err(FrameTooLarge { size, limit })
46 }
47 }
48}
49
50#[derive(Clone, Copy, Debug, PartialEq, Eq)]
52pub struct FrameTooLarge {
53 pub size: usize,
55 pub limit: u32,
56}
57
58impl fmt::Display for FrameTooLarge {
59 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
60 write!(
61 f,
62 "a frame of {} bytes exceeds the maximum frame size of {} bytes",
63 self.size, self.limit
64 )
65 }
66}
67
68impl std::error::Error for FrameTooLarge {}
69
70#[derive(Clone, Copy, Debug, PartialEq, Eq)]
74pub struct Oversized {
75 pub size: u32,
77 pub limit: u32,
78 pub kind: Option<u8>,
80 pub id: Option<u32>,
82 pub method: Option<Method>,
84}
85
86impl fmt::Display for Oversized {
87 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
88 write!(f, "a frame of {} bytes", self.size)?;
89 match (self.kind, self.method, self.id) {
90 (Some(k), Some(method), Some(id)) => {
91 write!(f, " ({method} {} for request {id})", kind::name(k))?;
92 }
93 (Some(k), None, Some(id)) => write!(f, " ({} for request {id})", kind::name(k))?,
94 (Some(k), _, None) => write!(f, " ({})", kind::name(k))?,
95 (None, ..) => {}
96 }
97 write!(
98 f,
99 " exceeds the maximum frame size of {} bytes; its payload was discarded",
100 self.limit
101 )
102 }
103}
104
105impl std::error::Error for Oversized {}
106
107#[derive(Debug)]
109pub struct FrameDecoder {
110 limit: u32,
111 buf: Vec<u8>,
112 start: usize,
114 discard: u64,
116}
117
118impl FrameDecoder {
119 pub fn new(limit: u32) -> FrameDecoder {
120 FrameDecoder {
121 limit,
122 buf: Vec::new(),
123 start: 0,
124 discard: 0,
125 }
126 }
127
128 pub fn limit(&self) -> u32 {
129 self.limit
130 }
131
132 pub fn set_limit(&mut self, limit: u32) {
134 self.limit = limit;
135 }
136
137 pub fn push(&mut self, bytes: &[u8]) {
139 let mut bytes = bytes;
140 if self.discard > 0 {
141 let n = usize::try_from(self.discard).map_or(bytes.len(), |d| d.min(bytes.len()));
142 self.discard -= n as u64;
143 bytes = &bytes[n..];
144 }
145 if bytes.is_empty() {
146 return;
147 }
148 if self.start > 0 {
149 self.buf.drain(..self.start);
150 self.start = 0;
151 }
152 self.buf.extend_from_slice(bytes);
153 }
154
155 pub fn next_frame(&mut self) -> Option<Result<&[u8], Oversized>> {
158 if self.discard > 0 || self.buf.len() - self.start < HEADER_LEN {
159 return None;
160 }
161 let body = self.start + HEADER_LEN;
162 let header: [u8; HEADER_LEN] = self.buf[self.start..body]
163 .try_into()
164 .expect("the header is HEADER_LEN bytes");
165 let declared = u32::from_be_bytes(header);
166 let len = declared as usize;
167 let have = self.buf.len() - body;
168 if declared > self.limit {
169 let wanted = len.min(PEEK_LEN);
170 if have < wanted {
171 return None;
172 }
173 let (kind, id, method) = peek(&self.buf[body..body + wanted]);
174 let taken = have.min(len);
175 self.start = body + taken;
176 self.discard = u64::from(declared) - taken as u64;
177 return Some(Err(Oversized {
178 size: declared,
179 limit: self.limit,
180 kind,
181 id,
182 method,
183 }));
184 }
185 if have < len {
186 self.buf.reserve(len - have);
187 return None;
188 }
189 self.start = body + len;
190 Some(Ok(&self.buf[body..body + len]))
191 }
192
193 pub fn is_discarding(&self) -> bool {
195 self.discard > 0
196 }
197
198 pub fn buffered(&self) -> usize {
200 self.buf.len() - self.start
201 }
202}
203
204fn peek(prefix: &[u8]) -> (Option<u8>, Option<u32>, Option<Method>) {
208 let mut d = Decoder::new(prefix);
209 match d.datatype() {
210 Ok(Type::Map | Type::MapIndef) => {
211 let Ok(len) = d.map() else {
212 return (None, None, None);
213 };
214 let mut found_kind = None;
215 let mut id = None;
216 let mut method = None;
217 for _ in 0..len.unwrap_or(u64::MAX).min(3) {
218 let Ok(key) = d.i64() else { break };
219 let read = match key {
220 0 => d.u8().map(|k| found_kind = Some(k)),
221 1 => d.u32().map(|v| id = Some(v)),
222 2 => d.u16().map(|m| method = Some(Method(m))),
223 _ => d.skip(),
224 };
225 if read.is_err() {
226 break;
227 }
228 }
229 if matches!(found_kind, Some(kind::REQUEST | kind::RESPONSE)) {
230 (found_kind, id, method)
231 } else {
232 (found_kind, None, None)
233 }
234 }
235 Ok(Type::Array | Type::ArrayIndef) => match d.array() {
236 Ok(_) => (d.u8().ok(), None, None),
237 Err(_) => (None, None, None),
238 },
239 _ => (None, None, None),
240 }
241}