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 fields: 0,
37 text: 0,
38 limits: *limits,
39 done: false,
40 checked_body: false,
41 }
42}
43
44#[derive(Clone)]
46pub struct RawPairs<'a> {
47 input: &'a [u8],
48 pos: usize,
49 fields: u32,
50 text: u64,
51 limits: Limits,
52 done: bool,
53 checked_body: bool,
54}
55
56impl fmt::Debug for RawPairs<'_> {
57 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
58 f.debug_struct("RawPairs")
59 .field("position", &self.pos)
60 .field("fields", &self.fields)
61 .finish_non_exhaustive()
62 }
63}
64
65impl<'a> RawPairs<'a> {
66 fn fail(&mut self, err: FormError) -> Option<Result<RawPair<'a>, FormError>> {
67 self.done = true;
68 Some(Err(err))
69 }
70}
71
72impl<'a> Iterator for RawPairs<'a> {
73 type Item = Result<RawPair<'a>, FormError>;
74
75 fn next(&mut self) -> Option<Self::Item> {
76 if self.done {
77 return None;
78 }
79 if !self.checked_body {
80 self.checked_body = true;
81 if self.input.len() > self.limits.body_usize() {
82 return self.fail(FormError::limit(
83 Limit::Body,
84 Location::at(self.limits.body()),
85 ));
86 }
87 }
88 loop {
89 if self.pos >= self.input.len() {
90 self.done = true;
91 return None;
92 }
93 let start = self.pos;
94 let mut flags = 0u8;
95 let mut eq = None;
96 let mut i = start;
97 let end = loop {
98 i = crate::scan::find_any(self.input, i, *b"&=%+");
99 match self.input.get(i) {
100 None | Some(b'&') => break i,
101 Some(b'=') if eq.is_none() => {
102 eq = Some(i);
103 flags |= HAS_EQUALS;
104 }
105 Some(b'%' | b'+') => {
106 flags |= if eq.is_some() {
107 VALUE_DECODE
108 } else {
109 NAME_DECODE
110 };
111 }
112 Some(_) => {}
113 }
114 i = i.wrapping_add(1);
115 };
116 self.pos = end.saturating_add(1).min(self.input.len());
117 if end == start {
118 continue;
119 }
120 let seq = self.input.get(start..end).unwrap_or(&[]);
121 let (name, value) = match eq {
122 Some(e) => {
123 let at = e.wrapping_sub(start);
124 (
125 seq.get(..at).unwrap_or(&[]),
126 seq.get(at.wrapping_add(1)..).unwrap_or(&[]),
127 )
128 }
129 None => (seq, &[][..]),
130 };
131 let offset = start as u64;
132 let at = Location::at(offset);
133 self.fields = self.fields.saturating_add(1);
134 if self.fields > self.limits.max_fields {
135 return self.fail(FormError::limit(Limit::Fields, at));
136 }
137 if name.len() as u64 > u64::from(self.limits.name()) {
138 return self.fail(FormError::limit(Limit::NameLength, at));
139 }
140 let value_at = Location::at(offset.saturating_add(name.len() as u64).saturating_add(1));
141 if value.len() as u64 > u64::from(self.limits.value()) {
142 return self.fail(FormError::limit(Limit::ValueLength, value_at));
143 }
144 self.text = self.text.saturating_add(value.len() as u64);
145 if self.text > self.limits.text() {
146 return self.fail(FormError::limit(Limit::TextTotal, value_at));
147 }
148 return Some(Ok(RawPair {
149 name,
150 value,
151 flags,
152 offset,
153 }));
154 }
155 }
156}
157
158impl core::iter::FusedIterator for RawPairs<'_> {}
159
160#[derive(Clone, Copy)]
164pub struct RawPair<'a> {
165 name: &'a [u8],
166 value: &'a [u8],
167 flags: u8,
168 offset: u64,
169}
170
171impl fmt::Debug for RawPair<'_> {
172 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
173 f.debug_struct("RawPair")
174 .field("offset", &self.offset)
175 .field("name_len", &self.name.len())
176 .field("value_len", &self.value.len())
177 .finish()
178 }
179}
180
181impl<'a> RawPair<'a> {
182 #[must_use]
192 pub const fn name_raw(&self) -> &'a [u8] {
193 self.name
194 }
195
196 #[must_use]
206 pub const fn value_raw(&self) -> &'a [u8] {
207 self.value
208 }
209
210 #[must_use]
224 pub const fn has_equals(&self) -> bool {
225 self.flags & HAS_EQUALS != 0
226 }
227
228 #[must_use]
238 pub const fn name_needs_decoding(&self) -> bool {
239 self.flags & NAME_DECODE != 0
240 }
241
242 #[must_use]
252 pub const fn value_needs_decoding(&self) -> bool {
253 self.flags & VALUE_DECODE != 0
254 }
255
256 #[must_use]
266 pub fn name_str(&self) -> Option<&'a str> {
267 if self.name_needs_decoding() {
268 None
269 } else {
270 core::str::from_utf8(self.name).ok()
271 }
272 }
273
274 #[must_use]
284 pub fn value_str(&self) -> Option<&'a str> {
285 if self.value_needs_decoding() {
286 None
287 } else {
288 core::str::from_utf8(self.value).ok()
289 }
290 }
291
292 pub fn decode_name<'b>(
310 &self,
311 out: &'b mut [u8],
312 policy: PercentPolicy,
313 ) -> Result<&'b str, FormError> {
314 decode_component(self.name, out, policy).map_err(|e| e.shifted(self.offset))
315 }
316
317 pub fn decode_value<'b>(
334 &self,
335 out: &'b mut [u8],
336 policy: PercentPolicy,
337 ) -> Result<&'b str, FormError> {
338 let at = self
339 .offset
340 .saturating_add(self.name.len() as u64)
341 .saturating_add(1);
342 decode_component(self.value, out, policy).map_err(|e| e.shifted(at))
343 }
344
345 #[must_use]
356 pub const fn offset(&self) -> u64 {
357 self.offset
358 }
359}
360
361#[cfg(test)]
362mod tests {
363 use super::*;
364 use alloc::vec::Vec;
365
366 type Pairs<'a> = Vec<(&'a [u8], &'a [u8])>;
367
368 fn pairs(input: &[u8]) -> Result<Pairs<'_>, FormError> {
369 raw_pairs(input, &Limits::DEFAULT)
370 .map(|p| p.map(|p| (p.name_raw(), p.value_raw())))
371 .collect()
372 }
373
374 #[test]
375 fn test_raw_pairs_whatwg_splitting() {
376 assert_eq!(pairs(b"").unwrap(), []);
377 assert_eq!(pairs(b"&&&").unwrap(), []);
378 assert_eq!(pairs(b"=").unwrap(), [(&b""[..], &b""[..])]);
379 assert_eq!(pairs(b"a==b").unwrap(), [(&b"a"[..], &b"=b"[..])]);
380 assert_eq!(pairs(b"=a").unwrap(), [(&b""[..], &b"a"[..])]);
381 assert_eq!(pairs(b"a;b=c").unwrap(), [(&b"a;b"[..], &b"c"[..])]);
382 assert_eq!(
383 pairs(b"a=1&b=2&").unwrap(),
384 [(&b"a"[..], &b"1"[..]), (&b"b"[..], &b"2"[..])]
385 );
386 }
387
388 #[test]
389 fn test_raw_pairs_flags_per_side() {
390 let p = raw_pairs(b"a%=b", &Limits::DEFAULT)
391 .next()
392 .unwrap()
393 .unwrap();
394 assert!(p.name_needs_decoding() && !p.value_needs_decoding());
395 let p = raw_pairs(b"a=b+%", &Limits::DEFAULT)
396 .next()
397 .unwrap()
398 .unwrap();
399 assert!(!p.name_needs_decoding() && p.value_needs_decoding());
400 let p = raw_pairs(b"a=b=+", &Limits::DEFAULT)
401 .next()
402 .unwrap()
403 .unwrap();
404 assert!(p.value_needs_decoding() && p.has_equals());
405 }
406
407 #[test]
408 fn test_raw_pairs_field_limit_n_and_n_plus_one() {
409 let l = Limits::DEFAULT.with_max_fields(2);
410 assert_eq!(raw_pairs(b"a&b", &l).count(), 2);
411 let r: Result<Vec<_>, _> = raw_pairs(b"a&b&c", &l).collect();
412 assert!(matches!(
413 r,
414 Err(FormError::Limit {
415 limit: Limit::Fields,
416 at
417 }) if at.offset == 4
418 ));
419 }
420
421 #[test]
422 fn test_raw_pairs_length_limits_at_the_edge() {
423 let l = Limits::DEFAULT
424 .with_max_name_bytes(3)
425 .with_max_value_bytes(3);
426 assert!(raw_pairs(b"abc=def", &l).all(|p| p.is_ok()));
427 let e = raw_pairs(b"abcd=1", &l).next().unwrap().unwrap_err();
428 assert!(matches!(
429 e,
430 FormError::Limit {
431 limit: Limit::NameLength,
432 ..
433 }
434 ));
435 let e = raw_pairs(b"a=defg", &l).next().unwrap().unwrap_err();
436 assert!(matches!(e, FormError::Limit { limit: Limit::ValueLength, at } if at.offset == 2));
437 let l = Limits::DEFAULT.with_max_text_bytes(4);
438 let r: Result<Vec<_>, _> = raw_pairs(b"a=12&b=345", &l).collect();
439 assert!(matches!(
440 r,
441 Err(FormError::Limit {
442 limit: Limit::TextTotal,
443 ..
444 })
445 ));
446 }
447
448 #[test]
449 fn test_raw_pairs_body_limit_counts_empty_sequences() {
450 let l = Limits::DEFAULT.with_max_body_bytes(4);
451 assert_eq!(raw_pairs(b"&&&&", &l).count(), 0);
452 let e = raw_pairs(b"&&&&&", &l).next().unwrap().unwrap_err();
453 assert!(matches!(
454 e,
455 FormError::Limit {
456 limit: Limit::Body,
457 ..
458 }
459 ));
460 }
461
462 #[test]
463 fn test_raw_pairs_stops_after_error() {
464 let l = Limits::DEFAULT.with_max_fields(0);
465 let mut it = raw_pairs(b"a&b", &l);
466 assert!(it.next().unwrap().is_err());
467 assert!(it.next().is_none());
468 }
469
470 #[test]
471 fn test_raw_pair_debug_hides_values() {
472 let p = raw_pairs(b"password=hunter2", &Limits::DEFAULT)
473 .next()
474 .unwrap()
475 .unwrap();
476 let s = alloc::format!("{p:?}");
477 assert!(!s.contains("hunter2") && !s.contains("password"));
478 }
479}