curb 0.5.8.0-x86-linux → 0.7.7-x86-linux
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/README +2 -1
- data/Rakefile +20 -1
- data/ext/curb.c +26 -0
- data/ext/curb.h +6 -4
- data/ext/curb.o +0 -0
- data/ext/curb_core.so +0 -0
- data/ext/curb_easy.c +734 -304
- data/ext/curb_easy.h +26 -45
- data/ext/curb_easy.o +0 -0
- data/ext/curb_errors.c +7 -0
- data/ext/curb_errors.h +1 -0
- data/ext/curb_errors.o +0 -0
- data/ext/curb_macros.h +41 -0
- data/ext/curb_multi.c +119 -94
- data/ext/curb_multi.o +0 -0
- data/ext/curb_postfield.c +9 -9
- data/ext/curb_postfield.o +0 -0
- data/ext/curb_upload.o +0 -0
- data/ext/extconf.rb +20 -10
- data/lib/curb.rb +71 -0
- data/tests/bug_curb_easy_post_with_string_no_content_length_header.rb +83 -0
- data/tests/bug_multi_segfault.rb +6 -2
- data/tests/bug_postfields_crash.rb +26 -0
- data/tests/bug_postfields_crash2.rb +57 -0
- data/tests/bugtests.rb +9 -0
- data/tests/helper.rb +17 -7
- data/tests/mem_check.rb +65 -0
- data/tests/tc_curl_easy.rb +116 -2
- data/tests/tc_curl_multi.rb +49 -9
- metadata +39 -5
data/ext/curb_easy.h
CHANGED
@@ -11,6 +11,24 @@
|
|
11
11
|
|
12
12
|
#include <curl/easy.h>
|
13
13
|
|
14
|
+
#ifdef CURL_VERSION_SSL
|
15
|
+
#if LIBCURL_VERSION_NUM >= 0x070b00
|
16
|
+
# if LIBCURL_VERSION_NUM <= 0x071004
|
17
|
+
# define CURB_FTPSSL CURLOPT_FTP_SSL
|
18
|
+
# define CURB_FTPSSL_ALL CURLFTPSSL_ALL
|
19
|
+
# define CURB_FTPSSL_TRY CURLFTPSSL_TRY
|
20
|
+
# define CURB_FTPSSL_CONTROL CURLFTPSSL_CONTROL
|
21
|
+
# define CURB_FTPSSL_NONE CURLFTPSSL_NONE
|
22
|
+
# else
|
23
|
+
# define CURB_FTPSSL CURLOPT_USE_SSL
|
24
|
+
# define CURB_FTPSSL_ALL CURLUSESSL_ALL
|
25
|
+
# define CURB_FTPSSL_TRY CURLUSESSL_TRY
|
26
|
+
# define CURB_FTPSSL_CONTROL CURLUSESSL_CONTROL
|
27
|
+
# define CURB_FTPSSL_NONE CURLUSESSL_NONE
|
28
|
+
# endif
|
29
|
+
#endif
|
30
|
+
#endif
|
31
|
+
|
14
32
|
/* a lot of this *could* be kept in the handler itself,
|
15
33
|
* but then we lose the ability to query it's status.
|
16
34
|
*/
|
@@ -18,33 +36,8 @@ typedef struct {
|
|
18
36
|
/* The handler */
|
19
37
|
CURL *curl;
|
20
38
|
|
21
|
-
/*
|
22
|
-
VALUE
|
23
|
-
VALUE proxy_url;
|
24
|
-
|
25
|
-
VALUE body_proc;
|
26
|
-
VALUE header_proc;
|
27
|
-
VALUE body_data; /* Holds the response body from the last call to curl_easy_perform */
|
28
|
-
VALUE header_data; /* unless a block is supplied (they'll be nil) */
|
29
|
-
VALUE progress_proc;
|
30
|
-
VALUE debug_proc;
|
31
|
-
VALUE interface_hm;
|
32
|
-
VALUE userpwd;
|
33
|
-
VALUE proxypwd;
|
34
|
-
VALUE headers; /* ruby array of strings with headers to set */
|
35
|
-
VALUE cookies; /* string */
|
36
|
-
VALUE cookiefile; /* filename */
|
37
|
-
VALUE cookiejar; /* filename */
|
38
|
-
VALUE cert;
|
39
|
-
VALUE cacert;
|
40
|
-
VALUE certpassword;
|
41
|
-
VALUE certtype;
|
42
|
-
VALUE encoding;
|
43
|
-
VALUE useragent;
|
44
|
-
|
45
|
-
VALUE success_proc;
|
46
|
-
VALUE failure_proc;
|
47
|
-
VALUE complete_proc;
|
39
|
+
VALUE opts; /* rather then allocate everything we might need to store, allocate a Hash and only store objects we actually use... */
|
40
|
+
VALUE multi; /* keep a multi handle alive for each easy handle not being used by a multi handle. This improves easy performance when not within a multi context */
|
48
41
|
|
49
42
|
/* Other opts */
|
50
43
|
unsigned short local_port; // 0 is no port
|
@@ -58,6 +51,9 @@ typedef struct {
|
|
58
51
|
unsigned long connect_timeout;
|
59
52
|
long dns_cache_timeout;
|
60
53
|
unsigned long ftp_response_timeout;
|
54
|
+
long ssl_version;
|
55
|
+
long use_ssl;
|
56
|
+
long ftp_filemethod;
|
61
57
|
|
62
58
|
/* bool flags */
|
63
59
|
char proxy_tunnel;
|
@@ -71,23 +67,8 @@ typedef struct {
|
|
71
67
|
char verbose;
|
72
68
|
char multipart_form_post;
|
73
69
|
char enable_cookies;
|
74
|
-
|
75
|
-
/* this is sometimes used as a buffer for a form data string,
|
76
|
-
* which we alloc in C and need to hang around for the call,
|
77
|
-
* and in case it's asked for before the next call.
|
78
|
-
*/
|
79
|
-
VALUE postdata_buffer;
|
80
|
-
|
81
|
-
/* when added to a multi handle these buffers are needed
|
82
|
-
* when the easy handle isn't supplied the body proc
|
83
|
-
* or a custom http header is passed.
|
84
|
-
*/
|
85
|
-
VALUE bodybuf;
|
86
|
-
VALUE headerbuf;
|
87
70
|
struct curl_slist *curl_headers;
|
88
|
-
|
89
|
-
VALUE self; /* pointer to self, used by multi interface */
|
90
|
-
VALUE upload; /* pointer to an active upload otherwise Qnil */
|
71
|
+
struct curl_slist *curl_ftp_commands;
|
91
72
|
|
92
73
|
int last_result; /* last result code from multi loop */
|
93
74
|
|
@@ -95,8 +76,8 @@ typedef struct {
|
|
95
76
|
|
96
77
|
extern VALUE cCurlEasy;
|
97
78
|
|
98
|
-
VALUE ruby_curl_easy_setup(ruby_curl_easy *rbce
|
99
|
-
VALUE ruby_curl_easy_cleanup(VALUE self, ruby_curl_easy *rbce
|
79
|
+
VALUE ruby_curl_easy_setup(ruby_curl_easy *rbce);
|
80
|
+
VALUE ruby_curl_easy_cleanup(VALUE self, ruby_curl_easy *rbce);
|
100
81
|
|
101
82
|
void init_curb_easy();
|
102
83
|
|
data/ext/curb_easy.o
CHANGED
Binary file
|
data/ext/curb_errors.c
CHANGED
@@ -23,6 +23,7 @@ VALUE eCurlErrTelnetError;
|
|
23
23
|
VALUE eCurlErrTFTPError;
|
24
24
|
|
25
25
|
/* Specific libcurl errors */
|
26
|
+
VALUE eCurlErrOK; /* not really an error but a return code */
|
26
27
|
VALUE eCurlErrUnsupportedProtocol;
|
27
28
|
VALUE eCurlErrFailedInit;
|
28
29
|
VALUE eCurlErrMalformedURL;
|
@@ -109,6 +110,7 @@ VALUE eCurlErrSSLCRLBadfile;
|
|
109
110
|
VALUE eCurlErrSSLIssuerError;
|
110
111
|
|
111
112
|
/* multi errors */
|
113
|
+
VALUE mCurlErrFailedInit;
|
112
114
|
VALUE mCurlErrCallMultiPerform;
|
113
115
|
VALUE mCurlErrBadHandle;
|
114
116
|
VALUE mCurlErrBadEasyHandle;
|
@@ -127,6 +129,9 @@ VALUE rb_curl_easy_error(CURLcode code) {
|
|
127
129
|
VALUE results;
|
128
130
|
|
129
131
|
switch (code) {
|
132
|
+
case CURLE_OK: /* 0 */
|
133
|
+
exclz = eCurlErrOK;
|
134
|
+
break;
|
130
135
|
case CURLE_UNSUPPORTED_PROTOCOL: /* 1 */
|
131
136
|
exclz = eCurlErrUnsupportedProtocol;
|
132
137
|
break;
|
@@ -509,6 +514,7 @@ void init_curb_errors() {
|
|
509
514
|
eCurlErrTelnetError = rb_define_class_under(mCurlErr, "TelnetError", eCurlErrError);
|
510
515
|
eCurlErrTFTPError = rb_define_class_under(mCurlErr, "TFTPError", eCurlErrError);
|
511
516
|
|
517
|
+
eCurlErrOK = rb_define_class_under(mCurlErr, "CurlOK", eCurlErrError);
|
512
518
|
eCurlErrUnsupportedProtocol = rb_define_class_under(mCurlErr, "UnsupportedProtocolError", eCurlErrError);
|
513
519
|
eCurlErrFailedInit = rb_define_class_under(mCurlErr, "FailedInitError", eCurlErrError);
|
514
520
|
eCurlErrMalformedURL = rb_define_class_under(mCurlErr, "MalformedURLError", eCurlErrError);
|
@@ -600,6 +606,7 @@ void init_curb_errors() {
|
|
600
606
|
eCurlErrSSLShutdownFailed = rb_define_class_under(mCurlErr, "SSLShutdownFailed", eCurlErrError);
|
601
607
|
eCurlErrSSH = rb_define_class_under(mCurlErr, "SSH", eCurlErrError);
|
602
608
|
|
609
|
+
mCurlErrFailedInit = rb_define_class_under(mCurlErr, "MultiInitError", eCurlErrError);
|
603
610
|
mCurlErrCallMultiPerform = rb_define_class_under(mCurlErr, "MultiPerform", eCurlErrError);
|
604
611
|
mCurlErrBadHandle = rb_define_class_under(mCurlErr, "MultiBadHandle", eCurlErrError);
|
605
612
|
mCurlErrBadEasyHandle = rb_define_class_under(mCurlErr, "MultiBadEasyHandle", eCurlErrError);
|
data/ext/curb_errors.h
CHANGED
@@ -108,6 +108,7 @@ extern VALUE eCurlErrSSLCRLBadfile;
|
|
108
108
|
extern VALUE eCurlErrSSLIssuerError;
|
109
109
|
|
110
110
|
/* multi errors */
|
111
|
+
extern VALUE mCurlErrFailedInit;
|
111
112
|
extern VALUE mCurlErrCallMultiPerform;
|
112
113
|
extern VALUE mCurlErrBadHandle;
|
113
114
|
extern VALUE mCurlErrBadEasyHandle;
|
data/ext/curb_errors.o
CHANGED
Binary file
|
data/ext/curb_macros.h
CHANGED
@@ -8,6 +8,17 @@
|
|
8
8
|
#ifndef __CURB_MACROS_H
|
9
9
|
#define __CURB_MACROS_H
|
10
10
|
|
11
|
+
#define rb_easy_hkey(key) ID2SYM(rb_intern(key))
|
12
|
+
#define rb_easy_set(key,val) rb_hash_aset(rbce->opts, rb_easy_hkey(key) , val)
|
13
|
+
#define rb_easy_get(key) rb_hash_aref(rbce->opts, rb_easy_hkey(key))
|
14
|
+
#define rb_easy_del(key) rb_hash_delete(rbce->opts, rb_easy_hkey(key))
|
15
|
+
#define rb_easy_nil(key) (rb_hash_aref(rbce->opts, rb_easy_hkey(key)) == Qnil)
|
16
|
+
#define rb_easy_type_check(key,type) (rb_type(rb_hash_aref(rbce->opts, rb_easy_hkey(key))) == type)
|
17
|
+
|
18
|
+
// TODO: rb_sym_to_s may not be defined?
|
19
|
+
#define rb_easy_get_str(key) \
|
20
|
+
RSTRING_PTR((rb_easy_type_check(key,T_STRING) ? rb_easy_get(key) : rb_str_to_str(rb_easy_get(key))))
|
21
|
+
|
11
22
|
/* getter/setter macros for various things */
|
12
23
|
/* setter for anything that stores a ruby VALUE in the struct */
|
13
24
|
#define CURB_OBJECT_SETTER(type, attr) \
|
@@ -25,6 +36,22 @@
|
|
25
36
|
Data_Get_Struct(self, type, ptr); \
|
26
37
|
return ptr->attr;
|
27
38
|
|
39
|
+
/* setter for anything that stores a ruby VALUE in the struct opts hash */
|
40
|
+
#define CURB_OBJECT_HSETTER(type, attr) \
|
41
|
+
type *ptr; \
|
42
|
+
\
|
43
|
+
Data_Get_Struct(self, type, ptr); \
|
44
|
+
rb_hash_aset(ptr->opts, rb_easy_hkey(#attr), attr); \
|
45
|
+
\
|
46
|
+
return attr;
|
47
|
+
|
48
|
+
/* getter for anything that stores a ruby VALUE in the struct opts hash */
|
49
|
+
#define CURB_OBJECT_HGETTER(type, attr) \
|
50
|
+
type *ptr; \
|
51
|
+
\
|
52
|
+
Data_Get_Struct(self, type, ptr); \
|
53
|
+
return rb_hash_aref(ptr->opts, rb_easy_hkey(#attr));
|
54
|
+
|
28
55
|
/* setter for bool flags */
|
29
56
|
#define CURB_BOOLEAN_SETTER(type, attr) \
|
30
57
|
type *ptr; \
|
@@ -57,6 +84,20 @@
|
|
57
84
|
\
|
58
85
|
return oldproc; \
|
59
86
|
|
87
|
+
/* special setter for on_event handlers that take a block, same as above but stores int he opts hash */
|
88
|
+
#define CURB_HANDLER_PROC_HSETTER(type, handler) \
|
89
|
+
type *ptr; \
|
90
|
+
VALUE oldproc, newproc; \
|
91
|
+
\
|
92
|
+
Data_Get_Struct(self, type, ptr); \
|
93
|
+
\
|
94
|
+
oldproc = rb_hash_aref(ptr->opts, rb_easy_hkey(#handler)); \
|
95
|
+
rb_scan_args(argc, argv, "0&", &newproc); \
|
96
|
+
\
|
97
|
+
rb_hash_aset(ptr->opts, rb_easy_hkey(#handler), newproc); \
|
98
|
+
\
|
99
|
+
return oldproc;
|
100
|
+
|
60
101
|
/* setter for numerics that are kept in c ints */
|
61
102
|
#define CURB_IMMED_SETTER(type, attr, nilval) \
|
62
103
|
type *ptr; \
|
data/ext/curb_multi.c
CHANGED
@@ -28,11 +28,13 @@ static VALUE idCall;
|
|
28
28
|
|
29
29
|
VALUE cCurlMulti;
|
30
30
|
|
31
|
+
static long cCurlMutiDefaulttimeout = 100; /* milliseconds */
|
32
|
+
|
31
33
|
static void rb_curl_multi_remove(ruby_curl_multi *rbcm, VALUE easy);
|
32
34
|
static void rb_curl_multi_read_info(VALUE self, CURLM *mptr);
|
35
|
+
static void rb_curl_multi_run(VALUE self, CURLM *multi_handle, int *still_running);
|
33
36
|
|
34
37
|
static void rb_curl_multi_mark_all_easy(VALUE key, VALUE rbeasy, ruby_curl_multi *rbcm) {
|
35
|
-
//printf( "mark easy: 0x%X\n", (long)rbeasy );
|
36
38
|
rb_gc_mark(rbeasy);
|
37
39
|
}
|
38
40
|
|
@@ -42,20 +44,14 @@ static void curl_multi_mark(ruby_curl_multi *rbcm) {
|
|
42
44
|
}
|
43
45
|
|
44
46
|
static void curl_multi_flush_easy(VALUE key, VALUE easy, ruby_curl_multi *rbcm) {
|
45
|
-
//rb_curl_multi_remove(rbcm, easy);
|
46
47
|
CURLMcode result;
|
47
48
|
ruby_curl_easy *rbce;
|
48
|
-
|
49
|
+
|
49
50
|
Data_Get_Struct(easy, ruby_curl_easy, rbce);
|
50
51
|
result = curl_multi_remove_handle(rbcm->handle, rbce->curl);
|
51
52
|
if (result != 0) {
|
52
53
|
raise_curl_multi_error_exception(result);
|
53
54
|
}
|
54
|
-
// XXX: easy handle may not be finished yet... so don't clean it GC pass will get it next time
|
55
|
-
r = rb_hash_delete( rbcm->requests, easy );
|
56
|
-
if( r != easy || r == Qnil ) {
|
57
|
-
rb_raise(rb_eRuntimeError, "Critical:: Unable to remove easy from requests");
|
58
|
-
}
|
59
55
|
}
|
60
56
|
|
61
57
|
static int
|
@@ -65,7 +61,6 @@ rb_hash_clear_i(VALUE key, VALUE value, VALUE dummy) {
|
|
65
61
|
|
66
62
|
static void curl_multi_free(ruby_curl_multi *rbcm) {
|
67
63
|
|
68
|
-
//printf("hash entries: %d\n", RHASH(rbcm->requests)->tbl->num_entries );
|
69
64
|
if (rbcm && !rbcm->requests == Qnil && rb_type(rbcm->requests) == T_HASH && RHASH_LEN(rbcm->requests) > 0) {
|
70
65
|
|
71
66
|
rb_hash_foreach( rbcm->requests, (int (*)())curl_multi_flush_easy, (VALUE)rbcm );
|
@@ -89,6 +84,9 @@ VALUE ruby_curl_multi_new(VALUE klass) {
|
|
89
84
|
ruby_curl_multi *rbcm = ALLOC(ruby_curl_multi);
|
90
85
|
|
91
86
|
rbcm->handle = curl_multi_init();
|
87
|
+
if (!rbcm->handle) {
|
88
|
+
rb_raise(mCurlErrFailedInit, "Failed to initialize multi handle");
|
89
|
+
}
|
92
90
|
|
93
91
|
rbcm->requests = rb_hash_new();
|
94
92
|
|
@@ -100,7 +98,31 @@ VALUE ruby_curl_multi_new(VALUE klass) {
|
|
100
98
|
return new_curlm;
|
101
99
|
}
|
102
100
|
|
103
|
-
|
101
|
+
/*
|
102
|
+
* call-seq:
|
103
|
+
* Curl::Multi.default_timeout = 4 => 4
|
104
|
+
*
|
105
|
+
* Set the global default time out for all Curl::Multi Handles. This value is used
|
106
|
+
* when libcurl cannot determine a timeout value when calling curl_multi_timeout.
|
107
|
+
*
|
108
|
+
*/
|
109
|
+
VALUE ruby_curl_multi_set_default_timeout(VALUE klass, VALUE timeout) {
|
110
|
+
cCurlMutiDefaulttimeout = FIX2LONG(timeout);
|
111
|
+
return timeout;
|
112
|
+
}
|
113
|
+
|
114
|
+
/*
|
115
|
+
* call-seq:
|
116
|
+
* Curl::Multi.default_timeout = 4 => 4
|
117
|
+
*
|
118
|
+
* Get the global default time out for all Curl::Multi Handles.
|
119
|
+
*
|
120
|
+
*/
|
121
|
+
VALUE ruby_curl_multi_get_default_timeout(VALUE klass) {
|
122
|
+
return INT2FIX(cCurlMutiDefaulttimeout);
|
123
|
+
}
|
124
|
+
|
125
|
+
/* Hash#foreach callback for ruby_curl_multi_requests */
|
104
126
|
static int ruby_curl_multi_requests_callback(VALUE key, VALUE value, VALUE result_array) {
|
105
127
|
rb_ary_push(result_array, value);
|
106
128
|
|
@@ -121,8 +143,8 @@ static VALUE ruby_curl_multi_requests(VALUE self) {
|
|
121
143
|
|
122
144
|
result_array = rb_ary_new();
|
123
145
|
|
124
|
-
|
125
|
-
rb_hash_foreach(
|
146
|
+
/* iterate over the requests hash, and stuff references into the array. */
|
147
|
+
rb_hash_foreach(rbcm->requests, ruby_curl_multi_requests_callback, result_array);
|
126
148
|
|
127
149
|
return result_array;
|
128
150
|
}
|
@@ -202,17 +224,14 @@ VALUE ruby_curl_multi_add(VALUE self, VALUE easy) {
|
|
202
224
|
Data_Get_Struct(self, ruby_curl_multi, rbcm);
|
203
225
|
Data_Get_Struct(easy, ruby_curl_easy, rbce);
|
204
226
|
|
227
|
+
/* setup the easy handle */
|
228
|
+
ruby_curl_easy_setup( rbce );
|
229
|
+
|
205
230
|
mcode = curl_multi_add_handle(rbcm->handle, rbce->curl);
|
206
231
|
if (mcode != CURLM_CALL_MULTI_PERFORM && mcode != CURLM_OK) {
|
207
232
|
raise_curl_multi_error_exception(mcode);
|
208
233
|
}
|
209
234
|
|
210
|
-
/* save a pointer to self */
|
211
|
-
rbce->self = easy;
|
212
|
-
|
213
|
-
/* setup the easy handle */
|
214
|
-
ruby_curl_easy_setup( rbce, &(rbce->bodybuf), &(rbce->headerbuf), &(rbce->curl_headers) );
|
215
|
-
|
216
235
|
rbcm->active++;
|
217
236
|
|
218
237
|
/* Increase the running count, so that the perform loop keeps running.
|
@@ -221,6 +240,8 @@ VALUE ruby_curl_multi_add(VALUE self, VALUE easy) {
|
|
221
240
|
|
222
241
|
rb_hash_aset( rbcm->requests, easy, easy );
|
223
242
|
|
243
|
+
rb_curl_multi_run( self, rbcm->handle, &(rbcm->running) );
|
244
|
+
|
224
245
|
return self;
|
225
246
|
}
|
226
247
|
|
@@ -264,18 +285,16 @@ static void rb_curl_multi_remove(ruby_curl_multi *rbcm, VALUE easy) {
|
|
264
285
|
|
265
286
|
rbcm->active--;
|
266
287
|
|
267
|
-
ruby_curl_easy_cleanup( easy, rbce
|
268
|
-
rbce->headerbuf = Qnil;
|
269
|
-
rbce->bodybuf = Qnil;
|
288
|
+
ruby_curl_easy_cleanup( easy, rbce );
|
270
289
|
|
271
290
|
// active should equal INT2FIX(RHASH(rbcm->requests)->tbl->num_entries)
|
272
291
|
r = rb_hash_delete( rbcm->requests, easy );
|
273
292
|
if( r != easy || r == Qnil ) {
|
274
|
-
|
293
|
+
rb_warn("Possibly lost track of Curl::Easy VALUE, it may not be reclaimed by GC");
|
275
294
|
}
|
276
295
|
}
|
277
296
|
|
278
|
-
|
297
|
+
/* Hash#foreach callback for ruby_curl_multi_cancel */
|
279
298
|
static int ruby_curl_multi_cancel_callback(VALUE key, VALUE value, ruby_curl_multi *rbcm) {
|
280
299
|
rb_curl_multi_remove(rbcm, value);
|
281
300
|
|
@@ -295,48 +314,47 @@ static VALUE ruby_curl_multi_cancel(VALUE self) {
|
|
295
314
|
|
296
315
|
rb_hash_foreach( rbcm->requests, ruby_curl_multi_cancel_callback, (VALUE)rbcm );
|
297
316
|
|
298
|
-
|
317
|
+
/* for chaining */
|
299
318
|
return self;
|
300
319
|
}
|
301
320
|
|
302
321
|
static void rb_curl_mutli_handle_complete(VALUE self, CURL *easy_handle, int result) {
|
303
322
|
|
304
323
|
long response_code = -1;
|
324
|
+
VALUE easy;
|
305
325
|
ruby_curl_easy *rbce = NULL;
|
306
|
-
VALUE ref;
|
307
|
-
CURLcode ecode = curl_easy_getinfo(easy_handle, CURLINFO_PRIVATE, (char**)&rbce);
|
308
326
|
|
309
|
-
|
310
|
-
|
311
|
-
|
327
|
+
CURLcode ecode = curl_easy_getinfo(easy_handle, CURLINFO_PRIVATE, (char**)&easy);
|
328
|
+
|
329
|
+
Data_Get_Struct(easy, ruby_curl_easy, rbce);
|
312
330
|
|
313
331
|
rbce->last_result = result; /* save the last easy result code */
|
314
332
|
|
315
|
-
ruby_curl_multi_remove( self,
|
333
|
+
ruby_curl_multi_remove( self, easy );
|
334
|
+
|
335
|
+
if (ecode != 0) {
|
336
|
+
raise_curl_easy_error_exception(ecode);
|
337
|
+
}
|
316
338
|
|
317
|
-
if (
|
318
|
-
rb_funcall(
|
339
|
+
if (!rb_easy_nil("complete_proc")) {
|
340
|
+
rb_funcall( rb_easy_get("complete_proc"), idCall, 1, easy );
|
319
341
|
}
|
320
342
|
|
321
343
|
curl_easy_getinfo(rbce->curl, CURLINFO_RESPONSE_CODE, &response_code);
|
322
344
|
|
323
|
-
ref = rbce->self;
|
324
|
-
/* break reference */
|
325
|
-
rbce->self = Qnil;
|
326
|
-
|
327
345
|
if (result != 0) {
|
328
|
-
if (
|
329
|
-
rb_funcall(
|
346
|
+
if (!rb_easy_nil("failure_proc")) {
|
347
|
+
rb_funcall( rb_easy_get("failure_proc"), idCall, 2, easy, rb_curl_easy_error(result) );
|
330
348
|
}
|
331
349
|
}
|
332
|
-
else if (
|
350
|
+
else if (!rb_easy_nil("success_proc") &&
|
333
351
|
((response_code >= 200 && response_code < 300) || response_code == 0)) {
|
334
352
|
/* NOTE: we allow response_code == 0, in the case of non http requests e.g. reading from disk */
|
335
|
-
rb_funcall(
|
353
|
+
rb_funcall( rb_easy_get("success_proc"), idCall, 1, easy );
|
336
354
|
}
|
337
|
-
else if (
|
355
|
+
else if (!rb_easy_nil("failure_proc") &&
|
338
356
|
(response_code >= 300 && response_code <= 999)) {
|
339
|
-
rb_funcall(
|
357
|
+
rb_funcall( rb_easy_get("failure_proc"), idCall, 2, easy, rb_curl_easy_error(result) );
|
340
358
|
}
|
341
359
|
}
|
342
360
|
|
@@ -368,8 +386,7 @@ static void rb_curl_multi_run(VALUE self, CURLM *multi_handle, int *still_runnin
|
|
368
386
|
if (mcode != CURLM_OK) {
|
369
387
|
raise_curl_multi_error_exception(mcode);
|
370
388
|
}
|
371
|
-
|
372
|
-
rb_curl_multi_read_info( self, multi_handle );
|
389
|
+
|
373
390
|
}
|
374
391
|
|
375
392
|
/*
|
@@ -401,66 +418,72 @@ VALUE ruby_curl_multi_perform(int argc, VALUE *argv, VALUE self) {
|
|
401
418
|
|
402
419
|
Data_Get_Struct(self, ruby_curl_multi, rbcm);
|
403
420
|
|
404
|
-
|
405
|
-
|
406
|
-
while(rbcm->running) {
|
407
|
-
FD_ZERO(&fdread);
|
408
|
-
FD_ZERO(&fdwrite);
|
409
|
-
FD_ZERO(&fdexcep);
|
421
|
+
timeout_milliseconds = cCurlMutiDefaulttimeout;
|
410
422
|
|
411
|
-
|
412
|
-
|
413
|
-
|
414
|
-
|
415
|
-
}
|
423
|
+
rb_curl_multi_run( self, rbcm->handle, &(rbcm->running) );
|
424
|
+
|
425
|
+
do {
|
426
|
+
while (rbcm->running) {
|
416
427
|
|
417
428
|
#ifdef HAVE_CURL_MULTI_TIMEOUT
|
418
|
-
|
419
|
-
|
420
|
-
|
421
|
-
|
422
|
-
|
429
|
+
/* get the curl suggested time out */
|
430
|
+
mcode = curl_multi_timeout(rbcm->handle, &timeout_milliseconds);
|
431
|
+
if (mcode != CURLM_OK) {
|
432
|
+
raise_curl_multi_error_exception(mcode);
|
433
|
+
}
|
423
434
|
#else
|
424
|
-
|
425
|
-
|
435
|
+
/* libcurl doesn't have a timeout method defined, initialize to -1 we'll pick up the default later */
|
436
|
+
timeout_milliseconds = -1;
|
426
437
|
#endif
|
427
|
-
//printf("libcurl says wait: %ld ms or %ld s\n", timeout_milliseconds, timeout_milliseconds/1000);
|
428
438
|
|
429
|
-
|
430
|
-
|
431
|
-
|
432
|
-
|
433
|
-
|
434
|
-
|
435
|
-
|
436
|
-
#ifdef __APPLE_CC__
|
437
|
-
if(timeout_milliseconds > 1000) {
|
438
|
-
timeout_milliseconds = 1000; /* apple libcurl sometimes reports huge timeouts... let's cap it */
|
439
|
-
}
|
440
|
-
#endif
|
439
|
+
if (timeout_milliseconds == 0) { /* no delay */
|
440
|
+
rb_curl_multi_run( self, rbcm->handle, &(rbcm->running) );
|
441
|
+
continue;
|
442
|
+
}
|
443
|
+
else if (timeout_milliseconds < 0) {
|
444
|
+
timeout_milliseconds = cCurlMutiDefaulttimeout; /* libcurl doesn't know how long to wait, use a default timeout */
|
445
|
+
}
|
441
446
|
|
442
|
-
|
443
|
-
|
444
|
-
|
445
|
-
rc = rb_thread_select(maxfd+1, &fdread, &fdwrite, &fdexcep, &tv);
|
446
|
-
switch(rc) {
|
447
|
-
case -1:
|
448
|
-
rb_raise(rb_eRuntimeError, "select(): %s", strerror(errno));
|
449
|
-
break;
|
450
|
-
case 0:
|
451
|
-
if (block != Qnil) {
|
452
|
-
rb_funcall(block, rb_intern("call"), 1, self);
|
447
|
+
if (timeout_milliseconds > cCurlMutiDefaulttimeout) {
|
448
|
+
timeout_milliseconds = cCurlMutiDefaulttimeout; /* buggy versions libcurl sometimes reports huge timeouts... let's cap it */
|
453
449
|
}
|
454
|
-
// if (rb_block_given_p()) {
|
455
|
-
// rb_yield(self);
|
456
|
-
// }
|
457
|
-
default:
|
458
|
-
rb_curl_multi_run( self, rbcm->handle, &(rbcm->running) );
|
459
|
-
break;
|
460
|
-
}
|
461
450
|
|
462
|
-
|
451
|
+
tv.tv_sec = 0; /* never wait longer than 1 second */
|
452
|
+
tv.tv_usec = timeout_milliseconds * 1000;
|
463
453
|
|
454
|
+
if (timeout_milliseconds == 0) { /* no delay */
|
455
|
+
rb_curl_multi_run( self, rbcm->handle, &(rbcm->running) );
|
456
|
+
continue;
|
457
|
+
}
|
458
|
+
|
459
|
+
if (block != Qnil) { rb_funcall(block, rb_intern("call"), 1, self); }
|
460
|
+
|
461
|
+
FD_ZERO(&fdread);
|
462
|
+
FD_ZERO(&fdwrite);
|
463
|
+
FD_ZERO(&fdexcep);
|
464
|
+
/* load the fd sets from the multi handle */
|
465
|
+
mcode = curl_multi_fdset(rbcm->handle, &fdread, &fdwrite, &fdexcep, &maxfd);
|
466
|
+
if (mcode != CURLM_OK) {
|
467
|
+
raise_curl_multi_error_exception(mcode);
|
468
|
+
}
|
469
|
+
|
470
|
+
rc = rb_thread_select(maxfd+1, &fdread, &fdwrite, &fdexcep, &tv);
|
471
|
+
switch(rc) {
|
472
|
+
case -1:
|
473
|
+
rb_raise(rb_eRuntimeError, "select(): %s", strerror(errno));
|
474
|
+
break;
|
475
|
+
case 0:
|
476
|
+
rb_curl_multi_read_info( self, rbcm->handle );
|
477
|
+
if (block != Qnil) { rb_funcall(block, rb_intern("call"), 1, self); }
|
478
|
+
default:
|
479
|
+
rb_curl_multi_run( self, rbcm->handle, &(rbcm->running) );
|
480
|
+
break;
|
481
|
+
}
|
482
|
+
}
|
483
|
+
rb_curl_multi_read_info( self, rbcm->handle );
|
484
|
+
if (block != Qnil) { rb_funcall(block, rb_intern("call"), 1, self); }
|
485
|
+
} while( rbcm->running );
|
486
|
+
|
464
487
|
return Qtrue;
|
465
488
|
}
|
466
489
|
|
@@ -472,6 +495,8 @@ void init_curb_multi() {
|
|
472
495
|
|
473
496
|
/* Class methods */
|
474
497
|
rb_define_singleton_method(cCurlMulti, "new", ruby_curl_multi_new, 0);
|
498
|
+
rb_define_singleton_method(cCurlMulti, "default_timeout=", ruby_curl_multi_set_default_timeout, 1);
|
499
|
+
rb_define_singleton_method(cCurlMulti, "default_timeout", ruby_curl_multi_get_default_timeout, 0);
|
475
500
|
|
476
501
|
/* "Attributes" */
|
477
502
|
rb_define_method(cCurlMulti, "requests", ruby_curl_multi_requests, 0);
|