1use multer::Multipart;
2use either::Either;
3
4use crate::request::{Request, local_cache_once};
5use crate::data::{Data, Limits, Outcome};
6use crate::http::{RawStr, Status};
7use crate::form::prelude::*;
8
9type Result<'r, T> = std::result::Result<T, Error<'r>>;
10
11type Field<'r, 'i> = Either<ValueField<'r>, DataField<'r, 'i>>;
12
13pub struct MultipartParser<'r, 'i> {
14 request: &'r Request<'i>,
15 buffer: &'r SharedStack<String>,
16 source: Multipart<'r>,
17 done: bool,
18}
19
20pub struct RawStrParser<'r> {
21 buffer: &'r SharedStack<String>,
22 source: &'r RawStr,
23}
24
25pub enum Parser<'r, 'i> {
26 Multipart(MultipartParser<'r, 'i>),
27 RawStr(RawStrParser<'r>),
28}
29
30impl<'r, 'i> Parser<'r, 'i> {
31 pub async fn new(
32 req: &'r Request<'i>,
33 data: Data<'r>
34 ) -> Outcome<'r, Parser<'r, 'i>, Errors<'r>> {
35 let parser = match req.content_type() {
36 Some(c) if c.is_form() => Self::from_form(req, data).await,
37 Some(c) if c.is_form_data() => Self::from_multipart(req, data).await,
38 _ => return Outcome::Forward((data, Status::UnsupportedMediaType)),
39 };
40
41 match parser {
42 Ok(storage) => Outcome::Success(storage),
43 Err(e) => Outcome::Error((e.status(), e.into()))
44 }
45 }
46
47 async fn from_form(req: &'r Request<'i>, data: Data<'r>) -> Result<'r, Parser<'r, 'i>> {
48 let limit = req.limits().get("form").unwrap_or(Limits::FORM);
49 let string = data.open(limit).into_string().await?;
50 if !string.is_complete() {
51 Err((None, Some(limit.as_u64())))?;
52 }
53
54 Ok(Parser::RawStr(RawStrParser {
55 buffer: local_cache_once!(req, SharedStack::new()),
56 source: RawStr::new(local_cache_once!(req, string.into_inner())),
57 }))
58 }
59
60 async fn from_multipart(req: &'r Request<'i>, data: Data<'r>) -> Result<'r, Parser<'r, 'i>> {
61 let boundary = req.content_type()
62 .ok_or(multer::Error::NoMultipart)?
63 .param("boundary")
64 .ok_or(multer::Error::NoBoundary)?;
65
66 let form_limit = req.limits()
67 .get("data-form")
68 .unwrap_or(Limits::DATA_FORM);
69
70 let stream = data.open(form_limit + 1);
72 let constraints = multer::Constraints::new()
73 .size_limit(multer::SizeLimit::new()
74 .whole_stream(form_limit.into())
75 .per_field(form_limit.into()));
76
77 Ok(Parser::Multipart(MultipartParser {
78 request: req,
79 buffer: local_cache_once!(req, SharedStack::new()),
80 source: Multipart::with_reader_with_constraints(stream, boundary, constraints),
81 done: false,
82 }))
83 }
84
85 pub async fn next(&mut self) -> Option<Result<'r, Field<'r, 'i>>> {
86 match self {
87 Parser::Multipart(ref mut p) => p.next().await,
88 Parser::RawStr(ref mut p) => p.next().map(|f| Ok(Either::Left(f)))
89 }
90 }
91}
92
93impl<'r> RawStrParser<'r> {
94 pub fn new(buffer: &'r SharedStack<String>, source: &'r RawStr) -> Self {
95 RawStrParser { buffer, source }
96 }
97}
98
99impl<'r> Iterator for RawStrParser<'r> {
100 type Item = ValueField<'r>;
101
102 fn next(&mut self) -> Option<Self::Item> {
103 use std::borrow::Cow::*;
104
105 let (name, value) = loop {
106 if self.source.is_empty() {
107 return None;
108 }
109
110 let (field_str, rest) = self.source.split_at_byte(b'&');
111 self.source = rest;
112
113 if !field_str.is_empty() {
114 break field_str.split_at_byte(b'=');
115 }
116 };
117
118 trace!(%name, %value, "url-encoded field");
119 let name_val = match (name.url_decode_lossy(), value.url_decode_lossy()) {
120 (Borrowed(name), Borrowed(val)) => (name, val),
121 (Borrowed(name), Owned(v)) => (name, self.buffer.push(v)),
122 (Owned(name), Borrowed(val)) => (self.buffer.push(name), val),
123 (Owned(mut name), Owned(val)) => {
124 let len = name.len();
125 name.push_str(&val);
126 self.buffer.push_split(name, len)
127 }
128 };
129
130 Some(ValueField::from(name_val))
131 }
132}
133
134#[cfg(test)]
135mod raw_str_parse_tests {
136 use crate::form::ValueField as Field;
137
138 #[test]
139 fn test_skips_empty() {
140 let buffer = super::SharedStack::new();
141 let fields: Vec<_> = super::RawStrParser::new(&buffer, "a&b=c&&&c".into()).collect();
142 assert_eq!(fields, &[Field::parse("a"), Field::parse("b=c"), Field::parse("c")]);
143 }
144
145 #[test]
146 fn test_decodes() {
147 let buffer = super::SharedStack::new();
148 let fields: Vec<_> = super::RawStrParser::new(&buffer, "a+b=c%20d&%26".into()).collect();
149 assert_eq!(fields, &[Field::parse("a b=c d"), Field::parse("&")]);
150 }
151}
152
153impl<'r, 'i> MultipartParser<'r, 'i> {
154 async fn next(&mut self) -> Option<Result<'r, Field<'r, 'i>>> {
157 if self.done {
158 return None;
159 }
160
161 let field = match self.source.next_field().await {
162 Ok(Some(field)) => field,
163 Ok(None) => return None,
164 Err(e) => {
165 self.done = true;
166 return Some(Err(e.into()));
167 }
168 };
169
170 trace!(?field, "multipart field");
172 let content_type = field.content_type().and_then(|m| m.as_ref().parse().ok());
173 let field = if let Some(content_type) = content_type {
174 let (name, file_name) = match (field.name(), field.file_name()) {
175 (None, None) => ("", None),
176 (None, Some(file_name)) => ("", Some(self.buffer.push(file_name))),
177 (Some(name), None) => (self.buffer.push(name), None),
178 (Some(a), Some(b)) => {
179 let (field_name, file_name) = self.buffer.push_two(a, b);
180 (field_name, Some(file_name))
181 }
182 };
183
184 Either::Right(DataField {
185 content_type,
186 request: self.request,
187 name: NameView::new(name),
188 file_name: file_name.map(crate::fs::FileName::new),
189 data: Data::from(field),
190 })
191 } else {
192 let (mut buf, len) = match field.name() {
193 Some(s) => (s.to_string(), s.len()),
194 None => (String::new(), 0)
195 };
196
197 match field.text().await {
198 Ok(text) => buf.push_str(&text),
199 Err(e) => return Some(Err(e.into())),
200 };
201
202 let name_val = self.buffer.push_split(buf, len);
203 Either::Left(ValueField::from(name_val))
204 };
205
206 Some(Ok(field))
207 }
208}