1use core::fmt;
4
5use crate::error::{FormError, Limit, Location};
6use crate::limits::{Limits, PercentPolicy};
7use crate::urlencoded::decode::decode_component;
8
9const HAS_EQUALS: u8 = 1;
10const NAME_DECODE: u8 = 2;
11const VALUE_DECODE: u8 = 4;
12
13#[must_use]
32pub fn raw_pairs<'a>(input: &'a [u8], limits: &Limits) -> RawPairs<'a> {
33 RawPairs {
34 input,
35 pos: 0,
36 budget: Budget::new(limits),
37 done: false,
38 checked_body: false,
39 }
40}
41
42#[derive(Clone, Copy, Debug)]
45pub(crate) struct Budget {
46 pub(crate) limits: Limits,
47 fields: u32,
48 text: u64,
49}
50
51impl Budget {
52 pub(crate) const fn new(limits: &Limits) -> Budget {
53 Budget {
54 limits: *limits,
55 fields: 0,
56 text: 0,
57 }
58 }
59
60 pub(crate) fn admit(&mut self, pair: &RawPair<'_>) -> Result<(), FormError> {
63 let at = Location::at(pair.offset);
64 self.fields = self.fields.saturating_add(1);
65 if self.fields > self.limits.max_fields {
66 return Err(FormError::limit(Limit::Fields, at));
67 }
68 if pair.name.len() as u64 > u64::from(self.limits.name()) {
69 return Err(FormError::limit(Limit::NameLength, at));
70 }
71 let value_at = pair.value_offset();
72 if pair.value.len() as u64 > u64::from(self.limits.value()) {
73 return Err(FormError::limit(Limit::ValueLength, value_at));
74 }
75 self.text = self.text.saturating_add(pair.value.len() as u64);
76 if self.text > self.limits.text() {
77 return Err(FormError::limit(Limit::TextTotal, value_at));
78 }
79 Ok(())
80 }
81
82 pub(crate) fn admit_partial(
87 &self,
88 offset: u64,
89 name_len: usize,
90 has_equals: bool,
91 value_len: usize,
92 ) -> Result<(), FormError> {
93 let name_over = name_len as u64 > u64::from(self.limits.name());
94 let value_over = has_equals && value_len as u64 > u64::from(self.limits.value());
95 if !name_over && !value_over {
96 return Ok(());
97 }
98 if self.fields.saturating_add(1) > self.limits.max_fields {
99 return Err(FormError::limit(Limit::Fields, Location::at(offset)));
100 }
101 if name_over {
102 return Err(FormError::limit(Limit::NameLength, Location::at(offset)));
103 }
104 let value_at = offset.saturating_add(name_len as u64).saturating_add(1);
105 Err(FormError::limit(Limit::ValueLength, Location::at(value_at)))
106 }
107
108 pub(crate) fn reset(&mut self) {
109 self.fields = 0;
110 self.text = 0;
111 }
112}
113
114#[derive(Clone)]
116pub struct RawPairs<'a> {
117 input: &'a [u8],
118 pos: usize,
119 budget: Budget,
120 done: bool,
121 checked_body: bool,
122}
123
124impl fmt::Debug for RawPairs<'_> {
125 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
126 f.debug_struct("RawPairs")
127 .field("position", &self.pos)
128 .field("fields", &self.budget.fields)
129 .finish_non_exhaustive()
130 }
131}
132
133impl<'a> RawPairs<'a> {
134 fn fail(&mut self, err: FormError) -> Option<Result<RawPair<'a>, FormError>> {
135 self.done = true;
136 Some(Err(err))
137 }
138}
139
140impl<'a> Iterator for RawPairs<'a> {
141 type Item = Result<RawPair<'a>, FormError>;
142
143 fn next(&mut self) -> Option<Self::Item> {
144 if self.done {
145 return None;
146 }
147 if !self.checked_body {
148 self.checked_body = true;
149 if self.input.len() > self.budget.limits.body_usize() {
150 return self.fail(FormError::limit(
151 Limit::Body,
152 Location::at(self.budget.limits.body()),
153 ));
154 }
155 }
156 loop {
157 if self.pos >= self.input.len() {
158 self.done = true;
159 return None;
160 }
161 let start = self.pos;
162 let mut flags = 0u8;
163 let mut eq = None;
164 let mut i = start;
165 let end = loop {
166 i = crate::scan::find_any(self.input, i, *b"&=%+");
167 match self.input.get(i) {
168 None | Some(b'&') => break i,
169 Some(b'=') if eq.is_none() => {
170 eq = Some(i);
171 flags |= HAS_EQUALS;
172 }
173 Some(b'%' | b'+') => {
174 flags |= if eq.is_some() {
175 VALUE_DECODE
176 } else {
177 NAME_DECODE
178 };
179 }
180 Some(_) => {}
181 }
182 i = i.wrapping_add(1);
183 };
184 self.pos = end.saturating_add(1).min(self.input.len());
185 if end == start {
186 continue;
187 }
188 let seq = self.input.get(start..end).unwrap_or(&[]);
189 let (name, value) = match eq {
190 Some(e) => {
191 let at = e.wrapping_sub(start);
192 (
193 seq.get(..at).unwrap_or(&[]),
194 seq.get(at.wrapping_add(1)..).unwrap_or(&[]),
195 )
196 }
197 None => (seq, &[][..]),
198 };
199 let pair = RawPair {
200 name,
201 value,
202 flags,
203 offset: start as u64,
204 };
205 if let Err(e) = self.budget.admit(&pair) {
206 return self.fail(e);
207 }
208 return Some(Ok(pair));
209 }
210 }
211}
212
213impl core::iter::FusedIterator for RawPairs<'_> {}
214
215#[derive(Clone, Copy)]
219pub struct RawPair<'a> {
220 name: &'a [u8],
221 value: &'a [u8],
222 flags: u8,
223 offset: u64,
224}
225
226impl fmt::Debug for RawPair<'_> {
227 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
228 f.debug_struct("RawPair")
229 .field("offset", &self.offset)
230 .field("name_len", &self.name.len())
231 .field("value_len", &self.value.len())
232 .finish()
233 }
234}
235
236impl<'a> RawPair<'a> {
237 pub(crate) fn split(seq: &'a [u8], offset: u64) -> RawPair<'a> {
239 let mut flags = 0u8;
240 let mut eq = None;
241 let mut i = 0usize;
242 loop {
243 i = crate::scan::find_any(seq, i, *b"&=%+");
244 match seq.get(i) {
245 None => break,
246 Some(b'=') if eq.is_none() => {
247 eq = Some(i);
248 flags |= HAS_EQUALS;
249 }
250 Some(b'%' | b'+') => {
251 flags |= if eq.is_some() {
252 VALUE_DECODE
253 } else {
254 NAME_DECODE
255 };
256 }
257 Some(_) => {}
258 }
259 i = i.wrapping_add(1);
260 }
261 let (name, value) = match eq {
262 Some(e) => (
263 seq.get(..e).unwrap_or(&[]),
264 seq.get(e.wrapping_add(1)..).unwrap_or(&[]),
265 ),
266 None => (seq, &[][..]),
267 };
268 RawPair {
269 name,
270 value,
271 flags,
272 offset,
273 }
274 }
275
276 fn value_offset(&self) -> Location {
277 Location::at(
278 self.offset
279 .saturating_add(self.name.len() as u64)
280 .saturating_add(1),
281 )
282 }
283
284 #[must_use]
294 pub const fn name_raw(&self) -> &'a [u8] {
295 self.name
296 }
297
298 #[must_use]
308 pub const fn value_raw(&self) -> &'a [u8] {
309 self.value
310 }
311
312 #[must_use]
326 pub const fn has_equals(&self) -> bool {
327 self.flags & HAS_EQUALS != 0
328 }
329
330 #[must_use]
340 pub const fn name_needs_decoding(&self) -> bool {
341 self.flags & NAME_DECODE != 0
342 }
343
344 #[must_use]
354 pub const fn value_needs_decoding(&self) -> bool {
355 self.flags & VALUE_DECODE != 0
356 }
357
358 #[must_use]
368 pub fn name_str(&self) -> Option<&'a str> {
369 if self.name_needs_decoding() {
370 None
371 } else {
372 core::str::from_utf8(self.name).ok()
373 }
374 }
375
376 #[must_use]
386 pub fn value_str(&self) -> Option<&'a str> {
387 if self.value_needs_decoding() {
388 None
389 } else {
390 core::str::from_utf8(self.value).ok()
391 }
392 }
393
394 pub fn decode_name<'b>(
412 &self,
413 out: &'b mut [u8],
414 policy: PercentPolicy,
415 ) -> Result<&'b str, FormError> {
416 decode_component(self.name, out, policy).map_err(|e| e.shifted(self.offset))
417 }
418
419 pub fn decode_value<'b>(
436 &self,
437 out: &'b mut [u8],
438 policy: PercentPolicy,
439 ) -> Result<&'b str, FormError> {
440 let at = self
441 .offset
442 .saturating_add(self.name.len() as u64)
443 .saturating_add(1);
444 decode_component(self.value, out, policy).map_err(|e| e.shifted(at))
445 }
446
447 #[must_use]
458 pub const fn offset(&self) -> u64 {
459 self.offset
460 }
461}
462
463#[cfg(test)]
464mod tests {
465 use super::*;
466 use alloc::vec::Vec;
467
468 type Pairs<'a> = Vec<(&'a [u8], &'a [u8])>;
469
470 fn pairs(input: &[u8]) -> Result<Pairs<'_>, FormError> {
471 raw_pairs(input, &Limits::DEFAULT)
472 .map(|p| p.map(|p| (p.name_raw(), p.value_raw())))
473 .collect()
474 }
475
476 #[test]
477 fn test_raw_pairs_whatwg_splitting() {
478 assert_eq!(pairs(b"").unwrap(), []);
479 assert_eq!(pairs(b"&&&").unwrap(), []);
480 assert_eq!(pairs(b"=").unwrap(), [(&b""[..], &b""[..])]);
481 assert_eq!(pairs(b"a==b").unwrap(), [(&b"a"[..], &b"=b"[..])]);
482 assert_eq!(pairs(b"=a").unwrap(), [(&b""[..], &b"a"[..])]);
483 assert_eq!(pairs(b"a;b=c").unwrap(), [(&b"a;b"[..], &b"c"[..])]);
484 assert_eq!(
485 pairs(b"a=1&b=2&").unwrap(),
486 [(&b"a"[..], &b"1"[..]), (&b"b"[..], &b"2"[..])]
487 );
488 }
489
490 #[test]
491 fn test_raw_pairs_flags_per_side() {
492 let p = raw_pairs(b"a%=b", &Limits::DEFAULT)
493 .next()
494 .unwrap()
495 .unwrap();
496 assert!(p.name_needs_decoding() && !p.value_needs_decoding());
497 let p = raw_pairs(b"a=b+%", &Limits::DEFAULT)
498 .next()
499 .unwrap()
500 .unwrap();
501 assert!(!p.name_needs_decoding() && p.value_needs_decoding());
502 let p = raw_pairs(b"a=b=+", &Limits::DEFAULT)
503 .next()
504 .unwrap()
505 .unwrap();
506 assert!(p.value_needs_decoding() && p.has_equals());
507 }
508
509 #[test]
510 fn test_raw_pairs_field_limit_n_and_n_plus_one() {
511 let l = Limits::DEFAULT.with_max_fields(2);
512 assert_eq!(raw_pairs(b"a&b", &l).count(), 2);
513 let r: Result<Vec<_>, _> = raw_pairs(b"a&b&c", &l).collect();
514 assert!(matches!(
515 r,
516 Err(FormError::Limit {
517 limit: Limit::Fields,
518 at
519 }) if at.offset == 4
520 ));
521 }
522
523 #[test]
524 fn test_raw_pairs_length_limits_at_the_edge() {
525 let l = Limits::DEFAULT
526 .with_max_name_bytes(3)
527 .with_max_value_bytes(3);
528 assert!(raw_pairs(b"abc=def", &l).all(|p| p.is_ok()));
529 let e = raw_pairs(b"abcd=1", &l).next().unwrap().unwrap_err();
530 assert!(matches!(
531 e,
532 FormError::Limit {
533 limit: Limit::NameLength,
534 ..
535 }
536 ));
537 let e = raw_pairs(b"a=defg", &l).next().unwrap().unwrap_err();
538 assert!(matches!(e, FormError::Limit { limit: Limit::ValueLength, at } if at.offset == 2));
539 let l = Limits::DEFAULT.with_max_text_bytes(4);
540 let r: Result<Vec<_>, _> = raw_pairs(b"a=12&b=345", &l).collect();
541 assert!(matches!(
542 r,
543 Err(FormError::Limit {
544 limit: Limit::TextTotal,
545 ..
546 })
547 ));
548 }
549
550 #[test]
551 fn test_raw_pairs_body_limit_counts_empty_sequences() {
552 let l = Limits::DEFAULT.with_max_body_bytes(4);
553 assert_eq!(raw_pairs(b"&&&&", &l).count(), 0);
554 let e = raw_pairs(b"&&&&&", &l).next().unwrap().unwrap_err();
555 assert!(matches!(
556 e,
557 FormError::Limit {
558 limit: Limit::Body,
559 ..
560 }
561 ));
562 }
563
564 #[test]
565 fn test_raw_pairs_stops_after_error() {
566 let l = Limits::DEFAULT.with_max_fields(0);
567 let mut it = raw_pairs(b"a&b", &l);
568 assert!(it.next().unwrap().is_err());
569 assert!(it.next().is_none());
570 }
571
572 #[test]
573 fn test_raw_pair_debug_hides_values() {
574 let p = raw_pairs(b"password=hunter2", &Limits::DEFAULT)
575 .next()
576 .unwrap()
577 .unwrap();
578 let s = alloc::format!("{p:?}");
579 assert!(!s.contains("hunter2") && !s.contains("password"));
580 }
581}