@@ -2,9 +2,12 @@ use std::ffi::CString;
22use std:: fmt;
33use std:: path:: Path ;
44
5+ use libc:: c_void;
6+
57use FormError ;
68use curl_sys;
7- use easy:: { list, List } ;
9+ use easy:: list;
10+ use easy:: { List , ReadError } ;
811
912/// Multipart/formdata for an HTTP POST request.
1013///
@@ -16,6 +19,7 @@ pub struct Form {
1619 headers : Vec < List > ,
1720 buffers : Vec < Vec < u8 > > ,
1821 strings : Vec < CString > ,
22+ streams : Option < Box < StreamNode > > ,
1923}
2024
2125/// One part in a multipart upload, added to a `Form`.
@@ -26,10 +30,19 @@ pub struct Part<'form, 'data> {
2630 error : Option < FormError > ,
2731}
2832
33+ struct StreamNode {
34+ stream : Box < FnMut ( & mut [ u8 ] ) -> Result < usize , ReadError > > ,
35+ _next : Option < Box < StreamNode > > ,
36+ }
37+
2938pub fn raw ( form : & Form ) -> * mut curl_sys:: curl_httppost {
3039 form. head
3140}
3241
42+ pub unsafe fn read ( raw : * mut c_void , into : & mut [ u8 ] ) -> Result < usize , ReadError > {
43+ ( ( * ( raw as * mut StreamNode ) ) . stream ) ( into)
44+ }
45+
3346impl Form {
3447 /// Creates a new blank form ready for the addition of new data.
3548 pub fn new ( ) -> Form {
@@ -39,6 +52,7 @@ impl Form {
3952 headers : Vec :: new ( ) ,
4053 buffers : Vec :: new ( ) ,
4154 strings : Vec :: new ( ) ,
55+ streams : None ,
4256 }
4357 }
4458
@@ -254,6 +268,48 @@ impl<'form, 'data> Part<'form, 'data> {
254268 self
255269 }
256270
271+ /// Tells libcurl to use the callback provided to get data.
272+ ///
273+ /// If you want the part to look like a file upload one, set the `filename`
274+ /// parameter as well. Note that when using `stream` the `len` option must
275+ /// also be set with the total expected length of the part unless the
276+ /// formpost is sent chunked encoded in which case it can be `None`.
277+ ///
278+ /// The callback provided must live for the `'static` lifetime and must
279+ /// adhere to the `Send` bound.
280+ pub fn stream < F > ( & mut self ,
281+ len : Option < usize > ,
282+ f : F ) -> & mut Self
283+ where F : FnMut ( & mut [ u8 ] ) -> Result < usize , ReadError > + ' static + Send ,
284+ {
285+ self . _stream ( len, Box :: new ( f) ) ;
286+ self
287+ }
288+
289+ fn _stream ( & mut self ,
290+ len : Option < usize > ,
291+ stream : Box < FnMut ( & mut [ u8 ] ) -> Result < usize , ReadError > + Send > )
292+ {
293+ let mut node = Box :: new ( StreamNode {
294+ stream : stream,
295+ _next : self . form . streams . take ( ) ,
296+ } ) ;
297+ let pos = self . array . len ( ) - 1 ;
298+ let ptr = & mut * node as * mut StreamNode as usize ;
299+ assert ! ( ptr & 1 == 0 ) ;
300+ self . array . insert ( pos, curl_sys:: curl_forms {
301+ option : curl_sys:: CURLFORM_STREAM ,
302+ value : ( ptr | 1 ) as * mut _ ,
303+ } ) ;
304+ if let Some ( len) = len {
305+ self . array . insert ( pos + 1 , curl_sys:: curl_forms {
306+ option : curl_sys:: CURLFORM_CONTENTSLENGTH ,
307+ value : len as * mut _ ,
308+ } ) ;
309+ }
310+ self . form . streams = Some ( node) ;
311+ }
312+
257313 /// Attempts to add this part to the `Form` that it was created from.
258314 ///
259315 /// If any error happens while adding, that error is returned, otherwise
0 commit comments