@@ -2,9 +2,12 @@ use std::ffi::CString;
2
2
use std:: fmt;
3
3
use std:: path:: Path ;
4
4
5
+ use libc:: c_void;
6
+
5
7
use FormError ;
6
8
use curl_sys;
7
- use easy:: { list, List } ;
9
+ use easy:: list;
10
+ use easy:: { List , ReadError } ;
8
11
9
12
/// Multipart/formdata for an HTTP POST request.
10
13
///
@@ -16,6 +19,7 @@ pub struct Form {
16
19
headers : Vec < List > ,
17
20
buffers : Vec < Vec < u8 > > ,
18
21
strings : Vec < CString > ,
22
+ streams : Option < Box < StreamNode > > ,
19
23
}
20
24
21
25
/// One part in a multipart upload, added to a `Form`.
@@ -26,10 +30,19 @@ pub struct Part<'form, 'data> {
26
30
error : Option < FormError > ,
27
31
}
28
32
33
+ struct StreamNode {
34
+ stream : Box < FnMut ( & mut [ u8 ] ) -> Result < usize , ReadError > > ,
35
+ _next : Option < Box < StreamNode > > ,
36
+ }
37
+
29
38
pub fn raw ( form : & Form ) -> * mut curl_sys:: curl_httppost {
30
39
form. head
31
40
}
32
41
42
+ pub unsafe fn read ( raw : * mut c_void , into : & mut [ u8 ] ) -> Result < usize , ReadError > {
43
+ ( ( * ( raw as * mut StreamNode ) ) . stream ) ( into)
44
+ }
45
+
33
46
impl Form {
34
47
/// Creates a new blank form ready for the addition of new data.
35
48
pub fn new ( ) -> Form {
@@ -39,6 +52,7 @@ impl Form {
39
52
headers : Vec :: new ( ) ,
40
53
buffers : Vec :: new ( ) ,
41
54
strings : Vec :: new ( ) ,
55
+ streams : None ,
42
56
}
43
57
}
44
58
@@ -254,6 +268,48 @@ impl<'form, 'data> Part<'form, 'data> {
254
268
self
255
269
}
256
270
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
+
257
313
/// Attempts to add this part to the `Form` that it was created from.
258
314
///
259
315
/// If any error happens while adding, that error is returned, otherwise
0 commit comments