11// COPY OF 'src/rust/cmn.rs'
22// DO NOT EDIT
33use std:: marker:: MarkerTrait ;
4- use std:: io:: { self , Read , Seek , Cursor } ;
4+ use std:: io:: { self , Read , Seek , Cursor , Write , SeekFrom } ;
5+ use std:: default:: Default ;
56
6- use mime;
7+ use mime:: { Mime , TopLevel , SubLevel , Attr , Value } ;
78use oauth2;
89use hyper;
10+ use hyper:: header:: { ContentType , ContentLength , Headers } ;
11+ use hyper:: http:: LINE_ENDING ;
912
1013/// Identifies the Hub. There is only one per library, this trait is supposed
1114/// to make intended use more explicit.
@@ -119,19 +122,26 @@ pub enum Result<T = ()> {
119122 Success ( T ) ,
120123}
121124
125+ const BOUNDARY : & ' static str = "MDuXWGyeE33QFXGchb2VFWc4Z7945d" ;
122126
123127/// Provides a `Read` interface that converts multiple parts into the protocol
124128/// identified by [RFC2387](https://tools.ietf.org/html/rfc2387).
125129/// **Note**: This implementation is just as rich as it needs to be to perform uploads
126130/// to google APIs, and might not be a fully-featured implementation.
127131#[ derive( Default ) ]
128132pub struct MultiPartReader < ' a > {
129- raw_parts : Vec < ( hyper :: header :: Headers , & ' a mut Read ) > ,
133+ raw_parts : Vec < ( Headers , & ' a mut Read ) > ,
130134 current_part : Option < ( Cursor < Vec < u8 > > , & ' a mut Read ) > ,
135+ last_part_boundary : Option < Cursor < Vec < u8 > > > ,
131136}
132137
133138impl < ' a > MultiPartReader < ' a > {
134139
140+ /// Reserve memory for exactly the given amount of parts
141+ pub fn reserve_exact ( & mut self , cap : usize ) {
142+ self . raw_parts . reserve_exact ( cap) ;
143+ }
144+
135145 /// Add a new part to the queue of parts to be read on the first `read` call.
136146 ///
137147 /// # Arguments
@@ -145,15 +155,88 @@ impl<'a> MultiPartReader<'a> {
145155 /// # Panics
146156 ///
147157 /// If this method is called after the first `read` call, it will panic
148- pub fn add_part ( mut self , reader : & ' a mut Read , size : u64 , mime_type : & mime:: Mime ) -> MultiPartReader < ' a > {
149- // let mut headers = hyper::header::Headers::
150- // raw_parts.push((headers, reader));
158+ pub fn add_part ( & mut self , reader : & ' a mut Read , size : u64 , mime_type : Mime ) -> & mut MultiPartReader < ' a > {
159+ let mut headers = Headers :: new ( ) ;
160+ headers. set ( ContentType ( mime_type) ) ;
161+ headers. set ( ContentLength ( size) ) ;
162+ self . raw_parts . push ( ( headers, reader) ) ;
151163 self
152164 }
165+
166+ /// Returns the mime-type representing our multi-part message.
167+ /// Use it with the ContentType header.
168+ pub fn mime_type ( & self ) -> Mime {
169+ Mime (
170+ TopLevel :: Multipart ,
171+ SubLevel :: Ext ( "Related" . to_string ( ) ) ,
172+ vec ! [ ( Attr :: Ext ( "boundary" . to_string( ) ) , Value :: Ext ( BOUNDARY . to_string( ) ) ) ] ,
173+ )
174+ }
175+
176+ /// Returns true if we are totally used
177+ fn is_depleted ( & self ) -> bool {
178+ self . raw_parts . len ( ) == 0 && self . current_part . is_none ( ) && self . last_part_boundary . is_none ( )
179+ }
180+
181+ /// Returns true if we are handling our last part
182+ fn is_last_part ( & self ) -> bool {
183+ self . raw_parts . len ( ) == 0 && self . current_part . is_some ( )
184+ }
153185}
154186
155187impl < ' a > Read for MultiPartReader < ' a > {
156188 fn read ( & mut self , buf : & mut [ u8 ] ) -> io:: Result < usize > {
157- Err ( io:: Error :: from_os_error ( 0 ) )
189+ if self . last_part_boundary . is_some ( ) {
190+ let br = self . last_part_boundary . as_mut ( ) . unwrap ( ) . read ( buf) . unwrap_or ( 0 ) ;
191+ if br < buf. len ( ) {
192+ self . last_part_boundary = None ;
193+ }
194+ return Ok ( br)
195+ } else if self . is_depleted ( ) {
196+ return Ok ( 0 )
197+ } else if self . raw_parts . len ( ) > 0 && self . current_part . is_none ( ) {
198+ let ( headers, reader) = self . raw_parts . remove ( 0 ) ;
199+ let mut c = Cursor :: new ( Vec :: < u8 > :: new ( ) ) ;
200+ write ! ( & mut c, "{}--{}{}{}{}" , LINE_ENDING , BOUNDARY , LINE_ENDING ,
201+ headers, LINE_ENDING ) . unwrap ( ) ;
202+ c. seek ( SeekFrom :: Start ( 0 ) ) . unwrap ( ) ;
203+ self . current_part = Some ( ( c, reader) ) ;
204+ }
205+ // read headers as long as possible
206+ let ( hb, rr) = {
207+ let & mut ( ref mut c, ref mut reader) = self . current_part . as_mut ( ) . unwrap ( ) ;
208+ let b = c. read ( buf) . unwrap_or ( 0 ) ;
209+ ( b, reader. read ( & mut buf[ b..] ) )
210+ } ;
211+
212+ match rr {
213+ Ok ( bytes_read) => {
214+ if hb < buf. len ( ) && bytes_read == 0 {
215+ if self . is_last_part ( ) {
216+ // before clearing the last part, we will add the boundary that
217+ // will be written last
218+ self . last_part_boundary = Some ( Cursor :: new (
219+ format ! ( "{}--{}" , LINE_ENDING , BOUNDARY ) . into_bytes ( ) ) )
220+ }
221+ // We are depleted - this can trigger the next part to come in
222+ self . current_part = None ;
223+ }
224+ let mut total_bytes_read = hb + bytes_read;
225+ while total_bytes_read < buf. len ( ) && !self . is_depleted ( ) {
226+ match self . read ( & mut buf[ total_bytes_read ..] ) {
227+ Ok ( br) => total_bytes_read += br,
228+ Err ( err) => return Err ( err) ,
229+ }
230+ }
231+ Ok ( total_bytes_read)
232+ }
233+ Err ( err) => {
234+ // fail permanently
235+ self . current_part = None ;
236+ self . last_part_boundary = None ;
237+ self . raw_parts . clear ( ) ;
238+ Err ( err)
239+ }
240+ }
158241 }
159242}
0 commit comments