curb 0.4.4.0 → 0.4.8.0
Sign up to get free protection for your applications and to get access to all the features.
Potentially problematic release.
This version of curb might be problematic. Click here for more details.
- data/Rakefile +5 -0
- data/ext/curb.h +6 -5
- data/ext/curb_easy.c +8 -138
- data/ext/curb_easy.h +2 -0
- data/ext/curb_multi.c +86 -10
- data/ext/curb_multi.h +4 -0
- data/ext/curb_upload.c +24 -0
- data/lib/curb.rb +41 -1
- data/tests/helper.rb +1 -1
- data/tests/tc_curl_multi.rb +61 -0
- metadata +16 -16
data/Rakefile
CHANGED
@@ -63,6 +63,11 @@ end
|
|
63
63
|
desc "Compile the shared object"
|
64
64
|
task :compile => [CURB_SO]
|
65
65
|
|
66
|
+
desc "Create the markdown file"
|
67
|
+
task :markdown do
|
68
|
+
cp "README", "README.markdown"
|
69
|
+
end
|
70
|
+
|
66
71
|
desc "Install to your site_ruby directory"
|
67
72
|
task :install => :alltests do
|
68
73
|
m = make 'install'
|
data/ext/curb.h
CHANGED
@@ -20,20 +20,21 @@
|
|
20
20
|
#include "curb_macros.h"
|
21
21
|
|
22
22
|
// These should be managed from the Rake 'release' task.
|
23
|
-
#define CURB_VERSION "0.4.
|
24
|
-
#define CURB_VER_NUM
|
23
|
+
#define CURB_VERSION "0.4.8.0"
|
24
|
+
#define CURB_VER_NUM 480
|
25
25
|
#define CURB_VER_MAJ 0
|
26
26
|
#define CURB_VER_MIN 4
|
27
|
-
#define CURB_VER_MIC
|
27
|
+
#define CURB_VER_MIC 8
|
28
28
|
#define CURB_VER_PATCH 0
|
29
29
|
|
30
30
|
|
31
31
|
// Maybe not yet defined in Ruby
|
32
32
|
#ifndef RSTRING_LEN
|
33
|
-
#define RSTRING_LEN(x) RSTRING(x)->len
|
33
|
+
#define RSTRING_LEN(x) RSTRING(x)->len
|
34
34
|
#endif
|
35
|
+
|
35
36
|
#ifndef RSTRING_PTR
|
36
|
-
#define RSTRING_PTR(x) RSTRING(x)->ptr
|
37
|
+
#define RSTRING_PTR(x) RSTRING(x)->ptr
|
37
38
|
#endif
|
38
39
|
|
39
40
|
#ifdef HAVE_RUBY19_HASH
|
data/ext/curb_easy.c
CHANGED
@@ -8,6 +8,7 @@
|
|
8
8
|
#include "curb_errors.h"
|
9
9
|
#include "curb_postfield.h"
|
10
10
|
#include "curb_upload.h"
|
11
|
+
#include "curb_multi.h"
|
11
12
|
|
12
13
|
#include <errno.h>
|
13
14
|
#include <string.h>
|
@@ -1716,147 +1717,16 @@ VALUE ruby_curl_easy_cleanup( VALUE self, ruby_curl_easy *rbce, VALUE bodybuf, V
|
|
1716
1717
|
*/
|
1717
1718
|
static VALUE handle_perform(VALUE self, ruby_curl_easy *rbce) {
|
1718
1719
|
|
1719
|
-
|
1720
|
-
|
1721
|
-
VALUE
|
1722
|
-
// char errors[CURL_ERROR_SIZE*2];
|
1720
|
+
VALUE multi = ruby_curl_multi_new(cCurlMulti);
|
1721
|
+
ruby_curl_multi_add(multi, self);
|
1722
|
+
VALUE ret = ruby_curl_multi_perform(multi);
|
1723
1723
|
|
1724
|
-
|
1725
|
-
|
1726
|
-
|
1727
|
-
|
1728
|
-
if( rb_thread_alone() ) {
|
1729
|
-
result = curl_easy_perform(rbce->curl);
|
1724
|
+
/* check for errors in the easy response and raise exceptions if anything went wrong and their is no on_failure handler */
|
1725
|
+
if( rbce->last_result != 0 && rbce->failure_proc == Qnil ) {
|
1726
|
+
raise_curl_easy_error_exception(rbce->last_result);
|
1730
1727
|
}
|
1731
|
-
else {
|
1732
|
-
int msgs;
|
1733
|
-
int still_running = 1;
|
1734
|
-
CURLMcode mcode = -1;
|
1735
|
-
CURLM *multi_handle = curl_multi_init();
|
1736
|
-
long timeout;
|
1737
|
-
struct timeval tv = {0, 0};
|
1738
|
-
int rc; /* select() return code */
|
1739
|
-
int maxfd;
|
1740
|
-
|
1741
|
-
/* NOTE:
|
1742
|
-
* We create an Curl multi handle here and use rb_thread_select allowing other ruby threads to
|
1743
|
-
* perform actions... ideally we'd have just 1 shared multi handle per all curl easy handles globally
|
1744
|
-
*/
|
1745
|
-
mcode = curl_multi_add_handle(multi_handle, rbce->curl);
|
1746
|
-
if (mcode != CURLM_CALL_MULTI_PERFORM && mcode != CURLM_OK) {
|
1747
|
-
raise_curl_multi_error_exception(mcode);
|
1748
|
-
}
|
1749
|
-
|
1750
|
-
while(CURLM_CALL_MULTI_PERFORM == (mcode=curl_multi_perform(multi_handle, &still_running)) ) ;
|
1751
|
-
|
1752
|
-
if (mcode != CURLM_CALL_MULTI_PERFORM && mcode != CURLM_OK) {
|
1753
|
-
raise_curl_multi_error_exception(mcode);
|
1754
|
-
}
|
1755
|
-
|
1756
|
-
|
1757
|
-
while(still_running) {
|
1758
|
-
|
1759
|
-
fd_set fdread;
|
1760
|
-
fd_set fdwrite;
|
1761
|
-
fd_set fdexcep;
|
1762
|
-
|
1763
|
-
FD_ZERO(&fdread);
|
1764
|
-
FD_ZERO(&fdwrite);
|
1765
|
-
FD_ZERO(&fdexcep);
|
1766
|
-
|
1767
|
-
//time_t timer = time(NULL);
|
1768
|
-
/* get file descriptors from the transfers */
|
1769
|
-
mcode = curl_multi_fdset(multi_handle, &fdread, &fdwrite, &fdexcep, &maxfd);
|
1770
|
-
if (mcode != CURLM_CALL_MULTI_PERFORM && mcode != CURLM_OK) {
|
1771
|
-
raise_curl_multi_error_exception(mcode);
|
1772
|
-
}
|
1773
|
-
|
1774
|
-
#ifdef HAVE_CURL_MULTI_TIMEOUT
|
1775
|
-
/* get the curl suggested time out */
|
1776
|
-
mcode = curl_multi_timeout(multi_handle, &timeout);
|
1777
|
-
if (mcode != CURLM_OK) {
|
1778
|
-
raise_curl_multi_error_exception(mcode);
|
1779
|
-
}
|
1780
|
-
#else
|
1781
|
-
/* libcurl doesn't have a timeout method defined... make a wild guess */
|
1782
|
-
timeout = 1; /* wait a second */
|
1783
|
-
#endif
|
1784
|
-
|
1785
|
-
if (timeout == 0) { /* no delay */
|
1786
|
-
while(CURLM_CALL_MULTI_PERFORM == (mcode=curl_multi_perform(multi_handle, &still_running)) );
|
1787
|
-
continue;
|
1788
|
-
}
|
1789
|
-
else if (timeout == -1) {
|
1790
|
-
timeout = 1; /* wait a second */
|
1791
|
-
}
|
1792
|
-
|
1793
|
-
/* set a suitable timeout to play around with - ruby seems to be greedy about this and won't necessarily yield so the timeout is small.. */
|
1794
|
-
tv.tv_sec = timeout / 1000;
|
1795
|
-
tv.tv_usec = (timeout * 1000) % 1000000;
|
1796
|
-
rc = rb_thread_select(maxfd+1, &fdread, &fdwrite, &fdexcep, &tv);
|
1797
|
-
if (rc < 0) {
|
1798
|
-
rb_raise(rb_eRuntimeError, "select(): %s", strerror(errno));
|
1799
|
-
}
|
1800
1728
|
|
1801
|
-
|
1802
|
-
switch(rc) {
|
1803
|
-
case 0:
|
1804
|
-
//printf("timeout(%.6f) :", difftime(time(NULL), timer) );
|
1805
|
-
default:
|
1806
|
-
//printf("readable/writable: %d\n", rc);
|
1807
|
-
/* timeout or readable/writable sockets */
|
1808
|
-
while(CURLM_CALL_MULTI_PERFORM == (mcode=curl_multi_perform(multi_handle, &still_running)) );
|
1809
|
-
break;
|
1810
|
-
}
|
1811
|
-
}
|
1812
|
-
else {
|
1813
|
-
// error
|
1814
|
-
}
|
1815
|
-
|
1816
|
-
if (mcode != CURLM_CALL_MULTI_PERFORM && mcode != CURLM_OK) {
|
1817
|
-
raise_curl_multi_error_exception(mcode);
|
1818
|
-
}
|
1819
|
-
|
1820
|
-
}
|
1821
|
-
|
1822
|
-
/* check for errors */
|
1823
|
-
CURLMsg *msg = curl_multi_info_read(multi_handle, &msgs);
|
1824
|
-
if (msg && msg->msg == CURLMSG_DONE) {
|
1825
|
-
result = msg->data.result;
|
1826
|
-
}
|
1827
|
-
|
1828
|
-
curl_multi_remove_handle(multi_handle, rbce->curl);
|
1829
|
-
curl_multi_cleanup(multi_handle);
|
1830
|
-
}
|
1831
|
-
|
1832
|
-
ruby_curl_easy_cleanup(self, rbce, bodybuf, headerbuf, headers);
|
1833
|
-
|
1834
|
-
if (rbce->complete_proc != Qnil) {
|
1835
|
-
rb_funcall( rbce->complete_proc, idCall, 1, self );
|
1836
|
-
}
|
1837
|
-
|
1838
|
-
/* check the request status and determine if on_success or on_failure should be called */
|
1839
|
-
long response_code = -1;
|
1840
|
-
curl_easy_getinfo(rbce->curl, CURLINFO_RESPONSE_CODE, &response_code);
|
1841
|
-
if (result != 0) {
|
1842
|
-
// printf("error: %s\n", errors);
|
1843
|
-
if (rbce->failure_proc != Qnil) {
|
1844
|
-
rb_funcall( rbce->failure_proc, idCall, 2, rbce->self, rb_curl_easy_error(result) );
|
1845
|
-
} else {
|
1846
|
-
raise_curl_easy_error_exception(result);
|
1847
|
-
}
|
1848
|
-
}
|
1849
|
-
else if (rbce->success_proc != Qnil &&
|
1850
|
-
/* NOTE: we allow response_code == 0, in the case the file is being read from disk */
|
1851
|
-
((response_code >= 200 && response_code < 300) || response_code == 0)) {
|
1852
|
-
rb_funcall( rbce->success_proc, idCall, 1, self );
|
1853
|
-
}
|
1854
|
-
else if (rbce->failure_proc != Qnil &&
|
1855
|
-
(response_code >= 300 && response_code <= 999)) {
|
1856
|
-
rb_funcall( rbce->failure_proc, idCall, 2, rbce->self, rb_curl_easy_error(result) );
|
1857
|
-
}
|
1858
|
-
|
1859
|
-
return Qtrue;
|
1729
|
+
return ret;
|
1860
1730
|
}
|
1861
1731
|
|
1862
1732
|
/*
|
data/ext/curb_easy.h
CHANGED
@@ -89,6 +89,8 @@ typedef struct {
|
|
89
89
|
VALUE self; /* pointer to self, used by multi interface */
|
90
90
|
VALUE upload; /* pointer to an active upload otherwise Qnil */
|
91
91
|
|
92
|
+
int last_result; /* last result code from multi loop */
|
93
|
+
|
92
94
|
} ruby_curl_easy;
|
93
95
|
|
94
96
|
extern VALUE cCurlEasy;
|
data/ext/curb_multi.c
CHANGED
@@ -6,9 +6,11 @@
|
|
6
6
|
|
7
7
|
#include "curb_config.h"
|
8
8
|
#ifdef HAVE_RUBY19_ST_H
|
9
|
-
#include <ruby
|
9
|
+
#include <ruby.h>
|
10
|
+
#include <ruby/st.h>
|
10
11
|
#else
|
11
|
-
#include <
|
12
|
+
#include <ruby.h>
|
13
|
+
#include <st.h>
|
12
14
|
#endif
|
13
15
|
#include "curb_easy.h"
|
14
16
|
#include "curb_errors.h"
|
@@ -26,7 +28,6 @@ static VALUE idCall;
|
|
26
28
|
|
27
29
|
VALUE cCurlMulti;
|
28
30
|
|
29
|
-
static VALUE ruby_curl_multi_remove(VALUE , VALUE );
|
30
31
|
static void rb_curl_multi_remove(ruby_curl_multi *rbcm, VALUE easy);
|
31
32
|
static void rb_curl_multi_read_info(VALUE self, CURLM *mptr);
|
32
33
|
|
@@ -76,7 +77,7 @@ static void curl_multi_free(ruby_curl_multi *rbcm) {
|
|
76
77
|
*
|
77
78
|
* Create a new Curl::Multi instance
|
78
79
|
*/
|
79
|
-
|
80
|
+
VALUE ruby_curl_multi_new(VALUE klass) {
|
80
81
|
VALUE new_curlm;
|
81
82
|
|
82
83
|
ruby_curl_multi *rbcm = ALLOC(ruby_curl_multi);
|
@@ -93,6 +94,51 @@ static VALUE ruby_curl_multi_new(VALUE klass) {
|
|
93
94
|
return new_curlm;
|
94
95
|
}
|
95
96
|
|
97
|
+
// Hash#foreach callback for ruby_curl_multi_requests
|
98
|
+
static int ruby_curl_multi_requests_callback(VALUE key, VALUE value, VALUE result_array) {
|
99
|
+
rb_ary_push(result_array, value);
|
100
|
+
|
101
|
+
return ST_CONTINUE;
|
102
|
+
}
|
103
|
+
|
104
|
+
/*
|
105
|
+
* call-seq:
|
106
|
+
* multi.requests => [#<Curl::Easy...>, ...]
|
107
|
+
*
|
108
|
+
* Returns an array containing all the active requests on this Curl::Multi object.
|
109
|
+
*/
|
110
|
+
static VALUE ruby_curl_multi_requests(VALUE self) {
|
111
|
+
ruby_curl_multi *rbcm;
|
112
|
+
|
113
|
+
Data_Get_Struct(self, ruby_curl_multi, rbcm);
|
114
|
+
|
115
|
+
VALUE result_array = rb_ary_new();
|
116
|
+
|
117
|
+
// iterate over the requests hash, and stuff references into the array.
|
118
|
+
rb_hash_foreach( rbcm->requests, ruby_curl_multi_requests_callback, result_array );
|
119
|
+
|
120
|
+
return result_array;
|
121
|
+
}
|
122
|
+
|
123
|
+
/*
|
124
|
+
* call-seq:
|
125
|
+
* multi.idle? => true or false
|
126
|
+
*
|
127
|
+
* Returns whether or not this Curl::Multi handle is processing any requests. E.g. this returns
|
128
|
+
* true when multi.requests.length == 0.
|
129
|
+
*/
|
130
|
+
static VALUE ruby_curl_multi_idle(VALUE self) {
|
131
|
+
ruby_curl_multi *rbcm;
|
132
|
+
|
133
|
+
Data_Get_Struct(self, ruby_curl_multi, rbcm);
|
134
|
+
|
135
|
+
if ( FIX2INT( rb_funcall(rbcm->requests, rb_intern("length"), 0) ) == 0 ) {
|
136
|
+
return Qtrue;
|
137
|
+
} else {
|
138
|
+
return Qfalse;
|
139
|
+
}
|
140
|
+
}
|
141
|
+
|
96
142
|
/*
|
97
143
|
* call-seq:
|
98
144
|
* multi = Curl::Multi.new
|
@@ -141,7 +187,7 @@ static VALUE ruby_curl_multi_pipeline(VALUE self, VALUE onoff) {
|
|
141
187
|
*
|
142
188
|
* Add an easy handle to the multi stack
|
143
189
|
*/
|
144
|
-
|
190
|
+
VALUE ruby_curl_multi_add(VALUE self, VALUE easy) {
|
145
191
|
CURLMcode mcode;
|
146
192
|
ruby_curl_easy *rbce;
|
147
193
|
ruby_curl_multi *rbcm;
|
@@ -185,11 +231,11 @@ static VALUE ruby_curl_multi_add(VALUE self, VALUE easy) {
|
|
185
231
|
* # sometime later
|
186
232
|
* multi.remove(easy)
|
187
233
|
*
|
188
|
-
* Remove an easy handle from a multi stack
|
234
|
+
* Remove an easy handle from a multi stack.
|
189
235
|
*
|
190
236
|
* Will raise an exception if the easy handle is not found
|
191
237
|
*/
|
192
|
-
|
238
|
+
VALUE ruby_curl_multi_remove(VALUE self, VALUE easy) {
|
193
239
|
ruby_curl_multi *rbcm;
|
194
240
|
|
195
241
|
Data_Get_Struct(self, ruby_curl_multi, rbcm);
|
@@ -226,6 +272,30 @@ static void rb_curl_multi_remove(ruby_curl_multi *rbcm, VALUE easy) {
|
|
226
272
|
}
|
227
273
|
}
|
228
274
|
|
275
|
+
// Hash#foreach callback for ruby_curl_multi_cancel
|
276
|
+
static int ruby_curl_multi_cancel_callback(VALUE key, VALUE value, ruby_curl_multi *rbcm) {
|
277
|
+
rb_curl_multi_remove(rbcm, value);
|
278
|
+
|
279
|
+
return ST_CONTINUE;
|
280
|
+
}
|
281
|
+
|
282
|
+
/*
|
283
|
+
* call-seq:
|
284
|
+
* multi.cancel!
|
285
|
+
*
|
286
|
+
* Cancels all requests currently being made on this Curl::Multi handle.
|
287
|
+
*/
|
288
|
+
static VALUE ruby_curl_multi_cancel(VALUE self) {
|
289
|
+
ruby_curl_multi *rbcm;
|
290
|
+
|
291
|
+
Data_Get_Struct(self, ruby_curl_multi, rbcm);
|
292
|
+
|
293
|
+
rb_hash_foreach( rbcm->requests, ruby_curl_multi_cancel_callback, (VALUE)rbcm );
|
294
|
+
|
295
|
+
// for chaining
|
296
|
+
return self;
|
297
|
+
}
|
298
|
+
|
229
299
|
static void rb_curl_multi_read_info(VALUE self, CURLM *multi_handle) {
|
230
300
|
int msgs_left, result;
|
231
301
|
CURLMsg *msg;
|
@@ -247,6 +317,7 @@ static void rb_curl_multi_read_info(VALUE self, CURLM *multi_handle) {
|
|
247
317
|
if (ecode != 0) {
|
248
318
|
raise_curl_easy_error_exception(ecode);
|
249
319
|
}
|
320
|
+
rbce->last_result = result; // save the last easy result code
|
250
321
|
ruby_curl_multi_remove( self, rbce->self );
|
251
322
|
|
252
323
|
if (rbce->complete_proc != Qnil) {
|
@@ -308,7 +379,7 @@ static void rb_curl_multi_run(VALUE self, CURLM *multi_handle, int *still_runnin
|
|
308
379
|
*
|
309
380
|
* Run multi handles, looping selecting when data can be transfered
|
310
381
|
*/
|
311
|
-
|
382
|
+
VALUE ruby_curl_multi_perform(VALUE self) {
|
312
383
|
CURLMcode mcode;
|
313
384
|
ruby_curl_multi *rbcm;
|
314
385
|
int maxfd, rc;
|
@@ -368,7 +439,7 @@ static VALUE ruby_curl_multi_perform(VALUE self) {
|
|
368
439
|
|
369
440
|
}
|
370
441
|
|
371
|
-
return
|
442
|
+
return Qtrue;
|
372
443
|
}
|
373
444
|
|
374
445
|
/* =================== INIT LIB =====================*/
|
@@ -379,11 +450,16 @@ void init_curb_multi() {
|
|
379
450
|
|
380
451
|
/* Class methods */
|
381
452
|
rb_define_singleton_method(cCurlMulti, "new", ruby_curl_multi_new, 0);
|
382
|
-
|
453
|
+
|
454
|
+
/* "Attributes" */
|
455
|
+
rb_define_method(cCurlMulti, "requests", ruby_curl_multi_requests, 0);
|
456
|
+
rb_define_method(cCurlMulti, "idle?", ruby_curl_multi_idle, 0);
|
457
|
+
|
383
458
|
/* Instnace methods */
|
384
459
|
rb_define_method(cCurlMulti, "max_connects=", ruby_curl_multi_max_connects, 1);
|
385
460
|
rb_define_method(cCurlMulti, "pipeline=", ruby_curl_multi_pipeline, 1);
|
386
461
|
rb_define_method(cCurlMulti, "add", ruby_curl_multi_add, 1);
|
387
462
|
rb_define_method(cCurlMulti, "remove", ruby_curl_multi_remove, 1);
|
463
|
+
rb_define_method(cCurlMulti, "cancel!", ruby_curl_multi_cancel, 0);
|
388
464
|
rb_define_method(cCurlMulti, "perform", ruby_curl_multi_perform, 0);
|
389
465
|
}
|
data/ext/curb_multi.h
CHANGED
@@ -20,6 +20,10 @@ typedef struct {
|
|
20
20
|
|
21
21
|
extern VALUE cCurlMulti;
|
22
22
|
void init_curb_multi();
|
23
|
+
VALUE ruby_curl_multi_new(VALUE klass);
|
24
|
+
VALUE ruby_curl_multi_perform(VALUE self);
|
25
|
+
VALUE ruby_curl_multi_add(VALUE self, VALUE easy);
|
26
|
+
VALUE ruby_curl_multi_remove(VALUE self, VALUE easy);
|
23
27
|
|
24
28
|
|
25
29
|
#endif
|
data/ext/curb_upload.c
CHANGED
@@ -6,6 +6,10 @@
|
|
6
6
|
extern VALUE mCurl;
|
7
7
|
VALUE cCurlUpload;
|
8
8
|
|
9
|
+
#ifdef RDOC_NEVER_DEFINED
|
10
|
+
mCurl = rb_define_module("Curl");
|
11
|
+
#endif
|
12
|
+
|
9
13
|
static void curl_upload_mark(ruby_curl_upload *rbcu) {
|
10
14
|
if (rbcu->stream) rb_gc_mark(rbcu->stream);
|
11
15
|
}
|
@@ -13,6 +17,10 @@ static void curl_upload_free(ruby_curl_upload *rbcu) {
|
|
13
17
|
free(rbcu);
|
14
18
|
}
|
15
19
|
|
20
|
+
/*
|
21
|
+
* call-seq:
|
22
|
+
* internal class for sending large file uploads
|
23
|
+
*/
|
16
24
|
VALUE ruby_curl_upload_new(VALUE klass) {
|
17
25
|
VALUE upload;
|
18
26
|
ruby_curl_upload *rbcu = ALLOC(ruby_curl_upload);
|
@@ -22,23 +30,39 @@ VALUE ruby_curl_upload_new(VALUE klass) {
|
|
22
30
|
return upload;
|
23
31
|
}
|
24
32
|
|
33
|
+
/*
|
34
|
+
* call-seq:
|
35
|
+
* internal class for sending large file uploads
|
36
|
+
*/
|
25
37
|
VALUE ruby_curl_upload_stream_set(VALUE self, VALUE stream) {
|
26
38
|
ruby_curl_upload *rbcu;
|
27
39
|
Data_Get_Struct(self, ruby_curl_upload, rbcu);
|
28
40
|
rbcu->stream = stream;
|
29
41
|
return stream;
|
30
42
|
}
|
43
|
+
/*
|
44
|
+
* call-seq:
|
45
|
+
* internal class for sending large file uploads
|
46
|
+
*/
|
31
47
|
VALUE ruby_curl_upload_stream_get(VALUE self) {
|
32
48
|
ruby_curl_upload *rbcu;
|
33
49
|
Data_Get_Struct(self, ruby_curl_upload, rbcu);
|
34
50
|
return rbcu->stream;
|
35
51
|
}
|
52
|
+
/*
|
53
|
+
* call-seq:
|
54
|
+
* internal class for sending large file uploads
|
55
|
+
*/
|
36
56
|
VALUE ruby_curl_upload_offset_set(VALUE self, VALUE offset) {
|
37
57
|
ruby_curl_upload *rbcu;
|
38
58
|
Data_Get_Struct(self, ruby_curl_upload, rbcu);
|
39
59
|
rbcu->offset = FIX2INT(offset);
|
40
60
|
return offset;
|
41
61
|
}
|
62
|
+
/*
|
63
|
+
* call-seq:
|
64
|
+
* internal class for sending large file uploads
|
65
|
+
*/
|
42
66
|
VALUE ruby_curl_upload_offset_get(VALUE self) {
|
43
67
|
ruby_curl_upload *rbcu;
|
44
68
|
Data_Get_Struct(self, ruby_curl_upload, rbcu);
|
data/lib/curb.rb
CHANGED
@@ -75,11 +75,51 @@ module Curl
|
|
75
75
|
easy_options.each do|k,v|
|
76
76
|
c.send("#{k}=",v)
|
77
77
|
end
|
78
|
-
c.on_complete {|curl| blk.call curl }
|
78
|
+
c.on_complete {|curl| blk.call curl } if blk
|
79
79
|
m.add(c)
|
80
80
|
end
|
81
81
|
m.perform
|
82
82
|
end
|
83
|
+
|
84
|
+
# call-seq:
|
85
|
+
#
|
86
|
+
# Curl::Multi.post([{:url => 'url1', :post_fields => {'field1' => 'value1', 'field2' => 'value2'}},
|
87
|
+
# {:url => 'url2', :post_fields => {'field1' => 'value1', 'field2' => 'value2'}},
|
88
|
+
# {:url => 'url3', :post_fields => {'field1' => 'value1', 'field2' => 'value2'}}],
|
89
|
+
# { :follow_location => true, :multipart_form_post => true },
|
90
|
+
# {:pipeline => true }) do|easy|
|
91
|
+
# easy_handle_on_request_complete
|
92
|
+
# end
|
93
|
+
#
|
94
|
+
# Blocking call to POST multiple form's in parallel.
|
95
|
+
#
|
96
|
+
# urls_with_config: is a hash of url's pointing to the postfields to send
|
97
|
+
# easy_options: are a set of common options to set on all easy handles
|
98
|
+
# multi_options: options to set on the Curl::Multi handle
|
99
|
+
#
|
100
|
+
def post(urls_with_config, easy_options, multi_options, &blk)
|
101
|
+
m = Curl::Multi.new
|
102
|
+
# configure the multi handle
|
103
|
+
multi_options.each do|k,v|
|
104
|
+
m.send("#{k}=", v)
|
105
|
+
end
|
106
|
+
|
107
|
+
urls_with_config.each do|conf|
|
108
|
+
c = conf.dup # avoid being destructive to input
|
109
|
+
url = c.delete(:url)
|
110
|
+
fields = c.delete(:post_fields)
|
111
|
+
easy = Curl::Easy.new(url)
|
112
|
+
# set the post post using the url fields
|
113
|
+
easy.post_body = fields.map{|f,k| "#{easy.escape(f)}=#{easy.escape(k)}"}.join('&')
|
114
|
+
# configure the easy handle
|
115
|
+
easy_options.each do|k,v|
|
116
|
+
easy.send("#{k}=",v)
|
117
|
+
end
|
118
|
+
easy.on_complete {|curl| blk.call curl } if blk
|
119
|
+
m.add(easy)
|
120
|
+
end
|
121
|
+
m.perform
|
122
|
+
end
|
83
123
|
end
|
84
124
|
end
|
85
125
|
end
|
data/tests/helper.rb
CHANGED
@@ -21,7 +21,7 @@ require 'webrick'
|
|
21
21
|
# or to test with multiple threads set it to false
|
22
22
|
# this is important since, some code paths will change depending
|
23
23
|
# on the presence of multiple threads
|
24
|
-
TEST_SINGLE_THREADED=
|
24
|
+
TEST_SINGLE_THREADED=false
|
25
25
|
|
26
26
|
# keep webrick quiet
|
27
27
|
class ::WEBrick::HTTPServer
|
data/tests/tc_curl_multi.rb
CHANGED
@@ -100,6 +100,50 @@ class TestCurbCurlMulti < Test::Unit::TestCase
|
|
100
100
|
m = nil
|
101
101
|
|
102
102
|
end
|
103
|
+
|
104
|
+
def test_idle_check
|
105
|
+
m = Curl::Multi.new
|
106
|
+
e = Curl::Easy.new($TEST_URL)
|
107
|
+
|
108
|
+
assert(m.idle?, 'A new Curl::Multi handle should be idle')
|
109
|
+
|
110
|
+
m.add(e)
|
111
|
+
|
112
|
+
assert((not m.idle?), 'A Curl::Multi handle with a request should not be idle')
|
113
|
+
|
114
|
+
m.perform
|
115
|
+
|
116
|
+
assert(m.idle?, 'A Curl::Multi handle should be idle after performing its requests')
|
117
|
+
end
|
118
|
+
|
119
|
+
def test_requests
|
120
|
+
m = Curl::Multi.new
|
121
|
+
|
122
|
+
assert_equal([], m.requests, 'A new Curl::Multi handle should have no requests')
|
123
|
+
|
124
|
+
10.times do
|
125
|
+
m.add(Curl::Easy.new($TEST_URL))
|
126
|
+
end
|
127
|
+
|
128
|
+
assert_equal(10, m.requests.length, 'multi.requests should contain all the active requests')
|
129
|
+
|
130
|
+
m.perform
|
131
|
+
|
132
|
+
assert_equal([], m.requests, 'A new Curl::Multi handle should have no requests after a perform')
|
133
|
+
end
|
134
|
+
|
135
|
+
def test_cancel
|
136
|
+
m = Curl::Multi.new
|
137
|
+
m.cancel! # shouldn't raise anything
|
138
|
+
|
139
|
+
10.times do
|
140
|
+
m.add(Curl::Easy.new($TEST_URL))
|
141
|
+
end
|
142
|
+
|
143
|
+
m.cancel!
|
144
|
+
|
145
|
+
assert_equal([], m.requests, 'A new Curl::Multi handle should have no requests after being canceled')
|
146
|
+
end
|
103
147
|
|
104
148
|
def test_with_success
|
105
149
|
c1 = Curl::Easy.new($TEST_URL)
|
@@ -260,6 +304,23 @@ class TestCurbCurlMulti < Test::Unit::TestCase
|
|
260
304
|
end
|
261
305
|
end
|
262
306
|
|
307
|
+
def test_multi_easy_post_01
|
308
|
+
urls = [
|
309
|
+
{ :url => TestServlet.url + '?q=1', :post_fields => {'field1' => 'value1', 'k' => 'j'}},
|
310
|
+
{ :url => TestServlet.url + '?q=2', :post_fields => {'field2' => 'value2', 'foo' => 'bar', 'i' => 'j' }},
|
311
|
+
{ :url => TestServlet.url + '?q=3', :post_fields => {'field3' => 'value3', 'field4' => 'value4'}}
|
312
|
+
]
|
313
|
+
Curl::Multi.post(urls, {:follow_location => true, :multipart_form_post => true}, {:pipeline => true}) do|easy|
|
314
|
+
str = easy.body_str
|
315
|
+
assert_match /POST/, str
|
316
|
+
fields = {}
|
317
|
+
str.gsub(/POST\n/,'').split('&').map{|sv| k, v = sv.split('='); fields[k] = v }
|
318
|
+
expected = urls.find{|s| s[:url] == easy.last_effective_url }
|
319
|
+
assert_equal expected[:post_fields], fields
|
320
|
+
#puts "#{easy.last_effective_url} #{fields.inspect}"
|
321
|
+
end
|
322
|
+
end
|
323
|
+
|
263
324
|
include TestServerMethods
|
264
325
|
|
265
326
|
def setup
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: curb
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.4.
|
4
|
+
version: 0.4.8.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Ross Bamford
|
@@ -10,7 +10,7 @@ autorequire:
|
|
10
10
|
bindir: bin
|
11
11
|
cert_chain: []
|
12
12
|
|
13
|
-
date: 2009-07-
|
13
|
+
date: 2009-07-21 00:00:00 -04:00
|
14
14
|
default_executable:
|
15
15
|
dependencies: []
|
16
16
|
|
@@ -32,19 +32,19 @@ files:
|
|
32
32
|
- lib/curb.rb
|
33
33
|
- lib/curl.rb
|
34
34
|
- ext/curb.c
|
35
|
-
- ext/curb_postfield.c
|
36
|
-
- ext/curb_multi.c
|
37
|
-
- ext/curb_errors.c
|
38
35
|
- ext/curb_easy.c
|
36
|
+
- ext/curb_errors.c
|
37
|
+
- ext/curb_multi.c
|
38
|
+
- ext/curb_postfield.c
|
39
39
|
- ext/curb_upload.c
|
40
|
+
- ext/curb.h
|
41
|
+
- ext/curb_config.h
|
40
42
|
- ext/curb_easy.h
|
41
43
|
- ext/curb_errors.h
|
42
|
-
- ext/curb_upload.h
|
43
44
|
- ext/curb_macros.h
|
44
|
-
- ext/curb.h
|
45
|
-
- ext/curb_postfield.h
|
46
|
-
- ext/curb_config.h
|
47
45
|
- ext/curb_multi.h
|
46
|
+
- ext/curb_postfield.h
|
47
|
+
- ext/curb_upload.h
|
48
48
|
has_rdoc: true
|
49
49
|
homepage: http://curb.rubyforge.org/
|
50
50
|
licenses: []
|
@@ -76,14 +76,14 @@ signing_key:
|
|
76
76
|
specification_version: 3
|
77
77
|
summary: Ruby libcurl bindings
|
78
78
|
test_files:
|
79
|
-
- tests/
|
80
|
-
- tests/tc_curl_postfield.rb
|
79
|
+
- tests/alltests.rb
|
81
80
|
- tests/bug_curb_easy_blocks_ruby_threads.rb
|
82
|
-
- tests/unittests.rb
|
83
|
-
- tests/bug_require_last_or_segfault.rb
|
84
81
|
- tests/bug_instance_post_differs_from_class_post.rb
|
85
|
-
- tests/
|
86
|
-
- tests/alltests.rb
|
82
|
+
- tests/bug_require_last_or_segfault.rb
|
87
83
|
- tests/helper.rb
|
88
|
-
- tests/tc_curl_easy.rb
|
89
84
|
- tests/require_last_or_segfault_script.rb
|
85
|
+
- tests/tc_curl_download.rb
|
86
|
+
- tests/tc_curl_easy.rb
|
87
|
+
- tests/tc_curl_multi.rb
|
88
|
+
- tests/tc_curl_postfield.rb
|
89
|
+
- tests/unittests.rb
|