Skip to main content

ntex_multipart/
field.rs

1use crate::MultipartError;
2use crate::payload::{PayloadBuffer, PayloadRef};
3use crate::safety::Safety;
4use futures::Stream;
5use ntex::http::error::PayloadError;
6use ntex::http::{HeaderMap, header};
7use ntex::util::Bytes;
8use ntex_files::header::ContentDisposition;
9use std::cell::RefCell;
10use std::pin::Pin;
11use std::rc::Rc;
12use std::task::{Context, Poll};
13use std::{cmp, fmt};
14
15/// A single field in a multipart stream
16pub struct Field {
17    /// Field's Content-Type.
18    content_type: Option<mime::Mime>,
19
20    /// Field's Content-Disposition.
21    content_disposition: Option<ContentDisposition>,
22
23    /// Form field name.
24    pub(crate) form_field_name: String,
25
26    /// Field's header map.
27    headers: HeaderMap,
28
29    inner: Rc<RefCell<InnerField>>,
30    safety: Safety,
31}
32
33impl Field {
34    pub(crate) fn new(
35        safety: Safety,
36        headers: HeaderMap,
37        content_type: Option<mime::Mime>,
38        content_disposition: Option<ContentDisposition>,
39        form_field_name: Option<String>,
40        inner: Rc<RefCell<InnerField>>,
41    ) -> Self {
42        Field {
43            content_type,
44            content_disposition,
45            form_field_name: form_field_name.unwrap_or_default(),
46            headers,
47            inner,
48            safety,
49        }
50    }
51
52    /// Get a map of headers
53    pub fn headers(&self) -> &HeaderMap {
54        &self.headers
55    }
56
57    /// Get the content type of the field
58    pub fn content_type(&self) -> Option<&mime::Mime> {
59        self.content_type.as_ref()
60    }
61
62    /// Returns this field's parsed Content-Disposition header, if set.
63    pub fn content_disposition(&self) -> Option<&ContentDisposition> {
64        self.content_disposition.as_ref()
65    }
66
67    /// Returns the field's name, if set.
68    pub fn name(&self) -> Option<&str> {
69        self.content_disposition()?.get_name()
70    }
71}
72
73impl Stream for Field {
74    type Item = Result<Bytes, MultipartError>;
75
76    fn poll_next(self: Pin<&mut Self>, cx: &mut Context) -> Poll<Option<Self::Item>> {
77        if self.safety.current() {
78            let mut inner = self.inner.borrow_mut();
79            if let Some(mut payload) = inner.payload.as_ref().unwrap().get_mut(&self.safety) {
80                payload.poll_stream(cx)?;
81            }
82            inner.poll(&self.safety)
83        } else if !self.safety.is_clean() {
84            Poll::Ready(Some(Err(MultipartError::NotConsumed)))
85        } else {
86            Poll::Pending
87        }
88    }
89}
90
91impl fmt::Debug for Field {
92    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
93        if let Some(ct) = &self.content_type {
94            writeln!(f, "\nField: {}", ct)?;
95        } else {
96            writeln!(f, "\nField:")?;
97        }
98        writeln!(f, "  boundary: {}", self.inner.borrow().boundary)?;
99        writeln!(f, "  headers:")?;
100        for (key, val) in self.headers.iter() {
101            writeln!(f, "    {:?}: {:?}", key, val)?;
102        }
103        Ok(())
104    }
105}
106
107pub(crate) struct InnerField {
108    payload: Option<PayloadRef>,
109    boundary: String,
110    eof: bool,
111    length: Option<u64>,
112}
113
114impl InnerField {
115    pub(crate) fn new(
116        payload: PayloadRef,
117        boundary: String,
118        headers: &HeaderMap,
119    ) -> Result<InnerField, PayloadError> {
120        let len = if let Some(len) = headers.get(&header::CONTENT_LENGTH) {
121            if let Ok(s) = len.to_str() {
122                if let Ok(len) = s.parse::<u64>() {
123                    Some(len)
124                } else {
125                    return Err(PayloadError::Incomplete(None));
126                }
127            } else {
128                return Err(PayloadError::Incomplete(None));
129            }
130        } else {
131            None
132        };
133
134        Ok(InnerField { boundary, payload: Some(payload), eof: false, length: len })
135    }
136
137    /// Reads body part content chunk of the specified size.
138    /// The body part must has `Content-Length` header with proper value.
139    pub(crate) fn read_len(
140        payload: &mut PayloadBuffer,
141        size: &mut u64,
142    ) -> Poll<Option<Result<Bytes, MultipartError>>> {
143        if *size == 0 {
144            Poll::Ready(None)
145        } else {
146            match payload.read_max(*size)? {
147                Some(mut chunk) => {
148                    let len = cmp::min(chunk.len() as u64, *size);
149                    *size -= len;
150                    let ch = chunk.split_to(len as usize);
151                    if !chunk.is_empty() {
152                        payload.unprocessed(chunk);
153                    }
154                    Poll::Ready(Some(Ok(ch)))
155                }
156                None => {
157                    if payload.eof && (*size != 0) {
158                        Poll::Ready(Some(Err(MultipartError::Incomplete)))
159                    } else {
160                        Poll::Pending
161                    }
162                }
163            }
164        }
165    }
166
167    /// Reads content chunk of body part with unknown length.
168    /// The `Content-Length` header for body part is not necessary.
169    pub(crate) fn read_stream(
170        payload: &mut PayloadBuffer,
171        boundary: &str,
172    ) -> Poll<Option<Result<Bytes, MultipartError>>> {
173        let mut pos = 0;
174
175        let len = payload.buf.len();
176        if len == 0 {
177            return if payload.eof {
178                Poll::Ready(Some(Err(MultipartError::Incomplete)))
179            } else {
180                Poll::Pending
181            };
182        }
183
184        // check boundary
185        if len > 4 && payload.buf[0] == b'\r' {
186            let b_len = if &payload.buf[..2] == b"\r\n" && &payload.buf[2..4] == b"--" {
187                Some(4)
188            } else if &payload.buf[1..3] == b"--" {
189                Some(3)
190            } else {
191                None
192            };
193
194            if let Some(b_len) = b_len {
195                let b_size = boundary.len() + b_len;
196                if len < b_size {
197                    return Poll::Pending;
198                } else if &payload.buf[b_len..b_size] == boundary.as_bytes() {
199                    // found boundary
200                    return Poll::Ready(None);
201                }
202            }
203        }
204
205        loop {
206            return if let Some(idx) = twoway::find_bytes(&payload.buf[pos..], b"\r") {
207                let cur = pos + idx;
208
209                // check if we have enough data for boundary detection
210                if cur + 4 > len {
211                    if cur > 0 {
212                        Poll::Ready(Some(Ok(payload.buf.split_to(cur))))
213                    } else {
214                        Poll::Pending
215                    }
216                } else {
217                    // check boundary
218                    if (&payload.buf[cur..cur + 2] == b"\r\n"
219                        && &payload.buf[cur + 2..cur + 4] == b"--")
220                        || (&payload.buf[cur..=cur] == b"\r"
221                            && &payload.buf[cur + 1..cur + 3] == b"--")
222                    {
223                        if cur != 0 {
224                            // return buffer
225                            Poll::Ready(Some(Ok(payload.buf.split_to(cur))))
226                        } else {
227                            pos = cur + 1;
228                            continue;
229                        }
230                    } else {
231                        // not boundary
232                        pos = cur + 1;
233                        continue;
234                    }
235                }
236            } else {
237                Poll::Ready(Some(Ok(payload.buf.take())))
238            };
239        }
240    }
241
242    pub(crate) fn poll(&mut self, s: &Safety) -> Poll<Option<Result<Bytes, MultipartError>>> {
243        if self.payload.is_none() {
244            return Poll::Ready(None);
245        }
246
247        let result = if let Some(mut payload) = self.payload.as_ref().unwrap().get_mut(s) {
248            if !self.eof {
249                let res = if let Some(ref mut len) = self.length {
250                    InnerField::read_len(&mut payload, len)
251                } else {
252                    InnerField::read_stream(&mut payload, &self.boundary)
253                };
254
255                match res {
256                    Poll::Pending => return Poll::Pending,
257                    Poll::Ready(Some(Ok(bytes))) => return Poll::Ready(Some(Ok(bytes))),
258                    Poll::Ready(Some(Err(e))) => return Poll::Ready(Some(Err(e))),
259                    Poll::Ready(None) => self.eof = true,
260                }
261            }
262
263            match payload.readline() {
264                Ok(None) => Poll::Pending,
265                Ok(Some(line)) => {
266                    if line.as_ref() != b"\r\n" {
267                        log::warn!(
268                            "multipart field did not read all the data or it is malformed"
269                        );
270                    }
271                    Poll::Ready(None)
272                }
273                Err(e) => Poll::Ready(Some(Err(e))),
274            }
275        } else {
276            Poll::Pending
277        };
278
279        if let Poll::Ready(None) = result {
280            self.payload.take();
281        }
282        result
283    }
284}