form_net/io.rs
1//! Blocking readers: a pull-style API over `std::io::Read`, free of any
2//! runtime. Ask for the next part, read it like a file, ask for the next.
3
4use alloc::string::String;
5use alloc::vec::Vec;
6use core::fmt;
7use std::io::{self, Read};
8
9use crate::error::{EncodingError, FormError, Location};
10use crate::limits::{Limits, Policy};
11use crate::multipart::owned_head::OwnedPartHead;
12use crate::multipart::parser::{MultipartEvent, MultipartParser, PartSummary};
13
14const READ_BUFFER: usize = 64 * 1024;
15
16/// Reads a multipart body from a blocking reader, one part at a time.
17///
18/// It has no hooks: the caller sees each part itself. Dropping a
19/// [`PartReader`] before its end skips the rest of the part at the next
20/// [`next_part`](Self::next_part).
21///
22/// # Examples
23///
24/// ```
25/// use std::io::Read;
26///
27/// let body = b"--X\r\nContent-Disposition: form-data; name=note\r\n\r\nhi\r\n--X\r\nContent-Disposition: form-data; name=f; filename=a.bin\r\n\r\n0123\r\n--X--";
28/// let mut reader = form_net::MultipartReader::new(b"multipart/form-data; boundary=X", &body[..])?;
29/// let mut seen = Vec::new();
30/// while let Some(mut part) = reader.next_part()? {
31/// if part.head().view().is_file() {
32/// let mut bytes = Vec::new();
33/// part.read_to_end(&mut bytes).unwrap();
34/// seen.push(bytes.len());
35/// } else {
36/// seen.push(part.text()?.len());
37/// }
38/// }
39/// assert_eq!(seen, [2, 4]);
40/// # Ok::<(), form_net::FormError>(())
41/// ```
42pub struct MultipartReader<R: Read> {
43 reader: R,
44 parser: MultipartParser<Vec<u8>>,
45 buf: Vec<u8>,
46 /// The most of `buf` any read filled: only that is wiped.
47 buf_used: usize,
48 start: usize,
49 end: usize,
50 eof: bool,
51 head: OwnedPartHead,
52 pending: Vec<u8>,
53 pending_at: usize,
54 in_part: bool,
55 last: Option<PartSummary>,
56 done: bool,
57 /// Whether the `_charset_` value declared before the current part
58 /// lets its text be read: the parser's record, read before the part
59 /// started, as every other entry point reads it (D-128, D-141).
60 declared: crate::multipart::parser::TextRule,
61 /// Bytes `save` has put on disk for this request.
62 #[cfg(feature = "fs")]
63 disk_used: u64,
64}
65
66impl<R: Read> Drop for MultipartReader<R> {
67 fn drop(&mut self) {
68 crate::wipe::wipe(self.buf.get_mut(..self.buf_used).unwrap_or(&mut []));
69 crate::wipe::wipe_vec(&mut self.pending);
70 }
71}
72
73impl<R: Read> fmt::Debug for MultipartReader<R> {
74 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
75 f.debug_struct("MultipartReader")
76 .field("parser", &self.parser)
77 .field("in_part", &self.in_part)
78 .finish_non_exhaustive()
79 }
80}
81
82/// What the reader's loop produced.
83enum Got {
84 Start,
85 Data,
86 End(PartSummary),
87 Done,
88}
89
90impl<R: Read> MultipartReader<R> {
91 /// A reader with the default limits and policy.
92 ///
93 /// # Errors
94 ///
95 /// `UnsupportedMediaType` and the boundary errors.
96 ///
97 /// # Examples
98 ///
99 /// ```
100 /// let body = b"--X\r\nContent-Disposition: form-data; name=note\r\n\r\nhi\r\n--X--";
101 /// let mut reader = form_net::MultipartReader::new(b"multipart/form-data; boundary=X", &body[..])?;
102 /// let mut part = reader.next_part()?.unwrap();
103 /// assert_eq!(part.text()?, "hi");
104 /// # Ok::<(), form_net::FormError>(())
105 /// ```
106 pub fn new(content_type: &[u8], reader: R) -> Result<Self, FormError> {
107 Self::with_limits(content_type, reader, &Limits::DEFAULT, &Policy::DEFAULT)
108 }
109
110 /// A reader with explicit limits and policy.
111 ///
112 /// # Errors
113 ///
114 /// As [`new`](Self::new); `InvalidLimits`.
115 ///
116 /// # Examples
117 ///
118 /// ```
119 /// use form_net::{Limits, MultipartReader, Policy};
120 ///
121 /// let limits = Limits::DEFAULT.with_max_value_bytes(4);
122 /// let body = b"--X\r\nContent-Disposition: form-data; name=note\r\n\r\ntoo long\r\n--X--";
123 /// let ct = b"multipart/form-data; boundary=X";
124 /// let mut reader = MultipartReader::with_limits(ct, &body[..], &limits, &Policy::DEFAULT)?;
125 /// let mut part = reader.next_part()?.unwrap();
126 /// assert_eq!(part.text().unwrap_err().code(), "limit.value_length");
127 /// # Ok::<(), form_net::FormError>(())
128 /// ```
129 pub fn with_limits(
130 content_type: &[u8],
131 reader: R,
132 limits: &Limits,
133 policy: &Policy,
134 ) -> Result<Self, FormError> {
135 let boundary = crate::Boundary::parse(content_type)?;
136 let parser = MultipartParser::new(boundary, limits, policy)?;
137 Ok(MultipartReader {
138 reader,
139 parser,
140 buf: alloc::vec![0u8; READ_BUFFER],
141 buf_used: 0,
142 start: 0,
143 end: 0,
144 eof: false,
145 head: OwnedPartHead::with_capacity(limits.multipart_buffer_len(policy)),
146 pending: Vec::new(),
147 pending_at: 0,
148 in_part: false,
149 last: None,
150 done: false,
151 declared: crate::multipart::parser::TextRule::Utf8,
152 #[cfg(feature = "fs")]
153 disk_used: 0,
154 })
155 }
156
157 /// The token field's value, once its part has ended.
158 ///
159 /// # Examples
160 ///
161 /// ```
162 /// use form_net::{Limits, MultipartReader, Policy, TokenField};
163 ///
164 /// let policy = Policy::DEFAULT.with_token_field(TokenField::new("csrf"));
165 /// let body = b"--X\r\nContent-Disposition: form-data; name=csrf\r\n\r\nt0k3n\r\n--X--";
166 /// let ct = b"multipart/form-data; boundary=X";
167 /// let mut reader = MultipartReader::with_limits(ct, &body[..], &Limits::DEFAULT, &policy)?;
168 /// while let Some(mut part) = reader.next_part()? {
169 /// part.skip()?;
170 /// }
171 /// assert_eq!(reader.captured_token(), Some("t0k3n"));
172 /// # Ok::<(), form_net::FormError>(())
173 /// ```
174 #[must_use]
175 pub fn captured_token(&self) -> Option<&str> {
176 self.parser.captured_token()
177 }
178
179 fn fill(&mut self) -> Result<(), FormError> {
180 if self.start < self.end || self.eof {
181 return Ok(());
182 }
183 loop {
184 match self.reader.read(&mut self.buf) {
185 Ok(0) => {
186 self.eof = true;
187 self.start = 0;
188 self.end = 0;
189 return Ok(());
190 }
191 Ok(n) => {
192 self.start = 0;
193 self.end = n.min(self.buf.len());
194 self.buf_used = self.buf_used.max(self.end);
195 return Ok(());
196 }
197 Err(e) if e.kind() == io::ErrorKind::Interrupted => {
198 // A failed read may have written anywhere in the buffer.
199 self.buf_used = self.buf.len();
200 }
201 Err(e) => {
202 self.buf_used = self.buf.len();
203 return Err(FormError::BodyRead { kind: e.kind() });
204 }
205 }
206 }
207 }
208
209 /// One parser event; data goes to `pending`.
210 fn step(&mut self) -> Result<Got, FormError> {
211 loop {
212 self.fill()?;
213 let input = self.buf.get(self.start..self.end).unwrap_or(&[]);
214 // Before `parse`: a `_charset_` part starting in this step resets
215 // the parser's record.
216 let declared = crate::multipart::parser::declared_rule(self.parser.declared_charset());
217 let step = self.parser.parse(input, self.eof)?;
218 self.start = self.start.saturating_add(step.consumed);
219 match step.event {
220 MultipartEvent::PartStart(head) => {
221 self.head.copy_from(&head);
222 self.declared = declared;
223 return Ok(Got::Start);
224 }
225 MultipartEvent::Data(bytes) => {
226 crate::wipe::wipe(&mut self.pending);
227 self.pending.clear();
228 crate::wipe::append_wiping(&mut self.pending, bytes, 4096, usize::MAX);
229 self.pending_at = 0;
230 return Ok(Got::Data);
231 }
232 MultipartEvent::PartEnd(s) => return Ok(Got::End(s)),
233 MultipartEvent::End => return Ok(Got::Done),
234 _ => {}
235 }
236 }
237 }
238
239 /// The next part, or `None` after the close delimiter. Skips whatever
240 /// is left of the previous part. After the close delimiter it reads the
241 /// rest of the body, which is epilogue and counts against
242 /// `max_epilogue_bytes` and `max_body_bytes`, as `parse_multipart`
243 /// counts it (D-142).
244 ///
245 /// # Errors
246 ///
247 /// Every multipart error; `Io { kind }` from the reader.
248 ///
249 /// # Examples
250 ///
251 /// ```
252 /// let body = b"--X\r\nContent-Disposition: form-data; name=a\r\n\r\n1\r\n--X\r\nContent-Disposition: form-data; name=b\r\n\r\n2\r\n--X--";
253 /// let mut reader = form_net::MultipartReader::new(b"multipart/form-data; boundary=X", &body[..])?;
254 /// let mut names = Vec::new();
255 /// while let Some(part) = reader.next_part()? {
256 /// names.push(part.head().view().name().to_owned());
257 /// }
258 /// assert_eq!(names, ["a", "b"]);
259 /// # Ok::<(), form_net::FormError>(())
260 /// ```
261 pub fn next_part(&mut self) -> Result<Option<PartReader<'_, R>>, FormError> {
262 if self.in_part {
263 self.parser.skip_part();
264 self.pending.clear();
265 while self.in_part {
266 if let Got::End(s) = self.step()? {
267 self.end_part(s);
268 }
269 }
270 }
271 while !self.done {
272 match self.step()? {
273 Got::Start => {
274 self.in_part = true;
275 return Ok(Some(PartReader { inner: self }));
276 }
277 Got::Done => {
278 self.done = true;
279 self.drain_epilogue()?;
280 }
281 _ => {}
282 }
283 }
284 Ok(None)
285 }
286
287 /// Feeds the parser what follows the close delimiter, to the end of the
288 /// body, so the epilogue and body budgets hold.
289 fn drain_epilogue(&mut self) -> Result<(), FormError> {
290 loop {
291 self.fill()?;
292 // `fill` leaves the buffer empty only at the end of the body.
293 if self.start >= self.end {
294 return Ok(());
295 }
296 let input = self.buf.get(self.start..self.end).unwrap_or(&[]);
297 let step = self.parser.parse(input, self.eof)?;
298 if step.consumed == 0 {
299 return Ok(());
300 }
301 self.start = self.start.saturating_add(step.consumed);
302 }
303 }
304
305 fn end_part(&mut self, summary: PartSummary) {
306 self.in_part = false;
307 self.last = Some(summary);
308 self.pending.clear();
309 }
310}
311
312/// One part of a [`MultipartReader`]: read it like a file.
313///
314/// `Read` reports a parse error as `std::io::Error` with kind `InvalidData`
315/// and the `FormError` as its source.
316///
317/// # Examples
318///
319/// ```
320/// use std::io::Read;
321///
322/// let body = b"--X\r\nContent-Disposition: form-data; name=f; filename=a.bin\r\n\r\n0123\r\n--X--";
323/// let mut reader = form_net::MultipartReader::new(b"multipart/form-data; boundary=X", &body[..])?;
324/// let mut part = reader.next_part()?.unwrap();
325/// let mut bytes = Vec::new();
326/// part.read_to_end(&mut bytes)?;
327/// assert_eq!(bytes, b"0123");
328/// # Ok::<(), Box<dyn std::error::Error>>(())
329/// ```
330pub struct PartReader<'r, R: Read> {
331 inner: &'r mut MultipartReader<R>,
332}
333
334impl<R: Read> fmt::Debug for PartReader<'_, R> {
335 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
336 f.debug_struct("PartReader")
337 .field("head", &self.inner.head)
338 .finish_non_exhaustive()
339 }
340}
341
342impl<R: Read> PartReader<'_, R> {
343 /// The part's head, copied when the part started.
344 ///
345 /// # Examples
346 ///
347 /// ```
348 /// let body = b"--X\r\nContent-Disposition: form-data; name=f; filename=a.txt\r\n\r\nhi\r\n--X--";
349 /// let mut reader = form_net::MultipartReader::new(b"multipart/form-data; boundary=X", &body[..])?;
350 /// let part = reader.next_part()?.unwrap();
351 /// let head = part.head().view();
352 /// assert_eq!((head.name(), head.is_file()), ("f", true));
353 /// # Ok::<(), form_net::FormError>(())
354 /// ```
355 #[must_use]
356 pub fn head(&self) -> &OwnedPartHead {
357 &self.inner.head
358 }
359
360 /// Reads the rest of the part and checks it as text (its charset, else
361 /// the `_charset_` field before it, else UTF-8), bounded by
362 /// `max_value_bytes` for file parts too.
363 ///
364 /// # Errors
365 ///
366 /// Every multipart error; `Encoding { InvalidUtf8 | UnsupportedCharset }`;
367 /// `Limit { ValueLength }`.
368 ///
369 /// # Examples
370 ///
371 /// ```
372 /// let body = b"--X\r\nContent-Disposition: form-data; name=title\r\n\r\nHoliday\r\n--X--";
373 /// let mut reader = form_net::MultipartReader::new(b"multipart/form-data; boundary=X", &body[..])?;
374 /// let mut part = reader.next_part()?.unwrap();
375 /// assert_eq!(part.text()?, "Holiday");
376 /// # Ok::<(), form_net::FormError>(())
377 /// ```
378 pub fn text(&mut self) -> Result<String, FormError> {
379 let own = self.inner.head.view().charset();
380 let cap = self.inner.parser.limits().value() as usize;
381 let mut out = Vec::new();
382 let read = (|| {
383 while let Some(chunk) = self.next_chunk()? {
384 if out.len().saturating_add(chunk.len()) > cap {
385 return Err(FormError::limit(
386 crate::Limit::ValueLength,
387 Location::in_part(
388 Some(self.inner.head.view().index()),
389 self.inner.parser.bytes_seen(),
390 ),
391 ));
392 }
393 crate::wipe::append_wiping(&mut out, chunk, 4096, cap);
394 }
395 Ok(())
396 })();
397 if let Err(e) = read {
398 crate::wipe::wipe_vec(&mut out);
399 return Err(e);
400 }
401 let at = Location::in_part(
402 Some(self.inner.head.view().index()),
403 self.inner.parser.bytes_seen(),
404 );
405 if let Err(reason) = own.rule(self.inner.declared).check(&out) {
406 crate::wipe::wipe_vec(&mut out);
407 return Err(FormError::encoding(reason, at));
408 }
409 String::from_utf8(out).map_err(|e| {
410 let mut bytes = e.into_bytes();
411 crate::wipe::wipe_vec(&mut bytes);
412 FormError::encoding(EncodingError::InvalidUtf8, at)
413 })
414 }
415
416 /// Discards the rest of the part and returns its data length.
417 ///
418 /// # Errors
419 ///
420 /// Every multipart error.
421 ///
422 /// # Examples
423 ///
424 /// ```
425 /// let body = b"--X\r\nContent-Disposition: form-data; name=f; filename=a.bin\r\n\r\n0123\r\n--X--";
426 /// let mut reader = form_net::MultipartReader::new(b"multipart/form-data; boundary=X", &body[..])?;
427 /// let mut part = reader.next_part()?.unwrap();
428 /// assert_eq!(part.skip()?, 4);
429 /// assert!(reader.next_part()?.is_none());
430 /// # Ok::<(), form_net::FormError>(())
431 /// ```
432 pub fn skip(&mut self) -> Result<u64, FormError> {
433 self.inner.parser.skip_part();
434 self.inner.pending.clear();
435 while self.inner.in_part {
436 if let Got::End(s) = self.inner.step()? {
437 self.inner.end_part(s);
438 }
439 }
440 Ok(self.inner.last.map_or(0, |s| s.bytes))
441 }
442
443 /// Streams a file part into `store`.
444 ///
445 /// # Errors
446 ///
447 /// Every multipart error; `Io`, `Store`, `Limit { Disk }`.
448 ///
449 /// # Examples
450 ///
451 /// ```
452 /// // A memory-only store keeps the file off the file system.
453 /// let store = form_net::Store::memory_only();
454 /// let body = b"--X\r\nContent-Disposition: form-data; name=f; filename=a.txt\r\n\r\nhello\r\n--X--";
455 /// let mut reader = form_net::MultipartReader::new(b"multipart/form-data; boundary=X", &body[..])?;
456 /// let file = reader.next_part()?.unwrap().save(&store)?;
457 /// assert_eq!(file.bytes(), Some(&b"hello"[..]));
458 /// # Ok::<(), form_net::FormError>(())
459 /// ```
460 #[cfg(feature = "fs")]
461 #[cfg_attr(docsrs, doc(cfg(feature = "fs")))]
462 pub fn save(&mut self, store: &crate::Store) -> Result<crate::StoredFile, FormError> {
463 use crate::hook::Sink;
464 // One request, one disk limit: the sink starts from what earlier
465 // saves of this body already put on disk.
466 let mut sink = store
467 .sink(self.inner.parser.limits())
468 .with_used_disk(self.inner.disk_used);
469 let head = self.inner.head.clone();
470 sink.open(&head.view())?;
471 let r = (|| {
472 while let Some(chunk) = self.next_chunk()? {
473 sink.write(chunk)?;
474 }
475 sink.close()
476 })();
477 if r.is_err() {
478 sink.abort();
479 } else {
480 self.inner.disk_used = sink.used_disk();
481 }
482 r
483 }
484
485 /// The next piece of data, or `None` at the end of the part.
486 fn next_chunk(&mut self) -> Result<Option<&[u8]>, FormError> {
487 let inner = &mut *self.inner;
488 if inner.pending_at < inner.pending.len() {
489 let chunk = inner.pending.get(inner.pending_at..).unwrap_or(&[]);
490 inner.pending_at = inner.pending.len();
491 return Ok(Some(chunk));
492 }
493 while inner.in_part {
494 match inner.step()? {
495 Got::Data => {
496 inner.pending_at = inner.pending.len();
497 return Ok(Some(&inner.pending));
498 }
499 Got::End(s) => inner.end_part(s),
500 _ => {}
501 }
502 }
503 Ok(None)
504 }
505}
506
507impl<R: Read> Read for PartReader<'_, R> {
508 fn read(&mut self, out: &mut [u8]) -> io::Result<usize> {
509 let inner = &mut *self.inner;
510 loop {
511 if inner.pending_at < inner.pending.len() {
512 let src = inner.pending.get(inner.pending_at..).unwrap_or(&[]);
513 let n = src.len().min(out.len());
514 if let (Some(dst), Some(src)) = (out.get_mut(..n), src.get(..n)) {
515 dst.copy_from_slice(src);
516 }
517 inner.pending_at = inner.pending_at.saturating_add(n);
518 return Ok(n);
519 }
520 if !inner.in_part {
521 return Ok(0);
522 }
523 match inner.step() {
524 Ok(Got::End(s)) => inner.end_part(s),
525 Ok(_) => {}
526 Err(e) => return Err(io::Error::new(io::ErrorKind::InvalidData, e)),
527 }
528 }
529 }
530}