1use core::fmt;
4
5use crate::error::{EncodingError, 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 max_fields: u32,
49 max_name: u32,
50 max_value: u32,
51 max_text: u64,
52 pub(crate) body: u64,
53 fields: u32,
54 text: u64,
55}
56
57impl Budget {
58 pub(crate) const fn new(limits: &Limits) -> Budget {
59 Budget {
60 max_fields: limits.max_fields,
61 max_name: limits.name(),
62 max_value: limits.value(),
63 max_text: limits.text(),
64 body: limits.body(),
65 fields: 0,
66 text: 0,
67 }
68 }
69
70 pub(crate) fn admit(&mut self, pair: &RawPair<'_>) -> Result<(), FormError> {
73 let at = Location::at(pair.offset);
74 self.fields = self.fields.saturating_add(1);
75 if self.fields > self.max_fields {
76 return Err(FormError::limit(Limit::Fields, at));
77 }
78 if pair.name.len() as u64 > u64::from(self.max_name) {
79 return Err(FormError::limit(Limit::NameLength, at));
80 }
81 let value_at = pair.value_offset();
82 if pair.value.len() as u64 > u64::from(self.max_value) {
83 return Err(FormError::limit(Limit::ValueLength, value_at));
84 }
85 self.text = self.text.saturating_add(pair.value.len() as u64);
86 if self.text > self.max_text {
87 return Err(FormError::limit(Limit::TextTotal, value_at));
88 }
89 Ok(())
90 }
91
92 pub(crate) fn admit_partial(
97 &self,
98 offset: u64,
99 name_len: usize,
100 has_equals: bool,
101 value_len: usize,
102 ) -> Result<(), FormError> {
103 let name_over = name_len as u64 > u64::from(self.max_name);
104 let value_over = has_equals && value_len as u64 > u64::from(self.max_value);
105 if !name_over && !value_over {
106 return Ok(());
107 }
108 if self.fields.saturating_add(1) > self.max_fields {
109 return Err(FormError::limit(Limit::Fields, Location::at(offset)));
110 }
111 if name_over {
112 return Err(FormError::limit(Limit::NameLength, Location::at(offset)));
113 }
114 let value_at = offset.saturating_add(name_len as u64).saturating_add(1);
115 Err(FormError::limit(Limit::ValueLength, Location::at(value_at)))
116 }
117
118 pub(crate) fn reset(&mut self) {
119 self.fields = 0;
120 self.text = 0;
121 }
122}
123
124#[inline]
130fn scan(input: &[u8], start: usize) -> (usize, Option<usize>, u8) {
131 let mut flags = 0u8;
132 let mut i = start;
133 let eq = loop {
135 i = if flags & NAME_DECODE == 0 {
136 crate::scan::find_any(input, i, *b"&=%+")
137 } else {
138 crate::scan::find_any(input, i, *b"&=")
139 };
140 match input.get(i) {
141 None | Some(b'&') => return (i, None, flags),
142 Some(b'=') => break i,
143 Some(_) => flags |= NAME_DECODE,
144 }
145 i = i.wrapping_add(1);
146 };
147 flags |= HAS_EQUALS;
148 i = eq.wrapping_add(1);
149 loop {
151 i = if flags & VALUE_DECODE == 0 {
152 crate::scan::find_any(input, i, *b"&%+")
153 } else {
154 crate::scan::find_byte(input, i, b'&')
155 };
156 match input.get(i) {
157 None | Some(b'&') => return (i, Some(eq), flags),
158 Some(_) => flags |= VALUE_DECODE,
159 }
160 i = i.wrapping_add(1);
161 }
162}
163
164#[derive(Clone)]
166pub struct RawPairs<'a> {
167 input: &'a [u8],
168 pos: usize,
169 budget: Budget,
170 done: bool,
171 checked_body: bool,
172}
173
174impl fmt::Debug for RawPairs<'_> {
175 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
176 f.debug_struct("RawPairs")
177 .field("position", &self.pos)
178 .field("fields", &self.budget.fields)
179 .finish_non_exhaustive()
180 }
181}
182
183impl<'a> RawPairs<'a> {
184 fn fail(&mut self, err: FormError) -> Option<Result<RawPair<'a>, FormError>> {
185 self.done = true;
186 Some(Err(err))
187 }
188}
189
190impl<'a> Iterator for RawPairs<'a> {
191 type Item = Result<RawPair<'a>, FormError>;
192
193 fn next(&mut self) -> Option<Self::Item> {
194 if self.done {
195 return None;
196 }
197 if !self.checked_body {
198 self.checked_body = true;
199 if self.input.len() as u64 > self.budget.body {
200 return self.fail(FormError::limit(
201 Limit::Body,
202 Location::at(self.budget.body),
203 ));
204 }
205 }
206 loop {
207 if self.pos >= self.input.len() {
208 self.done = true;
209 return None;
210 }
211 let start = self.pos;
212 let (end, eq, flags) = scan(self.input, start);
213 self.pos = end.saturating_add(1).min(self.input.len());
214 if end == start {
215 continue;
216 }
217 let seq = self.input.get(start..end).unwrap_or(&[]);
218 let (name, value) = match eq {
219 Some(e) => {
220 let at = e.wrapping_sub(start);
221 (
222 seq.get(..at).unwrap_or(&[]),
223 seq.get(at.wrapping_add(1)..).unwrap_or(&[]),
224 )
225 }
226 None => (seq, &[][..]),
227 };
228 let pair = RawPair {
229 name,
230 value,
231 flags,
232 offset: start as u64,
233 };
234 if let Err(e) = self.budget.admit(&pair) {
235 return self.fail(e);
236 }
237 return Some(Ok(pair));
238 }
239 }
240}
241
242impl core::iter::FusedIterator for RawPairs<'_> {}
243
244#[derive(Clone, Copy)]
248pub struct RawPair<'a> {
249 name: &'a [u8],
250 value: &'a [u8],
251 flags: u8,
252 offset: u64,
253}
254
255impl fmt::Debug for RawPair<'_> {
256 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
257 f.debug_struct("RawPair")
258 .field("offset", &self.offset)
259 .field("name_len", &self.name.len())
260 .field("value_len", &self.value.len())
261 .finish()
262 }
263}
264
265impl<'a> RawPair<'a> {
266 pub(crate) fn split(seq: &'a [u8], offset: u64) -> RawPair<'a> {
268 let (_, eq, flags) = scan(seq, 0);
269 let (name, value) = match eq {
270 Some(e) => (
271 seq.get(..e).unwrap_or(&[]),
272 seq.get(e.wrapping_add(1)..).unwrap_or(&[]),
273 ),
274 None => (seq, &[][..]),
275 };
276 RawPair {
277 name,
278 value,
279 flags,
280 offset,
281 }
282 }
283
284 #[cfg(feature = "alloc")]
289 #[inline]
290 pub(crate) fn name_text(&self, whole: Option<&'a str>) -> Option<&'a str> {
291 if self.name_needs_decoding() {
292 return None;
293 }
294 let start = usize::try_from(self.offset).ok()?;
295 match whole {
296 Some(w) => w.get(start..start.checked_add(self.name.len())?),
297 None => core::str::from_utf8(self.name).ok(),
298 }
299 }
300
301 #[cfg(feature = "alloc")]
303 #[inline]
304 pub(crate) fn value_text(&self, whole: Option<&'a str>) -> Option<&'a str> {
305 if self.value_needs_decoding() {
306 return None;
307 }
308 if self.value.is_empty() {
309 return Some("");
310 }
311 let start = usize::try_from(self.offset)
312 .ok()?
313 .checked_add(self.name.len())?
314 .checked_add(1)?;
315 match whole {
316 Some(w) => w.get(start..start.checked_add(self.value.len())?),
317 None => core::str::from_utf8(self.value).ok(),
318 }
319 }
320
321 fn value_offset(&self) -> Location {
322 Location::at(
323 self.offset
324 .saturating_add(self.name.len() as u64)
325 .saturating_add(1),
326 )
327 }
328
329 #[must_use]
339 pub const fn name_raw(&self) -> &'a [u8] {
340 self.name
341 }
342
343 #[must_use]
353 pub const fn value_raw(&self) -> &'a [u8] {
354 self.value
355 }
356
357 #[must_use]
371 pub const fn has_equals(&self) -> bool {
372 self.flags & HAS_EQUALS != 0
373 }
374
375 #[must_use]
385 pub const fn name_needs_decoding(&self) -> bool {
386 self.flags & NAME_DECODE != 0
387 }
388
389 #[must_use]
399 pub const fn value_needs_decoding(&self) -> bool {
400 self.flags & VALUE_DECODE != 0
401 }
402
403 #[must_use]
413 pub fn name_str(&self) -> Option<&'a str> {
414 if self.name_needs_decoding() {
415 None
416 } else {
417 core::str::from_utf8(self.name).ok()
418 }
419 }
420
421 #[must_use]
431 pub fn value_str(&self) -> Option<&'a str> {
432 if self.value_needs_decoding() {
433 None
434 } else {
435 core::str::from_utf8(self.value).ok()
436 }
437 }
438
439 pub fn decode_name<'b>(
457 &self,
458 out: &'b mut [u8],
459 policy: PercentPolicy,
460 ) -> Result<&'b str, FormError>
461 where
462 'a: 'b,
463 {
464 decoded(self.name, self.name_needs_decoding(), out, policy)
465 .map_err(|e| e.shifted(self.offset))
466 }
467
468 pub fn decode_value<'b>(
485 &self,
486 out: &'b mut [u8],
487 policy: PercentPolicy,
488 ) -> Result<&'b str, FormError>
489 where
490 'a: 'b,
491 {
492 let at = self
493 .offset
494 .saturating_add(self.name.len() as u64)
495 .saturating_add(1);
496 decoded(self.value, self.value_needs_decoding(), out, policy).map_err(|e| e.shifted(at))
497 }
498
499 #[must_use]
510 pub const fn offset(&self) -> u64 {
511 self.offset
512 }
513}
514
515fn decoded<'b>(
520 raw: &'b [u8],
521 needs_decoding: bool,
522 out: &'b mut [u8],
523 policy: PercentPolicy,
524) -> Result<&'b str, FormError> {
525 if needs_decoding {
526 return decode_component(raw, out, policy);
527 }
528 if out.len() < raw.len() {
529 return Err(FormError::BufferTooSmall { needed: raw.len() });
530 }
531 core::str::from_utf8(raw)
533 .map_err(|_| FormError::encoding(EncodingError::InvalidUtf8, Location::at(0)))
534}
535
536#[cfg(test)]
537mod tests {
538 use super::*;
539 use alloc::vec::Vec;
540
541 type Pairs<'a> = Vec<(&'a [u8], &'a [u8])>;
542
543 #[test]
546 fn test_decode_borrows_plain_components_and_keeps_the_rules() {
547 let body = b"name=value&a%20b=c+d&bad=\xff";
548 let mut it = super::raw_pairs(body, &crate::Limits::DEFAULT);
549 let mut out = [0u8; 16];
550 let p = it.next().unwrap().unwrap();
551 let name = p.decode_name(&mut out, PercentPolicy::Refuse).unwrap();
552 assert_eq!(name, "name");
553 assert_eq!(name.as_ptr(), body.as_ptr(), "borrowed from the body");
554 let value = p.decode_value(&mut out, PercentPolicy::Refuse).unwrap();
555 assert_eq!(value.as_ptr(), body[5..].as_ptr());
556 let mut short = [0u8; 3];
557 assert!(matches!(
558 p.decode_name(&mut short, PercentPolicy::Refuse),
559 Err(FormError::BufferTooSmall { needed: 4 })
560 ));
561 let p = it.next().unwrap().unwrap();
562 assert_eq!(
563 p.decode_name(&mut out, PercentPolicy::Refuse).unwrap(),
564 "a b"
565 );
566 assert_eq!(
567 p.decode_value(&mut out, PercentPolicy::Refuse).unwrap(),
568 "c d"
569 );
570 let p = it.next().unwrap().unwrap();
571 let e = p.decode_value(&mut out, PercentPolicy::Refuse).unwrap_err();
572 assert_eq!(
573 (e.code(), e.location().map(|l| l.offset)),
574 ("encoding.invalid_utf8", Some(25))
575 );
576 let mut it = super::raw_pairs(b"name=value&a%20b=c+d&bad=%FF", &crate::Limits::DEFAULT);
578 let p = it.nth(2).unwrap().unwrap();
579 let d = p.decode_value(&mut out, PercentPolicy::Refuse).unwrap_err();
580 assert_eq!((d.code(), d.location()), (e.code(), e.location()));
581 }
582
583 fn pairs(input: &[u8]) -> Result<Pairs<'_>, FormError> {
584 raw_pairs(input, &Limits::DEFAULT)
585 .map(|p| p.map(|p| (p.name_raw(), p.value_raw())))
586 .collect()
587 }
588
589 #[test]
590 fn test_raw_pairs_whatwg_splitting() {
591 assert_eq!(pairs(b"").unwrap(), []);
592 assert_eq!(pairs(b"&&&").unwrap(), []);
593 assert_eq!(pairs(b"=").unwrap(), [(&b""[..], &b""[..])]);
594 assert_eq!(pairs(b"a==b").unwrap(), [(&b"a"[..], &b"=b"[..])]);
595 assert_eq!(pairs(b"=a").unwrap(), [(&b""[..], &b"a"[..])]);
596 assert_eq!(pairs(b"a;b=c").unwrap(), [(&b"a;b"[..], &b"c"[..])]);
597 assert_eq!(
598 pairs(b"a=1&b=2&").unwrap(),
599 [(&b"a"[..], &b"1"[..]), (&b"b"[..], &b"2"[..])]
600 );
601 }
602
603 #[test]
604 fn test_raw_pairs_flags_per_side() {
605 let p = raw_pairs(b"a%=b", &Limits::DEFAULT)
606 .next()
607 .unwrap()
608 .unwrap();
609 assert!(p.name_needs_decoding() && !p.value_needs_decoding());
610 let p = raw_pairs(b"a=b+%", &Limits::DEFAULT)
611 .next()
612 .unwrap()
613 .unwrap();
614 assert!(!p.name_needs_decoding() && p.value_needs_decoding());
615 let p = raw_pairs(b"a=b=+", &Limits::DEFAULT)
616 .next()
617 .unwrap()
618 .unwrap();
619 assert!(p.value_needs_decoding() && p.has_equals());
620 }
621
622 #[test]
623 fn test_raw_pairs_field_limit_n_and_n_plus_one() {
624 let l = Limits::DEFAULT.with_max_fields(2);
625 assert_eq!(raw_pairs(b"a&b", &l).count(), 2);
626 let r: Result<Vec<_>, _> = raw_pairs(b"a&b&c", &l).collect();
627 assert!(matches!(
628 r,
629 Err(FormError::Limit {
630 limit: Limit::Fields,
631 at
632 }) if at.offset == 4
633 ));
634 }
635
636 #[test]
637 fn test_raw_pairs_length_limits_at_the_edge() {
638 let l = Limits::DEFAULT
639 .with_max_name_bytes(3)
640 .with_max_value_bytes(3);
641 assert!(raw_pairs(b"abc=def", &l).all(|p| p.is_ok()));
642 let e = raw_pairs(b"abcd=1", &l).next().unwrap().unwrap_err();
643 assert!(matches!(
644 e,
645 FormError::Limit {
646 limit: Limit::NameLength,
647 ..
648 }
649 ));
650 let e = raw_pairs(b"a=defg", &l).next().unwrap().unwrap_err();
651 assert!(matches!(e, FormError::Limit { limit: Limit::ValueLength, at } if at.offset == 2));
652 let l = Limits::DEFAULT.with_max_text_bytes(4);
653 let r: Result<Vec<_>, _> = raw_pairs(b"a=12&b=345", &l).collect();
654 assert!(matches!(
655 r,
656 Err(FormError::Limit {
657 limit: Limit::TextTotal,
658 ..
659 })
660 ));
661 }
662
663 #[test]
664 fn test_raw_pairs_body_limit_counts_empty_sequences() {
665 let l = Limits::DEFAULT.with_max_body_bytes(4);
666 assert_eq!(raw_pairs(b"&&&&", &l).count(), 0);
667 let e = raw_pairs(b"&&&&&", &l).next().unwrap().unwrap_err();
668 assert!(matches!(
669 e,
670 FormError::Limit {
671 limit: Limit::Body,
672 ..
673 }
674 ));
675 }
676
677 #[test]
678 fn test_raw_pairs_stops_after_error() {
679 let l = Limits::DEFAULT.with_max_fields(0);
680 let mut it = raw_pairs(b"a&b", &l);
681 assert!(it.next().unwrap().is_err());
682 assert!(it.next().is_none());
683 }
684
685 #[test]
686 fn test_raw_pair_debug_hides_values() {
687 let p = raw_pairs(b"password=hunter2", &Limits::DEFAULT)
688 .next()
689 .unwrap()
690 .unwrap();
691 let s = alloc::format!("{p:?}");
692 assert!(!s.contains("hunter2") && !s.contains("password"));
693 }
694}