diff --git a/actix-multipart/CHANGES.md b/actix-multipart/CHANGES.md index 6be07f2e2..fec3e50f8 100644 --- a/actix-multipart/CHANGES.md +++ b/actix-multipart/CHANGES.md @@ -2,4 +2,6 @@ ## [0.1.0-alpha.1] - 2019-04-xx +* Do not support nested multipart + * Split multipart support to separate crate diff --git a/actix-multipart/src/error.rs b/actix-multipart/src/error.rs index 1b872187d..995585850 100644 --- a/actix-multipart/src/error.rs +++ b/actix-multipart/src/error.rs @@ -16,6 +16,9 @@ pub enum MultipartError { /// Multipart boundary is not found #[display(fmt = "Multipart boundary is not found")] Boundary, + /// Nested multipart is not supported + #[display(fmt = "Nested multipart is not supported")] + Nested, /// Multipart stream is incomplete #[display(fmt = "Multipart stream is incomplete")] Incomplete, diff --git a/actix-multipart/src/extractor.rs b/actix-multipart/src/extractor.rs index 94eb4c305..52290b60f 100644 --- a/actix-multipart/src/extractor.rs +++ b/actix-multipart/src/extractor.rs @@ -21,19 +21,13 @@ use crate::server::Multipart; /// /// fn index(payload: mp::Multipart) -> impl Future { /// payload.from_err() // <- get multipart stream for current request -/// .and_then(|item| match item { // <- iterate over multipart items -/// mp::Item::Field(field) => { -/// // Field in turn is stream of *Bytes* object -/// Either::A(field.from_err() -/// .fold((), |_, chunk| { -/// println!("-- CHUNK: \n{:?}", std::str::from_utf8(&chunk)); -/// Ok::<_, Error>(()) -/// })) -/// }, -/// mp::Item::Nested(mp) => { -/// // Or item could be nested Multipart stream -/// Either::B(ok(())) -/// } +/// .and_then(|field| { // <- iterate over multipart items +/// // Field in turn is stream of *Bytes* object +/// field.from_err() +/// .fold((), |_, chunk| { +/// println!("-- CHUNK: \n{:?}", std::str::from_utf8(&chunk)); +/// Ok::<_, Error>(()) +/// }) /// }) /// .fold((), |_, _| Ok::<_, Error>(())) /// .map(|_| HttpResponse::Ok().into()) diff --git a/actix-multipart/src/lib.rs b/actix-multipart/src/lib.rs index 602c27931..d8f365b2c 100644 --- a/actix-multipart/src/lib.rs +++ b/actix-multipart/src/lib.rs @@ -3,4 +3,4 @@ mod extractor; mod server; pub use self::error::MultipartError; -pub use self::server::{Field, Item, Multipart}; +pub use self::server::{Field, Multipart}; diff --git a/actix-multipart/src/server.rs b/actix-multipart/src/server.rs index 2dae5fd33..c651fae56 100644 --- a/actix-multipart/src/server.rs +++ b/actix-multipart/src/server.rs @@ -32,18 +32,9 @@ pub struct Multipart { inner: Option>>, } -/// Multipart item -pub enum Item { - /// Multipart field - Field(Field), - /// Nested multipart stream - Nested(Multipart), -} - enum InnerMultipartItem { None, Field(Rc>), - Multipart(Rc>), } #[derive(PartialEq, Debug)] @@ -113,7 +104,7 @@ impl Multipart { } impl Stream for Multipart { - type Item = Item; + type Item = Field; type Error = MultipartError; fn poll(&mut self) -> Poll, Self::Error> { @@ -245,7 +236,7 @@ impl InnerMultipart { Ok(Some(eof)) } - fn poll(&mut self, safety: &Safety) -> Poll, MultipartError> { + fn poll(&mut self, safety: &Safety) -> Poll, MultipartError> { if self.state == InnerState::Eof { Ok(Async::Ready(None)) } else { @@ -262,14 +253,7 @@ impl InnerMultipart { Async::Ready(None) => true, } } - InnerMultipartItem::Multipart(ref mut multipart) => { - match multipart.borrow_mut().poll(safety)? { - Async::NotReady => return Ok(Async::NotReady), - Async::Ready(Some(_)) => continue, - Async::Ready(None) => true, - } - } - _ => false, + InnerMultipartItem::None => false, }; if stop { self.item = InnerMultipartItem::None; @@ -346,24 +330,7 @@ impl InnerMultipart { // nested multipart stream if mt.type_() == mime::MULTIPART { - let inner = if let Some(boundary) = mt.get_param(mime::BOUNDARY) { - Rc::new(RefCell::new(InnerMultipart { - payload: self.payload.clone(), - boundary: boundary.as_str().to_owned(), - state: InnerState::FirstBoundary, - item: InnerMultipartItem::None, - })) - } else { - return Err(MultipartError::Boundary); - }; - - self.item = InnerMultipartItem::Multipart(Rc::clone(&inner)); - - Ok(Async::Ready(Some(Item::Nested(Multipart { - safety: safety.clone(), - error: None, - inner: Some(inner), - })))) + Err(MultipartError::Nested) } else { let field = Rc::new(RefCell::new(InnerField::new( self.payload.clone(), @@ -372,12 +339,12 @@ impl InnerMultipart { )?)); self.item = InnerMultipartItem::Field(Rc::clone(&field)); - Ok(Async::Ready(Some(Item::Field(Field::new( + Ok(Async::Ready(Some(Field::new( safety.clone(), headers, mt, field, - ))))) + )))) } } } @@ -864,50 +831,40 @@ mod tests { let mut multipart = Multipart::new(&headers, payload); match multipart.poll().unwrap() { - Async::Ready(Some(item)) => match item { - Item::Field(mut field) => { - { - let cd = field.content_disposition().unwrap(); - assert_eq!(cd.disposition, DispositionType::FormData); - assert_eq!( - cd.parameters[0], - DispositionParam::Name("file".into()) - ); - } - assert_eq!(field.content_type().type_(), mime::TEXT); - assert_eq!(field.content_type().subtype(), mime::PLAIN); + Async::Ready(Some(mut field)) => { + let cd = field.content_disposition().unwrap(); + assert_eq!(cd.disposition, DispositionType::FormData); + assert_eq!(cd.parameters[0], DispositionParam::Name("file".into())); - match field.poll().unwrap() { - Async::Ready(Some(chunk)) => assert_eq!(chunk, "test"), - _ => unreachable!(), - } - match field.poll().unwrap() { - Async::Ready(None) => (), - _ => unreachable!(), - } + assert_eq!(field.content_type().type_(), mime::TEXT); + assert_eq!(field.content_type().subtype(), mime::PLAIN); + + match field.poll().unwrap() { + Async::Ready(Some(chunk)) => assert_eq!(chunk, "test"), + _ => unreachable!(), } - _ => unreachable!(), - }, + match field.poll().unwrap() { + Async::Ready(None) => (), + _ => unreachable!(), + } + } _ => unreachable!(), } match multipart.poll().unwrap() { - Async::Ready(Some(item)) => match item { - Item::Field(mut field) => { - assert_eq!(field.content_type().type_(), mime::TEXT); - assert_eq!(field.content_type().subtype(), mime::PLAIN); + Async::Ready(Some(mut field)) => { + assert_eq!(field.content_type().type_(), mime::TEXT); + assert_eq!(field.content_type().subtype(), mime::PLAIN); - match field.poll() { - Ok(Async::Ready(Some(chunk))) => assert_eq!(chunk, "data"), - _ => unreachable!(), - } - match field.poll() { - Ok(Async::Ready(None)) => (), - _ => unreachable!(), - } + match field.poll() { + Ok(Async::Ready(Some(chunk))) => assert_eq!(chunk, "data"), + _ => unreachable!(), } - _ => unreachable!(), - }, + match field.poll() { + Ok(Async::Ready(None)) => (), + _ => unreachable!(), + } + } _ => unreachable!(), }