1use core::fmt;
5
6use crate::error::{FormError, Limit, Location};
7use crate::limits::Limits;
8use crate::urlencoded::raw::{Budget, RawPair};
9
10pub struct UrlencodedParser<B: AsMut<[u8]> + AsRef<[u8]>> {
44 scratch: B,
45 held: usize,
47 held_at: u64,
49 release: bool,
51 seen: u64,
53 budget: Budget,
54 poisoned: bool,
55 ended: bool,
56}
57
58impl<B: AsMut<[u8]> + AsRef<[u8]>> fmt::Debug for UrlencodedParser<B> {
59 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
60 f.debug_struct("UrlencodedParser")
61 .field("bytes_seen", &self.seen)
62 .field("held", &self.held)
63 .field("ended", &self.ended)
64 .finish_non_exhaustive()
65 }
66}
67
68#[non_exhaustive]
71#[derive(Debug)]
72pub struct UrlencodedStep<'p> {
73 pub consumed: usize,
75 pub event: UrlencodedEvent<'p>,
77}
78
79#[non_exhaustive]
81#[derive(Clone, Copy, Debug)]
82pub enum UrlencodedEvent<'p> {
83 Pair(RawPair<'p>),
85 NeedInput,
87 End,
89}
90
91enum Found {
93 Input { start: usize, end: usize, at: u64 },
94 Scratch { len: usize, at: u64 },
95 NeedInput,
96 End,
97}
98
99impl<B: AsMut<[u8]> + AsRef<[u8]>> UrlencodedParser<B> {
100 pub fn with_buffer(limits: &Limits, scratch: B) -> Result<Self, FormError> {
107 limits.validate()?;
108 let needed = limits.urlencoded_buffer_len();
109 if scratch.as_ref().len() < needed {
110 return Err(FormError::BufferTooSmall { needed });
111 }
112 Ok(UrlencodedParser {
113 scratch,
114 held: 0,
115 held_at: 0,
116 release: false,
117 seen: 0,
118 budget: Budget::new(limits),
119 poisoned: false,
120 ended: false,
121 })
122 }
123
124 pub fn parse<'p>(
132 &'p mut self,
133 input: &'p [u8],
134 eof: bool,
135 ) -> Result<UrlencodedStep<'p>, FormError> {
136 if self.poisoned {
137 return Err(FormError::Poisoned);
138 }
139 if self.release {
140 self.release = false;
141 self.clear_held();
142 }
143 let (consumed, found) = match self.step(input, eof) {
144 Ok(r) => r,
145 Err(e) => {
146 self.poisoned = true;
147 self.clear_held();
148 return Err(e);
149 }
150 };
151 let event = match found {
152 Found::Input { start, end, at } => {
153 UrlencodedEvent::Pair(RawPair::split(input.get(start..end).unwrap_or(&[]), at))
154 }
155 Found::Scratch { len, at } => {
156 self.release = true;
157 let seq = self.scratch.as_ref().get(..len).unwrap_or(&[]);
158 UrlencodedEvent::Pair(RawPair::split(seq, at))
159 }
160 Found::NeedInput => UrlencodedEvent::NeedInput,
161 Found::End => UrlencodedEvent::End,
162 };
163 Ok(UrlencodedStep { consumed, event })
164 }
165
166 pub fn reset(&mut self) {
169 crate::wipe::wipe(self.scratch.as_mut());
170 self.held = 0;
171 self.held_at = 0;
172 self.release = false;
173 self.seen = 0;
174 self.budget.reset();
175 self.poisoned = false;
176 self.ended = false;
177 }
178
179 #[must_use]
181 pub const fn bytes_seen(&self) -> u64 {
182 self.seen
183 }
184
185 fn clear_held(&mut self) {
186 if let Some(held) = self.scratch.as_mut().get_mut(..self.held) {
187 crate::wipe::wipe(held);
188 }
189 self.held = 0;
190 }
191
192 fn step(&mut self, input: &[u8], eof: bool) -> Result<(usize, Found), FormError> {
193 if self.ended {
194 return Ok((0, Found::End));
195 }
196 let body = self.budget.limits.body();
197 let mut pos = 0usize;
198 loop {
199 let rest = input.get(pos..).unwrap_or(&[]);
200 let allowed = usize::try_from(body.saturating_sub(self.seen)).unwrap_or(usize::MAX);
201 let window = rest.get(..allowed.min(rest.len())).unwrap_or(&[]);
202 let over = rest.len() > window.len();
203 let amp = crate::scan::find_any(window, 0, *b"&&&&").min(window.len());
204 let terminated = amp < window.len();
205 let piece = window.get(..amp).unwrap_or(&[]);
206 if !terminated && (!eof || over) {
207 self.check_partial(piece)?;
210 if over {
211 return Err(FormError::limit(Limit::Body, Location::at(body)));
212 }
213 self.hold(piece);
214 pos = pos.saturating_add(piece.len());
215 self.seen = self.seen.saturating_add(piece.len() as u64);
216 return Ok((pos, Found::NeedInput));
217 }
218 let start = pos;
221 let at = self.seen;
222 let seq_len = self.held.saturating_add(piece.len());
223 pos = pos.saturating_add(piece.len());
224 self.seen = self.seen.saturating_add(piece.len() as u64);
225 if terminated {
226 pos = pos.saturating_add(1);
227 self.seen = self.seen.saturating_add(1);
228 }
229 if seq_len == 0 {
230 if terminated {
231 continue;
232 }
233 self.ended = true;
234 return Ok((pos, Found::End));
235 }
236 if self.held == 0 {
237 self.budget.admit(&RawPair::split(piece, at))?;
238 return Ok((
239 pos,
240 Found::Input {
241 start,
242 end: start.saturating_add(piece.len()),
243 at,
244 },
245 ));
246 }
247 self.check_partial(piece)?;
249 self.hold(piece);
250 let at = self.held_at;
251 let len = self.held;
252 let seq = self.scratch.as_ref().get(..len).unwrap_or(&[]);
253 self.budget.admit(&RawPair::split(seq, at))?;
254 return Ok((pos, Found::Scratch { len, at }));
255 }
256 }
257
258 fn check_partial(&self, more: &[u8]) -> Result<(), FormError> {
261 let held = self.scratch.as_ref().get(..self.held).unwrap_or(&[]);
262 let at = if self.held == 0 {
263 self.seen
264 } else {
265 self.held_at
266 };
267 let (name_len, has_equals, value_len) = match held.iter().position(|&b| b == b'=') {
268 Some(e) => (
269 e,
270 true,
271 held.len()
272 .saturating_sub(e)
273 .saturating_sub(1)
274 .saturating_add(more.len()),
275 ),
276 None => match more.iter().position(|&b| b == b'=') {
277 Some(e) => (
278 held.len().saturating_add(e),
279 true,
280 more.len().saturating_sub(e).saturating_sub(1),
281 ),
282 None => (held.len().saturating_add(more.len()), false, 0),
283 },
284 };
285 self.budget
286 .admit_partial(at, name_len, has_equals, value_len)
287 }
288
289 fn hold(&mut self, bytes: &[u8]) {
292 if bytes.is_empty() {
293 return;
294 }
295 if self.held == 0 {
296 self.held_at = self.seen;
297 }
298 let start = self.held;
299 let end = start.saturating_add(bytes.len());
300 if let Some(dst) = self.scratch.as_mut().get_mut(start..end) {
301 dst.copy_from_slice(bytes);
302 self.held = end;
303 }
304 }
305}
306
307impl<B: AsMut<[u8]> + AsRef<[u8]>> Drop for UrlencodedParser<B> {
308 fn drop(&mut self) {
309 crate::wipe::wipe(self.scratch.as_mut());
310 }
311}
312
313#[cfg(feature = "alloc")]
314impl UrlencodedParser<alloc::vec::Vec<u8>> {
315 pub fn new(limits: &Limits) -> Result<Self, FormError> {
332 limits.validate()?;
333 Self::with_buffer(limits, alloc::vec![0u8; limits.urlencoded_buffer_len()])
334 }
335}