1use core::fmt;
5
6use crate::error::{EncodingError, FormError, Limit, Location, PolicyRefusal, SyntaxError};
7use crate::limits::{CHARSET_CAPTURE, EmptyFilePolicy, Limits, Policy, TokenPlacement};
8use crate::multipart::boundary::Boundary;
9use crate::multipart::filename::FileName;
10use crate::multipart::header::{Areas, BlockScan, HeadFacts, Text, read_block};
11
12#[non_exhaustive]
23#[derive(Clone, Copy, Debug, PartialEq, Eq)]
24pub enum PartKind {
25 Field,
27 File,
30}
31
32#[non_exhaustive]
49#[derive(Clone, Copy, Debug, PartialEq, Eq)]
50pub enum Charset {
51 Utf8,
53 Ascii,
55 Unspecified,
57 Other,
59}
60
61impl Charset {
62 pub(crate) fn from_label(label: &[u8]) -> Charset {
63 if label.eq_ignore_ascii_case(b"utf-8") {
64 Charset::Utf8
65 } else if label.eq_ignore_ascii_case(b"us-ascii") {
66 Charset::Ascii
67 } else {
68 Charset::Other
69 }
70 }
71}
72
73#[non_exhaustive]
76#[derive(Debug)]
77pub struct Step<'p> {
78 pub consumed: usize,
81 pub event: Event<'p>,
83}
84
85#[non_exhaustive]
93pub enum Event<'p> {
94 PartStart(PartHead<'p>),
96 Data(&'p [u8]),
98 PartEnd(PartSummary),
100 End,
102 NeedInput,
104}
105
106impl fmt::Debug for Event<'_> {
107 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
108 match self {
109 Self::PartStart(head) => f.debug_tuple("PartStart").field(head).finish(),
110 Self::Data(bytes) => write!(f, "Data({} bytes)", bytes.len()),
111 Self::PartEnd(summary) => f.debug_tuple("PartEnd").field(summary).finish(),
112 Self::End => f.write_str("End"),
113 Self::NeedInput => f.write_str("NeedInput"),
114 }
115 }
116}
117
118#[non_exhaustive]
120#[derive(Clone, Copy, Debug, PartialEq, Eq)]
121pub struct PartSummary {
122 pub index: u32,
124 pub kind: PartKind,
126 pub bytes: u64,
128 pub skipped: bool,
130}
131
132#[derive(Clone, Copy)]
136pub struct PartHead<'p> {
137 index: u32,
138 block: &'p [u8],
139 name: &'p str,
140 name_raw: &'p [u8],
141 kind: PartKind,
142 filename: Option<FileName<'p>>,
143 content_type: Option<&'p [u8]>,
144 charset: Charset,
145}
146
147impl fmt::Debug for PartHead<'_> {
148 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
149 f.debug_struct("PartHead")
150 .field("index", &self.index)
151 .field("name", &self.name)
152 .field("kind", &self.kind)
153 .field("filename", &self.filename)
154 .finish_non_exhaustive()
155 }
156}
157
158impl<'p> PartHead<'p> {
159 #[must_use]
161 pub const fn index(&self) -> u32 {
162 self.index
163 }
164
165 #[must_use]
168 pub const fn name(&self) -> &'p str {
169 self.name
170 }
171
172 #[must_use]
174 pub const fn name_raw(&self) -> &'p [u8] {
175 self.name_raw
176 }
177
178 #[must_use]
180 pub const fn kind(&self) -> PartKind {
181 self.kind
182 }
183
184 #[must_use]
186 pub const fn is_file(&self) -> bool {
187 matches!(self.kind, PartKind::File)
188 }
189
190 #[must_use]
192 pub const fn filename(&self) -> Option<FileName<'p>> {
193 self.filename
194 }
195
196 #[must_use]
198 pub fn content_type(&self) -> Option<ContentType<'p>> {
199 self.content_type.and_then(ContentType::parse)
200 }
201
202 #[must_use]
204 pub const fn charset(&self) -> Charset {
205 self.charset
206 }
207
208 #[must_use]
210 pub fn headers(&self) -> Headers<'p> {
211 Headers { rest: self.block }
212 }
213
214 #[must_use]
216 pub const fn header_bytes(&self) -> u32 {
217 self.block.len() as u32
218 }
219}
220
221#[derive(Clone, Copy)]
236pub struct ContentType<'p> {
237 raw: &'p [u8],
238 media: parse_net::MediaType<'p>,
239}
240
241impl fmt::Debug for ContentType<'_> {
242 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
243 f.debug_struct("ContentType")
244 .field("type", &self.type_())
245 .field("subtype", &self.subtype())
246 .finish_non_exhaustive()
247 }
248}
249
250impl<'p> ContentType<'p> {
251 pub(crate) fn parse(raw: &'p [u8]) -> Option<ContentType<'p>> {
252 parse_net::media::parse(raw, &crate::kind::HEADER_LIMITS)
253 .ok()
254 .map(|media| ContentType { raw, media })
255 }
256
257 #[must_use]
259 pub const fn raw(&self) -> &'p [u8] {
260 self.raw
261 }
262
263 #[must_use]
265 pub fn type_(&self) -> &'p str {
266 core::str::from_utf8(self.media.type_()).unwrap_or("")
267 }
268
269 #[must_use]
271 pub fn subtype(&self) -> &'p str {
272 core::str::from_utf8(self.media.subtype()).unwrap_or("")
273 }
274
275 #[must_use]
277 pub fn is(&self, type_: &str, subtype: &str) -> bool {
278 self.media.is(type_, subtype)
279 }
280
281 #[must_use]
284 pub fn parameter(&self, name: &str) -> Option<&'p [u8]> {
285 self.media
286 .params()
287 .get(name)
288 .map(|w| crate::kind::word_raw(&w))
289 }
290
291 #[must_use]
293 pub fn charset(&self) -> Charset {
294 self.parameter("charset")
295 .map_or(Charset::Unspecified, Charset::from_label)
296 }
297}
298
299#[derive(Clone)]
304pub struct Headers<'p> {
305 rest: &'p [u8],
306}
307
308impl fmt::Debug for Headers<'_> {
309 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
310 let mut list = f.debug_list();
311 for (name, _) in self.clone() {
312 list.entry(&core::str::from_utf8(name).unwrap_or("?"));
313 }
314 list.finish()
315 }
316}
317
318impl<'p> Iterator for Headers<'p> {
319 type Item = (&'p [u8], &'p [u8]);
320
321 fn next(&mut self) -> Option<Self::Item> {
322 let lf = self.rest.iter().position(|&b| b == b'\n')?;
323 let line = self.rest.get(..lf.saturating_sub(1)).unwrap_or(&[]);
324 self.rest = self.rest.get(lf.wrapping_add(1)..).unwrap_or(&[]);
325 if line.is_empty() {
326 self.rest = &[];
327 return None;
328 }
329 let colon = line.iter().position(|&b| b == b':').unwrap_or(line.len());
330 let name = line.get(..colon).unwrap_or(&[]);
331 let value = line.get(colon.wrapping_add(1)..).unwrap_or(&[]);
332 Some((name, parse_net::text::trim_ows(value)))
333 }
334}
335
336#[derive(Clone, Copy, Debug, PartialEq, Eq)]
337enum State {
338 Preamble,
339 AfterDelimiter(After),
341 Headers,
342 Body,
343 EndOfPart,
345 Epilogue,
346 Poisoned,
347}
348
349#[derive(Clone, Copy, Debug, PartialEq, Eq)]
350enum After {
351 Start,
352 Dash,
353 Padding(u8),
354 Cr,
355}
356
357#[derive(Clone, Copy, Debug, PartialEq, Eq)]
359enum Token {
360 NotSeen,
361 Capturing,
362 Captured,
363}
364
365const SKIPPING: u8 = 1;
366const IS_TOKEN: u8 = 2;
367const IS_CHARSET: u8 = 4;
368const DEFERRED: u8 = 8;
369
370#[derive(Clone, Copy, Debug)]
372pub(crate) enum Source {
373 Input(usize),
375 Buffer,
377}
378
379#[derive(Clone, Copy, Debug)]
381pub(crate) enum Outcome {
382 PartStart(HeadFacts, Source),
383 DataInput(usize, usize),
385 DataDelimiter(usize),
387 PartEnd(PartSummary),
388 End,
389 NeedInput,
390}
391
392pub struct MultipartParser<B: AsMut<[u8]> + AsRef<[u8]>> {
440 boundary: Boundary,
441 limits: Limits,
442 policy: Policy,
443 buffer: B,
444 state: State,
445 k: u8,
447 flags: u8,
448 token: Token,
449 token_len: u16,
450 charset_len: u8,
451 charset_done: bool,
452 scan: BlockScan,
453 copied: u32,
455 parts: u32,
456 files: u32,
457 fields: u32,
458 kind: PartKind,
459 part_bytes: u64,
460 text_total: u64,
461 data_start: u64,
462 preamble: u64,
463 epilogue: u64,
464 head_start: u64,
466 epilogue_start: u64,
468 bytes_seen: u64,
469}
470
471impl<B: AsMut<[u8]> + AsRef<[u8]>> fmt::Debug for MultipartParser<B> {
472 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
473 f.debug_struct("MultipartParser")
474 .field("boundary", &self.boundary)
475 .field("state", &self.state)
476 .field("bytes_seen", &self.bytes_seen)
477 .field("parts_seen", &self.parts)
478 .finish_non_exhaustive()
479 }
480}
481
482#[cfg(feature = "alloc")]
483impl MultipartParser<alloc::vec::Vec<u8>> {
484 pub fn new(boundary: Boundary, limits: &Limits, policy: &Policy) -> Result<Self, FormError> {
501 limits.validate_with(policy)?;
502 let buffer = alloc::vec![0u8; limits.multipart_buffer_len(policy)];
503 Self::with_buffer(boundary, limits, policy, buffer)
504 }
505}
506
507impl<B: AsMut<[u8]> + AsRef<[u8]>> MultipartParser<B> {
508 pub fn with_buffer(
527 boundary: Boundary,
528 limits: &Limits,
529 policy: &Policy,
530 buffer: B,
531 ) -> Result<Self, FormError> {
532 limits.validate_with(policy)?;
533 let needed = limits.multipart_buffer_len(policy);
534 if buffer.as_ref().len() < needed {
535 return Err(FormError::BufferTooSmall { needed });
536 }
537 Ok(Self {
538 boundary,
539 limits: *limits,
540 policy: *policy,
541 buffer,
542 state: State::Preamble,
543 k: 2,
546 flags: 0,
547 token: Token::NotSeen,
548 token_len: 0,
549 charset_len: 0,
550 charset_done: false,
551 scan: BlockScan::default(),
552 copied: 0,
553 parts: 0,
554 files: 0,
555 fields: 0,
556 kind: PartKind::Field,
557 part_bytes: 0,
558 text_total: 0,
559 data_start: 0,
560 preamble: 0,
561 epilogue: 0,
562 head_start: 0,
563 epilogue_start: 0,
564 bytes_seen: 0,
565 })
566 }
567
568 pub fn parse<'p>(&'p mut self, input: &'p [u8], eof: bool) -> Result<Step<'p>, FormError> {
576 let (consumed, outcome) = self.advance(input, eof)?;
577 Ok(Step {
578 consumed,
579 event: self.view(outcome, input),
580 })
581 }
582
583 pub fn skip_part(&mut self) {
587 if matches!(self.state, State::Body) {
588 self.flags |= SKIPPING;
589 }
590 }
591
592 pub fn reset(&mut self, boundary: Boundary) {
595 crate::wipe::wipe(self.buffer.as_mut());
596 let limits = self.limits;
597 let policy = self.policy;
598 self.boundary = boundary;
599 self.state = State::Preamble;
600 self.k = 2;
601 self.flags = 0;
602 self.token = Token::NotSeen;
603 self.token_len = 0;
604 self.charset_len = 0;
605 self.charset_done = false;
606 self.scan = BlockScan::default();
607 self.copied = 0;
608 self.parts = 0;
609 self.files = 0;
610 self.fields = 0;
611 self.kind = PartKind::Field;
612 self.part_bytes = 0;
613 self.text_total = 0;
614 self.data_start = 0;
615 self.preamble = 0;
616 self.epilogue = 0;
617 self.head_start = 0;
618 self.epilogue_start = 0;
619 self.bytes_seen = 0;
620 self.limits = limits;
621 self.policy = policy;
622 }
623
624 #[must_use]
626 pub const fn bytes_seen(&self) -> u64 {
627 self.bytes_seen
628 }
629
630 #[must_use]
632 pub const fn parts_seen(&self) -> u32 {
633 self.parts
634 }
635
636 #[must_use]
638 pub const fn files_seen(&self) -> u32 {
639 self.files
640 }
641
642 #[must_use]
644 pub fn is_done(&self) -> bool {
645 self.state == State::Epilogue
646 }
647
648 #[must_use]
650 pub const fn limits(&self) -> &Limits {
651 &self.limits
652 }
653
654 #[must_use]
656 pub const fn policy(&self) -> &Policy {
657 &self.policy
658 }
659
660 #[must_use]
662 pub fn captured_token(&self) -> Option<&str> {
663 if self.token != Token::Captured {
664 return None;
665 }
666 let start = self.token_area();
667 let bytes = self
668 .buffer
669 .as_ref()
670 .get(start..start.saturating_add(usize::from(self.token_len)))?;
671 core::str::from_utf8(bytes).ok()
672 }
673
674 #[must_use]
676 pub fn declared_charset(&self) -> Option<&[u8]> {
677 if !self.charset_done {
678 return None;
679 }
680 let start = self.charset_area();
681 self.buffer
682 .as_ref()
683 .get(start..start.saturating_add(usize::from(self.charset_len)))
684 }
685
686 #[cfg(feature = "alloc")]
688 pub(crate) fn area_name(&self, len: u32) -> &str {
689 let start = self.name_area();
690 let bytes = self
691 .buffer
692 .as_ref()
693 .get(start..start.saturating_add(len as usize))
694 .unwrap_or(&[]);
695 core::str::from_utf8(bytes).unwrap_or("")
696 }
697
698 #[cfg(feature = "alloc")]
700 pub(crate) fn area_filename(&self, len: u32) -> &[u8] {
701 let start = self.filename_area();
702 self.buffer
703 .as_ref()
704 .get(start..start.saturating_add(len as usize))
705 .unwrap_or(&[])
706 }
707
708 #[cfg(feature = "alloc")]
710 pub(crate) const fn data_start(&self) -> u64 {
711 self.data_start
712 }
713
714 fn name_area(&self) -> usize {
717 self.limits.max_part_header_bytes as usize
718 }
719
720 fn filename_area(&self) -> usize {
721 self.name_area().saturating_add(self.limits.name() as usize)
722 }
723
724 fn token_area(&self) -> usize {
725 let filename = if matches!(
726 self.policy.extended_filename,
727 crate::ExtendedFilenamePolicy::AcceptAlone
728 ) {
729 self.limits.filename() as usize
730 } else {
731 0
732 };
733 self.filename_area().saturating_add(filename)
734 }
735
736 fn charset_area(&self) -> usize {
737 let token = if self.policy.token_field.is_some() {
738 usize::from(self.limits.token())
739 } else {
740 0
741 };
742 self.token_area().saturating_add(token)
743 }
744
745 fn head_at(&self) -> Location {
747 Location::in_part(self.parts.checked_sub(1), self.head_start)
748 }
749
750 fn excess(&self, used: u64, limit: u64) -> Location {
753 let into_part = self.part_bytes.saturating_add(limit.saturating_sub(used));
754 Location::in_part(
755 self.parts.checked_sub(1),
756 self.data_start.saturating_add(into_part),
757 )
758 }
759
760 fn at(&self, pos: usize) -> Location {
761 let part = if matches!(self.state, State::Preamble | State::Epilogue) {
762 None
763 } else {
764 self.parts.checked_sub(1)
765 };
766 Location::in_part(part, self.bytes_seen.saturating_add(pos as u64))
767 }
768
769 pub(crate) fn advance(
773 &mut self,
774 input: &[u8],
775 eof: bool,
776 ) -> Result<(usize, Outcome), FormError> {
777 if self.state == State::Poisoned {
778 return Err(FormError::Poisoned);
779 }
780 match self.run(input, eof) {
781 Ok((consumed, outcome)) => {
782 self.bytes_seen = self.bytes_seen.saturating_add(consumed as u64);
783 Ok((consumed, outcome))
784 }
785 Err(e) => {
786 self.state = State::Poisoned;
787 Err(e)
788 }
789 }
790 }
791
792 fn run(&mut self, input: &[u8], eof: bool) -> Result<(usize, Outcome), FormError> {
793 if self.bytes_seen.saturating_add(input.len() as u64) > self.limits.body() {
794 return Err(FormError::limit(
795 Limit::Body,
796 Location::at(self.limits.body()),
797 ));
798 }
799 let mut pos = 0usize;
800 loop {
801 let hay = input.get(pos..).unwrap_or(&[]);
802 match self.state {
803 State::Poisoned => return Err(FormError::Poisoned),
804 State::Preamble => {
805 if let Some(after) = self.preamble_step(hay)? {
806 pos = pos.wrapping_add(after);
807 self.state = State::AfterDelimiter(After::Start);
808 continue;
809 }
810 if eof {
811 return Err(FormError::syntax(
812 SyntaxError::NoInitialDelimiter,
813 self.at(input.len()),
814 ));
815 }
816 return Ok((input.len(), Outcome::NeedInput));
817 }
818 State::AfterDelimiter(sub) => {
819 let Some(&c) = hay.first() else {
820 return self.need_input(input.len(), eof);
821 };
822 pos = pos.wrapping_add(1);
823 let at = self.at(pos);
824 self.state = match (sub, c) {
825 (After::Start, b'-') => State::AfterDelimiter(After::Dash),
826 (After::Dash, b'-') => {
827 self.state = State::Epilogue;
828 self.epilogue_start = self.bytes_seen.saturating_add(pos as u64);
829 return Ok((pos, Outcome::End));
830 }
831 (After::Start, b' ' | b'\t') => {
832 if self.limits.max_padding_bytes == 0 {
833 return Err(FormError::limit(Limit::Padding, at));
834 }
835 State::AfterDelimiter(After::Padding(1))
836 }
837 (After::Padding(n), b' ' | b'\t') => {
838 if n >= self.limits.max_padding_bytes {
839 return Err(FormError::limit(Limit::Padding, at));
840 }
841 State::AfterDelimiter(After::Padding(n.saturating_add(1)))
842 }
843 (After::Start | After::Padding(_), b'\r') => {
844 State::AfterDelimiter(After::Cr)
845 }
846 (After::Cr, b'\n') => {
847 self.parts = self.parts.saturating_add(1);
848 if self.parts > self.limits.max_parts {
849 return Err(FormError::limit(Limit::Parts, self.at(pos)));
850 }
851 self.scan = BlockScan::default();
852 self.copied = 0;
853 self.head_start = self.bytes_seen.saturating_add(pos as u64);
854 State::Headers
855 }
856 (After::Start | After::Padding(_), b'\n') => {
857 return Err(FormError::syntax(SyntaxError::BareLineFeed, at));
858 }
859 _ => return Err(FormError::syntax(SyntaxError::BoundaryInContent, at)),
860 };
861 }
862 State::Headers => {
863 let at = self.head_at();
864 match self.scan.feed(hay, &self.limits, at)? {
865 Some(end) => {
866 let source = if self.copied == 0 {
867 Source::Input(pos)
868 } else {
869 self.copy_header(hay.get(..end).unwrap_or(&[]), at)?;
870 Source::Buffer
871 };
872 let block_start_in_input = pos;
873 pos = pos.wrapping_add(end);
874 let facts =
875 self.read_head(input, source, block_start_in_input, end, at)?;
876 let (is_token, is_charset) = {
877 let block = self.block(&facts, source, input);
878 let name = self.name_bytes(&facts, block);
879 let token = self
880 .policy
881 .token_field
882 .is_some_and(|t| name == t.name().as_bytes());
883 (token, name == b"_charset_")
884 };
885 self.start_part(&facts, is_token, is_charset, at)?;
886 self.data_start = self.bytes_seen.saturating_add(pos as u64);
887 return Ok((pos, Outcome::PartStart(facts, source)));
888 }
889 None => {
890 self.copy_header(hay, at)?;
891 return self.need_input(input.len(), eof);
892 }
893 }
894 }
895 State::Body => {
896 if hay.is_empty() {
897 return self.need_input(input.len(), eof);
898 }
899 match self.body_step(hay, pos, input.len(), eof)? {
900 BodyStep::Emit(consumed, outcome) => return Ok((consumed, outcome)),
901 BodyStep::Continue(next) => pos = next,
902 }
903 }
904 State::EndOfPart => {
905 let summary = self.end_part(self.at(pos))?;
906 self.state = State::AfterDelimiter(After::Start);
907 return Ok((pos, Outcome::PartEnd(summary)));
908 }
909 State::Epilogue => {
910 self.epilogue = self.epilogue.saturating_add(hay.len() as u64);
911 if self.epilogue > self.limits.epilogue() {
912 let at = self.epilogue_start.saturating_add(self.limits.epilogue());
913 return Err(FormError::limit(Limit::Epilogue, Location::at(at)));
914 }
915 return Ok((input.len(), Outcome::End));
916 }
917 }
918 }
919 }
920
921 fn need_input(&self, len: usize, eof: bool) -> Result<(usize, Outcome), FormError> {
922 if eof {
923 Err(FormError::syntax(SyntaxError::Truncated, self.at(len)))
924 } else {
925 Ok((len, Outcome::NeedInput))
926 }
927 }
928
929 fn preamble_step(&mut self, hay: &[u8]) -> Result<Option<usize>, FormError> {
932 let len = self.boundary.len() as u64;
933 let budget = self.limits.preamble().saturating_add(len);
935 let room = usize::try_from(budget.saturating_sub(self.preamble)).unwrap_or(usize::MAX);
936 let window = hay.get(..room.min(hay.len())).unwrap_or(hay);
937 let (k, found) = self.boundary.run(usize::from(self.k), window);
938 self.k = k as u8;
939 match found {
940 Some(after) => {
941 let end = self.preamble.saturating_add(after as u64);
944 let preamble = end.saturating_sub(len);
945 if preamble > self.limits.preamble() {
946 return Err(FormError::limit(
947 Limit::Preamble,
948 Location::at(self.limits.preamble()),
949 ));
950 }
951 self.k = 0;
952 Ok(Some(after))
953 }
954 None => {
955 self.preamble = self.preamble.saturating_add(window.len() as u64);
956 if window.len() < hay.len() || self.preamble >= budget {
957 return Err(FormError::limit(
958 Limit::Preamble,
959 Location::at(self.limits.preamble()),
960 ));
961 }
962 Ok(None)
963 }
964 }
965 }
966
967 fn copy_header(&mut self, bytes: &[u8], at: Location) -> Result<(), FormError> {
968 let start = self.copied as usize;
969 let end = start.saturating_add(bytes.len());
970 if end > self.limits.max_part_header_bytes as usize {
971 return Err(FormError::limit(Limit::PartHeaderBytes, at));
972 }
973 match self.buffer.as_mut().get_mut(start..end) {
974 Some(dst) => dst.copy_from_slice(bytes),
975 None => return Err(FormError::limit(Limit::PartHeaderBytes, at)),
976 }
977 self.copied = end as u32;
978 Ok(())
979 }
980
981 fn read_head(
982 &mut self,
983 input: &[u8],
984 source: Source,
985 start: usize,
986 end: usize,
987 at: Location,
988 ) -> Result<HeadFacts, FormError> {
989 let name_area = self.name_area();
990 let filename_area = self.filename_area();
991 let filename_end = self.token_area();
992 let limits = self.limits;
993 let policy = self.policy;
994 let copied = self.copied as usize;
995 let buf = self.buffer.as_mut();
996 let (head, rest) = buf.split_at_mut(name_area.min(buf.len()));
997 let (name, rest) =
998 rest.split_at_mut(filename_area.saturating_sub(name_area).min(rest.len()));
999 let filename = rest
1000 .get_mut(..filename_end.saturating_sub(filename_area))
1001 .unwrap_or(&mut []);
1002 let block = match source {
1003 Source::Input(_) => input.get(start..start.saturating_add(end)).unwrap_or(&[]),
1004 Source::Buffer => head.get(..copied).unwrap_or(&[]),
1005 };
1006 read_block(block, &limits, &policy, Areas { name, filename }, at)
1007 }
1008
1009 fn start_part(
1011 &mut self,
1012 facts: &HeadFacts,
1013 is_token: bool,
1014 is_charset: bool,
1015 at: Location,
1016 ) -> Result<(), FormError> {
1017 self.state = State::Body;
1018 self.k = 0;
1019 self.flags = 0;
1020 self.kind = facts.kind;
1021 self.part_bytes = 0;
1022 match facts.kind {
1023 PartKind::Field => {
1024 self.fields = self.fields.saturating_add(1);
1025 if self.fields > self.limits.max_fields {
1026 return Err(FormError::limit(Limit::Fields, at));
1027 }
1028 if is_token {
1029 if self.token != Token::NotSeen {
1030 return Err(FormError::policy(PolicyRefusal::DuplicateToken, at));
1031 }
1032 self.token = Token::Capturing;
1033 self.token_len = 0;
1034 self.flags |= IS_TOKEN;
1035 }
1036 if is_charset {
1037 self.flags |= IS_CHARSET;
1038 self.charset_len = 0;
1039 self.charset_done = false;
1040 }
1041 }
1042 PartKind::File => {
1043 let empty = matches!(facts.filename, Some((Text::Block(span), _)) if span.len == 0)
1044 || matches!(facts.filename, Some((Text::Area(0), _)));
1045 if empty && self.policy.empty_files == EmptyFilePolicy::Skip {
1046 self.flags |= DEFERRED;
1047 } else {
1048 self.count_file(at)?;
1049 }
1050 }
1051 }
1052 Ok(())
1053 }
1054
1055 fn block<'a>(&'a self, facts: &HeadFacts, source: Source, input: &'a [u8]) -> &'a [u8] {
1057 let len = facts.block_len as usize;
1058 match source {
1059 Source::Input(start) => input.get(start..start.saturating_add(len)).unwrap_or(&[]),
1060 Source::Buffer => self.buffer.as_ref().get(..len).unwrap_or(&[]),
1061 }
1062 }
1063
1064 fn name_bytes<'a>(&'a self, facts: &HeadFacts, block: &'a [u8]) -> &'a [u8] {
1066 match facts.name {
1067 Text::Block(span) => span.get(block),
1068 Text::Area(len) => {
1069 let start = self.name_area();
1070 self.buffer
1071 .as_ref()
1072 .get(start..start.saturating_add(len as usize))
1073 .unwrap_or(&[])
1074 }
1075 }
1076 }
1077
1078 fn head_view<'p>(&'p self, facts: &HeadFacts, source: Source, input: &'p [u8]) -> PartHead<'p> {
1080 let block = self.block(facts, source, input);
1081 let name = core::str::from_utf8(self.name_bytes(facts, block)).unwrap_or("");
1082 let filename = facts.filename.map(|(text, origin)| {
1083 let raw = match text {
1084 Text::Block(span) => span.get(block),
1085 Text::Area(len) => {
1086 let start = self.filename_area();
1087 self.buffer
1088 .as_ref()
1089 .get(start..start.saturating_add(len as usize))
1090 .unwrap_or(&[])
1091 }
1092 };
1093 FileName::new(raw, origin)
1094 });
1095 PartHead {
1096 index: self.parts.saturating_sub(1),
1097 block,
1098 name,
1099 name_raw: facts.name_raw.get(block),
1100 kind: facts.kind,
1101 filename,
1102 content_type: facts.content_type.map(|span| span.get(block)),
1103 charset: facts.charset,
1104 }
1105 }
1106
1107 fn view<'p>(&'p self, outcome: Outcome, input: &'p [u8]) -> Event<'p> {
1109 match outcome {
1110 Outcome::PartStart(facts, source) => {
1111 Event::PartStart(self.head_view(&facts, source, input))
1112 }
1113 Outcome::DataInput(start, end) => Event::Data(input.get(start..end).unwrap_or(&[])),
1114 Outcome::DataDelimiter(n) => {
1115 Event::Data(self.boundary.delimiter().get(..n).unwrap_or(&[]))
1116 }
1117 Outcome::PartEnd(summary) => Event::PartEnd(summary),
1118 Outcome::End => Event::End,
1119 Outcome::NeedInput => Event::NeedInput,
1120 }
1121 }
1122
1123 fn count_file(&mut self, at: Location) -> Result<(), FormError> {
1124 self.files = self.files.saturating_add(1);
1125 if self.files > self.limits.max_files {
1126 return Err(FormError::limit(Limit::Files, at));
1127 }
1128 if let Some(t) = self.policy.token_field {
1129 if t.placement() == TokenPlacement::BeforeFirstFile && self.token != Token::Captured {
1130 return Err(FormError::policy(PolicyRefusal::TokenFieldLate, at));
1131 }
1132 }
1133 Ok(())
1134 }
1135
1136 fn take_data(&mut self, bytes: &[u8]) -> Result<(), FormError> {
1139 let n = bytes.len() as u64;
1140 if n == 0 {
1141 return Ok(());
1142 }
1143 if self.flags & DEFERRED != 0 {
1144 self.flags &= !DEFERRED;
1145 let at = Location::in_part(self.parts.checked_sub(1), self.data_start);
1146 self.count_file(at)?;
1147 }
1148 let total = self.part_bytes.saturating_add(n);
1149 match self.kind {
1150 PartKind::File => {
1151 let limit = self.limits.file();
1152 if total > limit {
1153 let at = self.excess(self.part_bytes, limit);
1154 return Err(FormError::limit(Limit::FileSize, at));
1155 }
1156 }
1157 PartKind::Field => {
1158 let limit = u64::from(self.limits.value());
1159 if total > limit {
1160 let at = self.excess(self.part_bytes, limit);
1161 return Err(FormError::limit(Limit::ValueLength, at));
1162 }
1163 let text = self.text_total.saturating_add(n);
1164 let limit = self.limits.text();
1165 if text > limit {
1166 let at = self.excess(self.text_total, limit);
1167 return Err(FormError::limit(Limit::TextTotal, at));
1168 }
1169 self.text_total = text;
1170 }
1171 }
1172 if self.flags & IS_TOKEN != 0 {
1173 let start = self
1174 .token_area()
1175 .saturating_add(usize::from(self.token_len));
1176 let end = start.saturating_add(bytes.len());
1177 let limit = u64::from(self.limits.token());
1178 let at = self.excess(u64::from(self.token_len), limit);
1179 if end
1180 > self
1181 .token_area()
1182 .saturating_add(usize::from(self.limits.token()))
1183 {
1184 return Err(FormError::limit(Limit::TokenLength, at));
1185 }
1186 match self.buffer.as_mut().get_mut(start..end) {
1187 Some(dst) => dst.copy_from_slice(bytes),
1188 None => return Err(FormError::limit(Limit::TokenLength, at)),
1189 }
1190 self.token_len = self.token_len.saturating_add(bytes.len() as u16);
1191 }
1192 if self.flags & IS_CHARSET != 0 {
1193 let start = self
1194 .charset_area()
1195 .saturating_add(usize::from(self.charset_len));
1196 let end = start.saturating_add(bytes.len());
1197 let at = self.excess(u64::from(self.charset_len), CHARSET_CAPTURE as u64);
1198 if end > self.charset_area().saturating_add(CHARSET_CAPTURE) {
1199 return Err(FormError::encoding(EncodingError::UnsupportedCharset, at));
1200 }
1201 match self.buffer.as_mut().get_mut(start..end) {
1202 Some(dst) => dst.copy_from_slice(bytes),
1203 None => return Err(FormError::encoding(EncodingError::UnsupportedCharset, at)),
1204 }
1205 self.charset_len = self.charset_len.saturating_add(bytes.len() as u8);
1206 }
1207 self.part_bytes = total;
1208 Ok(())
1209 }
1210
1211 fn end_part(&mut self, at: Location) -> Result<PartSummary, FormError> {
1212 if self.flags & IS_TOKEN != 0 {
1213 let start = self.token_area();
1214 let bytes = self
1215 .buffer
1216 .as_ref()
1217 .get(start..start.saturating_add(usize::from(self.token_len)))
1218 .unwrap_or(&[]);
1219 if core::str::from_utf8(bytes).is_err() {
1220 return Err(FormError::encoding(EncodingError::InvalidUtf8, at));
1221 }
1222 self.token = Token::Captured;
1223 }
1224 if self.flags & IS_CHARSET != 0 {
1225 self.charset_done = true;
1226 }
1227 let summary = PartSummary {
1228 index: self.parts.saturating_sub(1),
1229 kind: self.kind,
1230 bytes: self.part_bytes,
1231 skipped: self.flags & SKIPPING != 0,
1232 };
1233 self.flags = 0;
1234 self.k = 0;
1235 Ok(summary)
1236 }
1237
1238 fn body_step(
1240 &mut self,
1241 hay: &[u8],
1242 pos: usize,
1243 input_len: usize,
1244 eof: bool,
1245 ) -> Result<BodyStep, FormError> {
1246 let len = self.boundary.len();
1247 let k0 = usize::from(self.k);
1248 if k0 > 0 {
1249 let mut k = k0;
1252 for (i, &c) in hay.iter().enumerate() {
1253 k = self.boundary.step(k, c);
1254 let n = i.wrapping_add(1);
1255 if k == len {
1256 let data = k0.saturating_add(n).saturating_sub(len);
1258 self.k = 0;
1259 self.state = State::EndOfPart;
1260 return self.emit_delimiter_bytes(data, pos.wrapping_add(n));
1261 }
1262 if k <= n {
1263 self.k = 0;
1265 return self.emit_delimiter_bytes(k0, pos);
1266 }
1267 }
1268 let n = hay.len();
1270 if eof {
1271 return Err(FormError::syntax(
1272 SyntaxError::Truncated,
1273 self.at(input_len),
1274 ));
1275 }
1276 let data = k0.saturating_add(n).saturating_sub(k);
1277 self.k = k as u8;
1278 return self.emit_delimiter_bytes(data, input_len);
1279 }
1280 let (k, found) = self.boundary.run(0, hay);
1281 match found {
1282 Some(after) => {
1283 let data = after.saturating_sub(len);
1284 self.k = 0;
1285 self.state = State::EndOfPart;
1286 let bytes = hay.get(..data).unwrap_or(&[]);
1287 self.emit_input_bytes(bytes, pos, pos.wrapping_add(data), pos.wrapping_add(after))
1288 }
1289 None => {
1290 if eof {
1291 return Err(FormError::syntax(
1292 SyntaxError::Truncated,
1293 self.at(input_len),
1294 ));
1295 }
1296 self.k = k as u8;
1297 let data_end = hay.len().saturating_sub(k);
1298 let bytes = hay.get(..data_end).unwrap_or(&[]);
1299 self.emit_input_bytes(bytes, pos, pos.wrapping_add(data_end), input_len)
1300 }
1301 }
1302 }
1303
1304 fn emit_delimiter_bytes(&mut self, n: usize, consumed: usize) -> Result<BodyStep, FormError> {
1307 let boundary = self.boundary;
1308 let bytes = boundary.delimiter().get(..n).unwrap_or(&[]);
1309 self.take_data(bytes)?;
1310 if n == 0 || self.flags & SKIPPING != 0 {
1311 return Ok(BodyStep::Continue(consumed));
1312 }
1313 Ok(BodyStep::Emit(consumed, Outcome::DataDelimiter(n)))
1314 }
1315
1316 fn emit_input_bytes(
1319 &mut self,
1320 bytes: &[u8],
1321 start: usize,
1322 end: usize,
1323 consumed: usize,
1324 ) -> Result<BodyStep, FormError> {
1325 self.take_data(bytes)?;
1326 if start == end || self.flags & SKIPPING != 0 {
1327 return Ok(BodyStep::Continue(consumed));
1328 }
1329 Ok(BodyStep::Emit(consumed, Outcome::DataInput(start, end)))
1330 }
1331}
1332
1333enum BodyStep {
1335 Emit(usize, Outcome),
1336 Continue(usize),
1337}
1338
1339impl<B: AsMut<[u8]> + AsRef<[u8]>> Drop for MultipartParser<B> {
1340 fn drop(&mut self) {
1341 crate::wipe::wipe(self.buffer.as_mut());
1342 }
1343}
1344
1345#[cfg(test)]
1346mod tests {
1347 use super::*;
1348
1349 #[test]
1350 fn test_parser_size_is_bounded() {
1351 assert!(core::mem::size_of::<MultipartParser<&mut [u8]>>() <= 384);
1354 assert!(core::mem::size_of::<Boundary>() <= 150);
1355 }
1356
1357 #[cfg(feature = "alloc")]
1358 #[test]
1359 fn test_debug_never_shows_data_or_file_names() {
1360 let body = b"--X\r\nContent-Disposition: form-data; name=f; filename=\"secret.pdf\"\r\n\r\nhunter2\r\n--X--";
1361 let mut p = MultipartParser::new(
1362 Boundary::new(b"X").unwrap(),
1363 &Limits::DEFAULT,
1364 &Policy::DEFAULT,
1365 )
1366 .unwrap();
1367 let mut rest: &[u8] = body;
1368 let mut seen = alloc::string::String::new();
1369 loop {
1370 let step = p.parse(rest, true).unwrap();
1371 rest = &rest[step.consumed..];
1372 if let Event::PartStart(head) = &step.event {
1373 seen.push_str(&alloc::format!("{:?}", head.headers()));
1374 }
1375 seen.push_str(&alloc::format!("{step:?}"));
1376 if matches!(step.event, Event::End) {
1377 break;
1378 }
1379 }
1380 assert!(seen.contains("Data(7 bytes)"), "{seen}");
1381 assert!(
1382 !seen.contains("hunter2") && !seen.contains("secret"),
1383 "{seen}"
1384 );
1385 }
1386
1387 #[test]
1388 fn test_charset_labels() {
1389 assert_eq!(Charset::from_label(b"UTF-8"), Charset::Utf8);
1390 assert_eq!(Charset::from_label(b"us-ascii"), Charset::Ascii);
1391 assert_eq!(Charset::from_label(b"utf8"), Charset::Other);
1392 }
1393}