warp/filters/
multipart.rs1use std::error::Error as StdError;
6use std::fmt::{Display, Formatter};
7use std::future::Future;
8use std::pin::Pin;
9use std::task::{Context, Poll};
10use std::{fmt, io};
11
12use bytes::{Buf, Bytes};
13use futures_util::{future, Stream};
14use headers::ContentType;
15use hyper::Body;
16use mime::Mime;
17use multer::{Field as PartInner, Multipart as FormDataInner};
18
19use crate::filter::{Filter, FilterBase, Internal};
20use crate::reject::{self, Rejection};
21
22const DEFAULT_FORM_DATA_MAX_LENGTH: u64 = 1024 * 1024 * 2;
24
25#[derive(Debug, Clone)]
29pub struct FormOptions {
30 max_length: Option<u64>,
31}
32
33pub struct FormData {
37 inner: FormDataInner<'static>,
38}
39
40pub struct Part {
44 part: PartInner<'static>,
45}
46
47pub fn form() -> FormOptions {
52 FormOptions {
53 max_length: Some(DEFAULT_FORM_DATA_MAX_LENGTH),
54 }
55}
56
57impl FormOptions {
60 pub fn max_length(mut self, max: impl Into<Option<u64>>) -> Self {
65 self.max_length = max.into();
66 self
67 }
68}
69
70type FormFut = Pin<Box<dyn Future<Output = Result<(FormData,), Rejection>> + Send>>;
71
72impl FilterBase for FormOptions {
73 type Extract = (FormData,);
74 type Error = Rejection;
75 type Future = FormFut;
76
77 fn filter(&self, _: Internal) -> Self::Future {
78 let boundary = super::header::header2::<ContentType>().and_then(|ct| {
79 let mime = Mime::from(ct);
80 let mime = mime
81 .get_param("boundary")
82 .map(|v| v.to_string())
83 .ok_or_else(|| reject::invalid_header("content-type"));
84 future::ready(mime)
85 });
86
87 let filt = boundary
88 .and(super::body::body())
89 .map(|boundary: String, body| {
90 let body = BodyIoError(body);
91 FormData {
92 inner: FormDataInner::new(body, &boundary),
93 }
94 });
95
96 if let Some(max_length) = self.max_length {
97 Box::pin(
98 super::body::content_length_limit(max_length)
99 .and(filt)
100 .filter(Internal),
101 )
102 } else {
103 Box::pin(filt.filter(Internal))
104 }
105 }
106}
107
108impl fmt::Debug for FormData {
111 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
112 f.debug_struct("FormData").finish()
113 }
114}
115
116impl Stream for FormData {
117 type Item = Result<Part, crate::Error>;
118
119 fn poll_next(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Option<Self::Item>> {
120 match self.inner.poll_next_field(cx) {
121 Poll::Pending => Poll::Pending,
122 Poll::Ready(Ok(Some(part))) => {
123 if part.name().is_some() || part.file_name().is_some() {
124 Poll::Ready(Some(Ok(Part { part })))
125 } else {
126 Poll::Ready(Some(Err(crate::Error::new(MultipartFieldMissingName))))
127 }
128 }
129 Poll::Ready(Ok(None)) => Poll::Ready(None),
130 Poll::Ready(Err(err)) => Poll::Ready(Some(Err(crate::Error::new(err)))),
131 }
132 }
133}
134
135impl Part {
138 pub fn name(&self) -> &str {
140 self.part
141 .name()
142 .unwrap_or_else(|| self.part.file_name().expect("checked for name previously"))
143 }
144
145 pub fn filename(&self) -> Option<&str> {
147 self.part.file_name()
148 }
149
150 pub fn content_type(&self) -> Option<&str> {
152 let content_type = self.part.content_type();
153 content_type.map(|t| t.as_ref())
154 }
155
156 pub async fn data(&mut self) -> Option<Result<impl Buf, crate::Error>> {
158 future::poll_fn(|cx| self.poll_next(cx)).await
159 }
160
161 pub fn stream(self) -> impl Stream<Item = Result<impl Buf, crate::Error>> {
163 PartStream(self)
164 }
165
166 fn poll_next(&mut self, cx: &mut Context<'_>) -> Poll<Option<Result<Bytes, crate::Error>>> {
167 match Pin::new(&mut self.part).poll_next(cx) {
168 Poll::Pending => Poll::Pending,
169 Poll::Ready(Some(Ok(bytes))) => Poll::Ready(Some(Ok(bytes))),
170 Poll::Ready(None) => Poll::Ready(None),
171 Poll::Ready(Some(Err(err))) => Poll::Ready(Some(Err(crate::Error::new(err)))),
172 }
173 }
174}
175
176impl fmt::Debug for Part {
177 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
178 let mut builder = f.debug_struct("Part");
179 builder.field("name", &self.name());
180
181 if let Some(ref filename) = self.part.file_name() {
182 builder.field("filename", filename);
183 }
184
185 if let Some(ref mime) = self.part.content_type() {
186 builder.field("content_type", mime);
187 }
188
189 builder.finish()
190 }
191}
192
193struct PartStream(Part);
194
195impl Stream for PartStream {
196 type Item = Result<Bytes, crate::Error>;
197
198 fn poll_next(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Option<Self::Item>> {
199 self.0.poll_next(cx)
200 }
201}
202
203struct BodyIoError(Body);
204
205impl Stream for BodyIoError {
206 type Item = io::Result<Bytes>;
207
208 fn poll_next(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Option<Self::Item>> {
209 match Pin::new(&mut self.0).poll_next(cx) {
210 Poll::Pending => Poll::Pending,
211 Poll::Ready(Some(Ok(bytes))) => Poll::Ready(Some(Ok(bytes))),
212 Poll::Ready(None) => Poll::Ready(None),
213 Poll::Ready(Some(Err(err))) => {
214 Poll::Ready(Some(Err(io::Error::new(io::ErrorKind::Other, err))))
215 }
216 }
217 }
218}
219
220#[derive(Debug)]
222struct MultipartFieldMissingName;
223
224impl Display for MultipartFieldMissingName {
225 fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
226 write!(f, "Multipart field is missing a name")
227 }
228}
229
230impl StdError for MultipartFieldMissingName {}