3131//! }
3232//! ```
3333
34- use crate :: Body ;
34+ use std:: task:: Context ;
35+ use std:: task:: Poll ;
36+ use std:: { fmt:: Debug , pin:: Pin , str:: FromStr } ;
37+
38+ use futures_core:: stream:: Stream ;
39+ use multipart:: server:: Multipart as Parser ;
40+ use std:: io:: { Cursor , Read } ;
41+
42+ use crate :: { format_err, Mime , Status } ;
3543pub use entry:: Entry ;
3644
3745mod entry;
3846
3947/// A multipart response body.
40- #[ derive( Debug ) ]
4148pub struct Multipart {
4249 entries : Vec < Entry > ,
43- body : Option < Body > ,
50+ body : Option < Parser < Cursor < String > > > ,
51+ }
52+
53+ impl Debug for Multipart {
54+ fn fmt ( & self , f : & mut std:: fmt:: Formatter < ' _ > ) -> std:: fmt:: Result {
55+ f. debug_struct ( "Multipart" ) . finish ( )
56+ }
4457}
4558
4659impl Multipart {
@@ -53,11 +66,28 @@ impl Multipart {
5366 }
5467
5568 /// Parse a `Body` stream as a `Multipart` instance.
56- pub fn from_body ( body : Body ) -> Self {
57- Self {
69+ pub async fn from_req ( req : & mut crate :: Request ) -> crate :: Result < Self > {
70+ let body = req. take_body ( ) . into_string ( ) . await ?;
71+ let boundary = req
72+ . content_type ( )
73+ . map ( |ct| ct. param ( "boundary" ) . cloned ( ) )
74+ . flatten ( ) ;
75+
76+ let boundary = match boundary {
77+ Some ( boundary) => boundary. as_str ( ) . to_owned ( ) ,
78+ None => {
79+ let mut err =
80+ format_err ! ( "Invalid `Content-Type` header. Expected a `boundary` param" ) ;
81+ err. set_status ( 400 ) ;
82+ return Err ( err) ;
83+ }
84+ } ;
85+
86+ let multipart = Parser :: with_body ( Cursor :: new ( body) , boundary) ;
87+ Ok ( Self {
5888 entries : vec ! [ ] ,
59- body : Some ( body ) ,
60- }
89+ body : Some ( multipart ) ,
90+ } )
6191 }
6292
6393 /// Add a new entry to the `Multipart` instance.
@@ -69,8 +99,41 @@ impl Multipart {
6999 }
70100}
71101
72- // TODO
73- // impl Stream for Multipart {}
102+ impl Stream for Multipart {
103+ type Item = crate :: Result < Entry > ;
104+
105+ fn poll_next ( mut self : Pin < & mut Self > , _cx : & mut Context ) -> Poll < Option < Self :: Item > > {
106+ let body = match self . body . as_mut ( ) {
107+ None => return Poll :: Ready ( None ) ,
108+ Some ( body) => body,
109+ } ;
110+
111+ match body. read_entry ( ) {
112+ Ok ( Some ( mut field) ) => {
113+ let mut body = vec ! [ ] ;
114+ field. data . read_to_end ( & mut body) . status ( 400 ) ?;
115+
116+ let mut entry = Entry :: new ( field. headers . name , body) ;
117+ entry. set_file_name ( field. headers . filename ) ;
118+ let mime = field
119+ . headers
120+ . content_type
121+ . map ( |ct| Mime :: from_str ( & ct. to_string ( ) ) )
122+ . transpose ( ) ?;
123+ entry. set_content_type ( mime) ;
124+
125+ Poll :: Ready ( Some ( Ok ( entry) ) )
126+ }
127+ Ok ( None ) => Poll :: Ready ( None ) ,
128+ Err ( _e) => {
129+ // TODO: forward error?
130+ let mut err = format_err ! ( "Invalid multipart entry" ) ;
131+ err. set_status ( 400 ) ;
132+ Poll :: Ready ( Some ( Err ( err) ) )
133+ }
134+ }
135+ }
136+ }
74137
75138// TODO
76139// impl From<Multipart> for Body {}
0 commit comments