form_net/multipart/owned_head.rs
1//! An owned copy of a part head, for code that needs the head after the
2//! `parse` call that produced it.
3
4use alloc::vec::Vec;
5use core::fmt;
6use core::ops::Range;
7
8use crate::multipart::filename::{FileName, FileNameSource};
9use crate::multipart::parser::{Charset, PartHead, PartKind};
10
11/// An owned copy of a [`PartHead`]. Its buffer is reused for the next head
12/// copied into it, so a driver that keeps one never allocates per part once
13/// the buffer has grown to the largest head.
14///
15/// # Examples
16///
17/// ```
18/// use form_net::{Boundary, MultipartEvent, Limits, MultipartParser, OwnedPartHead, Policy};
19///
20/// let mut parser = MultipartParser::new(Boundary::new(b"X")?, &Limits::DEFAULT, &Policy::DEFAULT)?;
21/// let body = b"--X\r\nContent-Disposition: form-data; name=\"a\"\r\n\r\n1\r\n--X--";
22/// let mut kept = OwnedPartHead::new();
23/// let step = parser.parse(body, true)?;
24/// if let MultipartEvent::PartStart(head) = step.event {
25/// kept.copy_from(&head);
26/// }
27/// assert_eq!(kept.view().name(), "a");
28/// # Ok::<(), form_net::FormError>(())
29/// ```
30#[derive(Clone, Default)]
31pub struct OwnedPartHead {
32 buf: Vec<u8>,
33 index: u32,
34 block: Range<usize>,
35 name: Range<usize>,
36 name_raw: Range<usize>,
37 kind: Option<PartKind>,
38 filename: Option<(Range<usize>, FileNameSource)>,
39 content_type: Option<Range<usize>>,
40 charset: Option<Charset>,
41}
42
43impl fmt::Debug for OwnedPartHead {
44 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
45 fmt::Debug::fmt(&self.view(), f)
46 }
47}
48
49impl OwnedPartHead {
50 /// An empty head; [`view`](Self::view) of it is a field with no name.
51 ///
52 /// # Examples
53 ///
54 /// ```
55 /// use form_net::OwnedPartHead;
56 ///
57 /// let head = OwnedPartHead::new();
58 /// assert_eq!(head.view().name(), "");
59 /// assert!(!head.view().is_file());
60 /// ```
61 #[must_use]
62 pub fn new() -> OwnedPartHead {
63 OwnedPartHead::default()
64 }
65
66 /// An empty head whose buffer already holds `capacity` bytes.
67 ///
68 /// # Examples
69 ///
70 /// ```
71 /// use form_net::OwnedPartHead;
72 ///
73 /// // Room for a 1 KiB header block before the first copy allocates.
74 /// let head = OwnedPartHead::with_capacity(1024);
75 /// assert_eq!(head.view().header_bytes(), 0);
76 /// ```
77 #[must_use]
78 pub fn with_capacity(capacity: usize) -> OwnedPartHead {
79 let mut head = OwnedPartHead::default();
80 head.buf = Vec::with_capacity(capacity);
81 head
82 }
83
84 fn push(&mut self, bytes: &[u8]) -> Range<usize> {
85 let start = self.buf.len();
86 // The capacity was reserved in `copy_from`, so this never moves.
87 crate::wipe::append_wiping(&mut self.buf, bytes, bytes.len(), usize::MAX);
88 start..self.buf.len()
89 }
90
91 /// Replaces this copy with `head`. The old bytes are wiped first, and a
92 /// buffer too small for the new head is wiped and freed before its
93 /// replacement is allocated, so no copy of a head is freed unwiped and
94 /// two buffers are never held at once. The header block is copied once:
95 /// the name, file name, and content type that lie inside it are kept as
96 /// positions in that copy (D-140).
97 ///
98 /// # Examples
99 ///
100 /// ```
101 /// # use form_net::{Boundary, Limits, MultipartEvent, MultipartParser, OwnedPartHead, Policy};
102 /// # let mut parser = MultipartParser::new(Boundary::new(b"X")?, &Limits::DEFAULT, &Policy::DEFAULT)?;
103 /// # let body = b"--X\r\nContent-Disposition: form-data; name=a\r\n\r\n1\r\n--X--";
104 /// let mut kept = OwnedPartHead::new();
105 /// if let MultipartEvent::PartStart(head) = parser.parse(body, true)?.event {
106 /// kept.copy_from(&head);
107 /// }
108 /// // The copy outlives the parser that produced the head.
109 /// drop(parser);
110 /// assert_eq!(kept.view().name(), "a");
111 /// # Ok::<(), form_net::FormError>(())
112 /// ```
113 pub fn copy_from(&mut self, head: &PartHead<'_>) {
114 crate::wipe::wipe(&mut self.buf);
115 self.buf.clear();
116 let block = head.block();
117 let outside = |s: &[u8]| {
118 if within(block, s).is_some() {
119 0
120 } else {
121 s.len()
122 }
123 };
124 let needed = [
125 block.len(),
126 outside(head.name().as_bytes()),
127 outside(head.name_raw()),
128 head.filename().map_or(0, |f| outside(f.raw())),
129 head.content_type().map_or(0, |c| outside(c.raw())),
130 ]
131 .iter()
132 .fold(0usize, |a, n| a.saturating_add(*n));
133 if needed > self.buf.capacity() {
134 let mut old = core::mem::take(&mut self.buf);
135 crate::wipe::wipe_vec(&mut old);
136 drop(old);
137 self.buf = Vec::with_capacity(needed);
138 }
139 self.index = head.index();
140 self.block = self.push(block);
141 let base = self.block.start;
142 let mut place = |s: &[u8]| match within(block, s) {
143 Some(r) => r.start.saturating_add(base)..r.end.saturating_add(base),
144 None => {
145 // As `push`, on the buffer alone, so the fields stay free.
146 let start = self.buf.len();
147 crate::wipe::append_wiping(&mut self.buf, s, s.len(), usize::MAX);
148 start..self.buf.len()
149 }
150 };
151 self.name = place(head.name().as_bytes());
152 self.name_raw = place(head.name_raw());
153 self.kind = Some(head.kind());
154 self.filename = head.filename().map(|f| (place(f.raw()), f.source()));
155 self.content_type = head.content_type().map(|c| place(c.raw()));
156 self.charset = Some(head.charset());
157 }
158
159 /// The usual borrowed view.
160 ///
161 /// # Examples
162 ///
163 /// ```
164 /// # use form_net::{Boundary, Limits, MultipartEvent, MultipartParser, OwnedPartHead, Policy};
165 /// # let mut parser = MultipartParser::new(Boundary::new(b"X")?, &Limits::DEFAULT, &Policy::DEFAULT)?;
166 /// # let body = b"--X\r\nContent-Disposition: form-data; name=f; filename=a.txt\r\n\r\nhi\r\n--X--";
167 /// let mut kept = OwnedPartHead::new();
168 /// if let MultipartEvent::PartStart(head) = parser.parse(body, true)?.event {
169 /// kept.copy_from(&head);
170 /// }
171 /// let head = kept.view();
172 /// assert!(head.is_file());
173 /// assert_eq!(head.filename().unwrap().raw(), b"a.txt");
174 /// # Ok::<(), form_net::FormError>(())
175 /// ```
176 #[must_use]
177 pub fn view(&self) -> PartHead<'_> {
178 let get = |r: &Range<usize>| self.buf.get(r.clone()).unwrap_or(&[]);
179 PartHead::from_parts(
180 self.index,
181 get(&self.block),
182 core::str::from_utf8(get(&self.name)).unwrap_or(""),
183 get(&self.name_raw),
184 self.kind.unwrap_or(PartKind::Field),
185 self.filename
186 .as_ref()
187 .map(|(r, source)| FileName::new(get(r), *source)),
188 self.content_type.as_ref().map(get),
189 self.charset.unwrap_or(Charset::Unspecified),
190 )
191 }
192}
193
194impl Drop for OwnedPartHead {
195 fn drop(&mut self) {
196 // Only the length can hold head bytes: `copy_from` wipes the old
197 // bytes before every reuse and moves to a fresh buffer (wiping the
198 // old one) when it must grow, so the spare capacity, 9.6 KiB under
199 // the default limits, was never written (D-103).
200 crate::wipe::wipe(&mut self.buf);
201 }
202}
203
204/// Where `part` lies inside `whole`, when it is a subslice of it: compared
205/// by address, so equal bytes elsewhere do not count.
206fn within(whole: &[u8], part: &[u8]) -> Option<Range<usize>> {
207 let start = (part.as_ptr() as usize).checked_sub(whole.as_ptr() as usize)?;
208 let end = start.checked_add(part.len())?;
209 (end <= whole.len()).then_some(start..end)
210}