ghazel-curb 0.6.2.3 → 0.7.9.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/README +8 -1
- data/Rakefile +20 -1
- data/ext/curb.c +34 -0
- data/ext/curb.h +6 -4
- data/ext/curb_easy.c +627 -181
- data/ext/curb_easy.h +28 -2
- data/ext/curb_errors.c +2 -0
- data/ext/curb_errors.h +1 -0
- data/ext/curb_macros.h +1 -1
- data/ext/curb_multi.c +155 -59
- data/ext/curb_postfield.c +61 -49
- data/ext/curb_upload.c +2 -2
- data/ext/extconf.rb +7 -2
- data/lib/curb.rb +94 -5
- 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 +21 -7
- data/tests/mem_check.rb +65 -0
- data/tests/tc_curl_download.rb +44 -1
- data/tests/tc_curl_easy.rb +181 -11
- data/tests/tc_curl_multi.rb +36 -3
- data/tests/tc_curl_postfield.rb +3 -1
- data/tests/timeout.rb +100 -0
- data/tests/timeout_server.rb +33 -0
- metadata +44 -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
|
*/
|
@@ -19,6 +37,7 @@ typedef struct {
|
|
19
37
|
CURL *curl;
|
20
38
|
|
21
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 */
|
22
41
|
|
23
42
|
/* Other opts */
|
24
43
|
unsigned short local_port; // 0 is no port
|
@@ -32,6 +51,11 @@ typedef struct {
|
|
32
51
|
unsigned long connect_timeout;
|
33
52
|
long dns_cache_timeout;
|
34
53
|
unsigned long ftp_response_timeout;
|
54
|
+
long low_speed_limit;
|
55
|
+
long low_speed_time;
|
56
|
+
long ssl_version;
|
57
|
+
long use_ssl;
|
58
|
+
long ftp_filemethod;
|
35
59
|
|
36
60
|
/* bool flags */
|
37
61
|
char proxy_tunnel;
|
@@ -45,7 +69,9 @@ typedef struct {
|
|
45
69
|
char verbose;
|
46
70
|
char multipart_form_post;
|
47
71
|
char enable_cookies;
|
72
|
+
char ignore_content_length;
|
48
73
|
struct curl_slist *curl_headers;
|
74
|
+
struct curl_slist *curl_ftp_commands;
|
49
75
|
|
50
76
|
int last_result; /* last result code from multi loop */
|
51
77
|
|
@@ -53,8 +79,8 @@ typedef struct {
|
|
53
79
|
|
54
80
|
extern VALUE cCurlEasy;
|
55
81
|
|
56
|
-
VALUE ruby_curl_easy_setup(ruby_curl_easy *rbce
|
57
|
-
VALUE ruby_curl_easy_cleanup(VALUE self, ruby_curl_easy *rbce
|
82
|
+
VALUE ruby_curl_easy_setup(ruby_curl_easy *rbce);
|
83
|
+
VALUE ruby_curl_easy_cleanup(VALUE self, ruby_curl_easy *rbce);
|
58
84
|
|
59
85
|
void init_curb_easy();
|
60
86
|
|
data/ext/curb_errors.c
CHANGED
@@ -110,6 +110,7 @@ VALUE eCurlErrSSLCRLBadfile;
|
|
110
110
|
VALUE eCurlErrSSLIssuerError;
|
111
111
|
|
112
112
|
/* multi errors */
|
113
|
+
VALUE mCurlErrFailedInit;
|
113
114
|
VALUE mCurlErrCallMultiPerform;
|
114
115
|
VALUE mCurlErrBadHandle;
|
115
116
|
VALUE mCurlErrBadEasyHandle;
|
@@ -605,6 +606,7 @@ void init_curb_errors() {
|
|
605
606
|
eCurlErrSSLShutdownFailed = rb_define_class_under(mCurlErr, "SSLShutdownFailed", eCurlErrError);
|
606
607
|
eCurlErrSSH = rb_define_class_under(mCurlErr, "SSH", eCurlErrError);
|
607
608
|
|
609
|
+
mCurlErrFailedInit = rb_define_class_under(mCurlErr, "MultiInitError", eCurlErrError);
|
608
610
|
mCurlErrCallMultiPerform = rb_define_class_under(mCurlErr, "MultiPerform", eCurlErrError);
|
609
611
|
mCurlErrBadHandle = rb_define_class_under(mCurlErr, "MultiBadHandle", eCurlErrError);
|
610
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_macros.h
CHANGED
@@ -12,7 +12,7 @@
|
|
12
12
|
#define rb_easy_set(key,val) rb_hash_aset(rbce->opts, rb_easy_hkey(key) , val)
|
13
13
|
#define rb_easy_get(key) rb_hash_aref(rbce->opts, rb_easy_hkey(key))
|
14
14
|
#define rb_easy_del(key) rb_hash_delete(rbce->opts, rb_easy_hkey(key))
|
15
|
-
#define rb_easy_nil(key) (
|
15
|
+
#define rb_easy_nil(key) (rb_hash_aref(rbce->opts, rb_easy_hkey(key)) == Qnil)
|
16
16
|
#define rb_easy_type_check(key,type) (rb_type(rb_hash_aref(rbce->opts, rb_easy_hkey(key))) == type)
|
17
17
|
|
18
18
|
// TODO: rb_sym_to_s may not be defined?
|
data/ext/curb_multi.c
CHANGED
@@ -19,6 +19,11 @@
|
|
19
19
|
|
20
20
|
#include <errno.h>
|
21
21
|
|
22
|
+
#ifdef _WIN32
|
23
|
+
// for O_RDWR and O_BINARY
|
24
|
+
#include <fcntl.h>
|
25
|
+
#endif
|
26
|
+
|
22
27
|
extern VALUE mCurl;
|
23
28
|
static VALUE idCall;
|
24
29
|
|
@@ -28,8 +33,11 @@ static VALUE idCall;
|
|
28
33
|
|
29
34
|
VALUE cCurlMulti;
|
30
35
|
|
36
|
+
static long cCurlMutiDefaulttimeout = 100; /* milliseconds */
|
37
|
+
|
31
38
|
static void rb_curl_multi_remove(ruby_curl_multi *rbcm, VALUE easy);
|
32
39
|
static void rb_curl_multi_read_info(VALUE self, CURLM *mptr);
|
40
|
+
static void rb_curl_multi_run(VALUE self, CURLM *multi_handle, int *still_running);
|
33
41
|
|
34
42
|
static void rb_curl_multi_mark_all_easy(VALUE key, VALUE rbeasy, ruby_curl_multi *rbcm) {
|
35
43
|
rb_gc_mark(rbeasy);
|
@@ -81,6 +89,9 @@ VALUE ruby_curl_multi_new(VALUE klass) {
|
|
81
89
|
ruby_curl_multi *rbcm = ALLOC(ruby_curl_multi);
|
82
90
|
|
83
91
|
rbcm->handle = curl_multi_init();
|
92
|
+
if (!rbcm->handle) {
|
93
|
+
rb_raise(mCurlErrFailedInit, "Failed to initialize multi handle");
|
94
|
+
}
|
84
95
|
|
85
96
|
rbcm->requests = rb_hash_new();
|
86
97
|
|
@@ -92,6 +103,30 @@ VALUE ruby_curl_multi_new(VALUE klass) {
|
|
92
103
|
return new_curlm;
|
93
104
|
}
|
94
105
|
|
106
|
+
/*
|
107
|
+
* call-seq:
|
108
|
+
* Curl::Multi.default_timeout = 4 => 4
|
109
|
+
*
|
110
|
+
* Set the global default time out for all Curl::Multi Handles. This value is used
|
111
|
+
* when libcurl cannot determine a timeout value when calling curl_multi_timeout.
|
112
|
+
*
|
113
|
+
*/
|
114
|
+
VALUE ruby_curl_multi_set_default_timeout(VALUE klass, VALUE timeout) {
|
115
|
+
cCurlMutiDefaulttimeout = FIX2LONG(timeout);
|
116
|
+
return timeout;
|
117
|
+
}
|
118
|
+
|
119
|
+
/*
|
120
|
+
* call-seq:
|
121
|
+
* Curl::Multi.default_timeout = 4 => 4
|
122
|
+
*
|
123
|
+
* Get the global default time out for all Curl::Multi Handles.
|
124
|
+
*
|
125
|
+
*/
|
126
|
+
VALUE ruby_curl_multi_get_default_timeout(VALUE klass) {
|
127
|
+
return INT2FIX(cCurlMutiDefaulttimeout);
|
128
|
+
}
|
129
|
+
|
95
130
|
/* Hash#foreach callback for ruby_curl_multi_requests */
|
96
131
|
static int ruby_curl_multi_requests_callback(VALUE key, VALUE value, VALUE result_array) {
|
97
132
|
rb_ary_push(result_array, value);
|
@@ -194,14 +229,14 @@ VALUE ruby_curl_multi_add(VALUE self, VALUE easy) {
|
|
194
229
|
Data_Get_Struct(self, ruby_curl_multi, rbcm);
|
195
230
|
Data_Get_Struct(easy, ruby_curl_easy, rbce);
|
196
231
|
|
232
|
+
/* setup the easy handle */
|
233
|
+
ruby_curl_easy_setup( rbce );
|
234
|
+
|
197
235
|
mcode = curl_multi_add_handle(rbcm->handle, rbce->curl);
|
198
236
|
if (mcode != CURLM_CALL_MULTI_PERFORM && mcode != CURLM_OK) {
|
199
237
|
raise_curl_multi_error_exception(mcode);
|
200
238
|
}
|
201
239
|
|
202
|
-
/* setup the easy handle */
|
203
|
-
ruby_curl_easy_setup( rbce, &(rbce->curl_headers) );
|
204
|
-
|
205
240
|
rbcm->active++;
|
206
241
|
|
207
242
|
/* Increase the running count, so that the perform loop keeps running.
|
@@ -210,6 +245,8 @@ VALUE ruby_curl_multi_add(VALUE self, VALUE easy) {
|
|
210
245
|
|
211
246
|
rb_hash_aset( rbcm->requests, easy, easy );
|
212
247
|
|
248
|
+
rb_curl_multi_run( self, rbcm->handle, &(rbcm->running) );
|
249
|
+
|
213
250
|
return self;
|
214
251
|
}
|
215
252
|
|
@@ -253,7 +290,7 @@ static void rb_curl_multi_remove(ruby_curl_multi *rbcm, VALUE easy) {
|
|
253
290
|
|
254
291
|
rbcm->active--;
|
255
292
|
|
256
|
-
ruby_curl_easy_cleanup( easy, rbce
|
293
|
+
ruby_curl_easy_cleanup( easy, rbce );
|
257
294
|
|
258
295
|
// active should equal INT2FIX(RHASH(rbcm->requests)->tbl->num_entries)
|
259
296
|
r = rb_hash_delete( rbcm->requests, easy );
|
@@ -296,14 +333,20 @@ static void rb_curl_mutli_handle_complete(VALUE self, CURL *easy_handle, int res
|
|
296
333
|
|
297
334
|
Data_Get_Struct(easy, ruby_curl_easy, rbce);
|
298
335
|
|
299
|
-
if (ecode != 0) {
|
300
|
-
raise_curl_easy_error_exception(ecode);
|
301
|
-
}
|
302
|
-
|
303
336
|
rbce->last_result = result; /* save the last easy result code */
|
304
337
|
|
305
338
|
ruby_curl_multi_remove( self, easy );
|
306
339
|
|
340
|
+
/* after running a request cleanup the headers, these are set before each request */
|
341
|
+
if (rbce->curl_headers) {
|
342
|
+
curl_slist_free_all(rbce->curl_headers);
|
343
|
+
rbce->curl_headers = NULL;
|
344
|
+
}
|
345
|
+
|
346
|
+
if (ecode != 0) {
|
347
|
+
raise_curl_easy_error_exception(ecode);
|
348
|
+
}
|
349
|
+
|
307
350
|
if (!rb_easy_nil("complete_proc")) {
|
308
351
|
rb_funcall( rb_easy_get("complete_proc"), idCall, 1, easy );
|
309
352
|
}
|
@@ -324,6 +367,7 @@ static void rb_curl_mutli_handle_complete(VALUE self, CURL *easy_handle, int res
|
|
324
367
|
(response_code >= 300 && response_code <= 999)) {
|
325
368
|
rb_funcall( rb_easy_get("failure_proc"), idCall, 2, easy, rb_curl_easy_error(result) );
|
326
369
|
}
|
370
|
+
|
327
371
|
}
|
328
372
|
|
329
373
|
static void rb_curl_multi_read_info(VALUE self, CURLM *multi_handle) {
|
@@ -354,10 +398,38 @@ static void rb_curl_multi_run(VALUE self, CURLM *multi_handle, int *still_runnin
|
|
354
398
|
if (mcode != CURLM_OK) {
|
355
399
|
raise_curl_multi_error_exception(mcode);
|
356
400
|
}
|
401
|
+
|
402
|
+
}
|
357
403
|
|
358
|
-
|
404
|
+
#ifdef _WIN32
|
405
|
+
void create_crt_fd(fd_set *os_set, fd_set *crt_set)
|
406
|
+
{
|
407
|
+
int i;
|
408
|
+
crt_set->fd_count = os_set->fd_count;
|
409
|
+
for (i = 0; i < os_set->fd_count; i++) {
|
410
|
+
WSAPROTOCOL_INFO wsa_pi;
|
411
|
+
// dupicate the SOCKET
|
412
|
+
int r = WSADuplicateSocket(os_set->fd_array[i], GetCurrentProcessId(), &wsa_pi);
|
413
|
+
SOCKET s = WSASocket(wsa_pi.iAddressFamily, wsa_pi.iSocketType, wsa_pi.iProtocol, &wsa_pi, 0, 0);
|
414
|
+
// create the CRT fd so ruby can get back to the SOCKET
|
415
|
+
int fd = _open_osfhandle(s, O_RDWR|O_BINARY);
|
416
|
+
os_set->fd_array[i] = s;
|
417
|
+
crt_set->fd_array[i] = fd;
|
418
|
+
}
|
359
419
|
}
|
360
420
|
|
421
|
+
void cleanup_crt_fd(fd_set *os_set, fd_set *crt_set)
|
422
|
+
{
|
423
|
+
int i;
|
424
|
+
for (i = 0; i < os_set->fd_count; i++) {
|
425
|
+
// cleanup the CRT fd
|
426
|
+
_close(crt_set->fd_array[i]);
|
427
|
+
// cleanup the duplicated SOCKET
|
428
|
+
closesocket(os_set->fd_array[i]);
|
429
|
+
}
|
430
|
+
}
|
431
|
+
#endif
|
432
|
+
|
361
433
|
/*
|
362
434
|
* call-seq:
|
363
435
|
* multi = Curl::Multi.new
|
@@ -378,6 +450,9 @@ VALUE ruby_curl_multi_perform(int argc, VALUE *argv, VALUE self) {
|
|
378
450
|
ruby_curl_multi *rbcm;
|
379
451
|
int maxfd, rc;
|
380
452
|
fd_set fdread, fdwrite, fdexcep;
|
453
|
+
#ifdef _WIN32
|
454
|
+
fd_set crt_fdread, crt_fdwrite, crt_fdexcep;
|
455
|
+
#endif
|
381
456
|
|
382
457
|
long timeout_milliseconds;
|
383
458
|
struct timeval tv = {0, 0};
|
@@ -387,66 +462,85 @@ VALUE ruby_curl_multi_perform(int argc, VALUE *argv, VALUE self) {
|
|
387
462
|
|
388
463
|
Data_Get_Struct(self, ruby_curl_multi, rbcm);
|
389
464
|
|
390
|
-
|
391
|
-
|
392
|
-
while(rbcm->running) {
|
393
|
-
FD_ZERO(&fdread);
|
394
|
-
FD_ZERO(&fdwrite);
|
395
|
-
FD_ZERO(&fdexcep);
|
465
|
+
timeout_milliseconds = cCurlMutiDefaulttimeout;
|
396
466
|
|
397
|
-
|
398
|
-
|
399
|
-
|
400
|
-
|
401
|
-
}
|
467
|
+
rb_curl_multi_run( self, rbcm->handle, &(rbcm->running) );
|
468
|
+
|
469
|
+
do {
|
470
|
+
while (rbcm->running) {
|
402
471
|
|
403
472
|
#ifdef HAVE_CURL_MULTI_TIMEOUT
|
404
|
-
|
405
|
-
|
406
|
-
|
407
|
-
|
408
|
-
|
473
|
+
/* get the curl suggested time out */
|
474
|
+
mcode = curl_multi_timeout(rbcm->handle, &timeout_milliseconds);
|
475
|
+
if (mcode != CURLM_OK) {
|
476
|
+
raise_curl_multi_error_exception(mcode);
|
477
|
+
}
|
409
478
|
#else
|
410
|
-
|
411
|
-
|
479
|
+
/* libcurl doesn't have a timeout method defined, initialize to -1 we'll pick up the default later */
|
480
|
+
timeout_milliseconds = -1;
|
412
481
|
#endif
|
413
|
-
//printf("libcurl says wait: %ld ms or %ld s\n", timeout_milliseconds, timeout_milliseconds/1000);
|
414
482
|
|
415
|
-
|
416
|
-
|
417
|
-
|
418
|
-
|
419
|
-
|
420
|
-
|
421
|
-
|
422
|
-
#ifdef __APPLE_CC__
|
423
|
-
if(timeout_milliseconds > 1000) {
|
424
|
-
timeout_milliseconds = 1000; /* apple libcurl sometimes reports huge timeouts... let's cap it */
|
425
|
-
}
|
426
|
-
#endif
|
483
|
+
if (timeout_milliseconds == 0) { /* no delay */
|
484
|
+
rb_curl_multi_run( self, rbcm->handle, &(rbcm->running) );
|
485
|
+
continue;
|
486
|
+
}
|
487
|
+
else if (timeout_milliseconds < 0) {
|
488
|
+
timeout_milliseconds = cCurlMutiDefaulttimeout; /* libcurl doesn't know how long to wait, use a default timeout */
|
489
|
+
}
|
427
490
|
|
428
|
-
|
429
|
-
|
430
|
-
|
431
|
-
rc = rb_thread_select(maxfd+1, &fdread, &fdwrite, &fdexcep, &tv);
|
432
|
-
switch(rc) {
|
433
|
-
case -1:
|
434
|
-
rb_raise(rb_eRuntimeError, "select(): %s", strerror(errno));
|
435
|
-
break;
|
436
|
-
case 0:
|
437
|
-
if (block != Qnil) {
|
438
|
-
rb_funcall(block, rb_intern("call"), 1, self);
|
491
|
+
if (timeout_milliseconds > cCurlMutiDefaulttimeout) {
|
492
|
+
timeout_milliseconds = cCurlMutiDefaulttimeout; /* buggy versions libcurl sometimes reports huge timeouts... let's cap it */
|
439
493
|
}
|
440
|
-
// if (rb_block_given_p()) {
|
441
|
-
// rb_yield(self);
|
442
|
-
// }
|
443
|
-
default:
|
444
|
-
rb_curl_multi_run( self, rbcm->handle, &(rbcm->running) );
|
445
|
-
break;
|
446
|
-
}
|
447
494
|
|
448
|
-
|
495
|
+
tv.tv_sec = 0; /* never wait longer than 1 second */
|
496
|
+
tv.tv_usec = (int)(timeout_milliseconds * 1000); /* XXX: int is the right type for OSX, what about linux? */
|
449
497
|
|
498
|
+
if (timeout_milliseconds == 0) { /* no delay */
|
499
|
+
rb_curl_multi_run( self, rbcm->handle, &(rbcm->running) );
|
500
|
+
continue;
|
501
|
+
}
|
502
|
+
|
503
|
+
if (block != Qnil) { rb_funcall(block, rb_intern("call"), 1, self); }
|
504
|
+
|
505
|
+
FD_ZERO(&fdread);
|
506
|
+
FD_ZERO(&fdwrite);
|
507
|
+
FD_ZERO(&fdexcep);
|
508
|
+
/* load the fd sets from the multi handle */
|
509
|
+
mcode = curl_multi_fdset(rbcm->handle, &fdread, &fdwrite, &fdexcep, &maxfd);
|
510
|
+
if (mcode != CURLM_OK) {
|
511
|
+
raise_curl_multi_error_exception(mcode);
|
512
|
+
}
|
513
|
+
|
514
|
+
#ifdef _WIN32
|
515
|
+
create_crt_fd(&fdread, &crt_fdread);
|
516
|
+
create_crt_fd(&fdwrite, &crt_fdrwrite);
|
517
|
+
create_crt_fd(&fdexcep, &crt_fdexcep);
|
518
|
+
#endif
|
519
|
+
|
520
|
+
rc = rb_thread_select(maxfd+1, &fdread, &fdwrite, &fdexcep, &tv);
|
521
|
+
|
522
|
+
#ifdef _WIN32
|
523
|
+
cleanup_crt_fd(&fdread, &crt_fdread);
|
524
|
+
cleanup_crt_fd(&fdwrite, &crt_fdrwrite);
|
525
|
+
cleanup_crt_fd(&fdexcep, &crt_fdexcep);
|
526
|
+
#endif
|
527
|
+
|
528
|
+
switch(rc) {
|
529
|
+
case -1:
|
530
|
+
rb_raise(rb_eRuntimeError, "select(): %s", strerror(errno));
|
531
|
+
break;
|
532
|
+
case 0:
|
533
|
+
rb_curl_multi_read_info( self, rbcm->handle );
|
534
|
+
if (block != Qnil) { rb_funcall(block, rb_intern("call"), 1, self); }
|
535
|
+
default:
|
536
|
+
rb_curl_multi_run( self, rbcm->handle, &(rbcm->running) );
|
537
|
+
break;
|
538
|
+
}
|
539
|
+
}
|
540
|
+
rb_curl_multi_read_info( self, rbcm->handle );
|
541
|
+
if (block != Qnil) { rb_funcall(block, rb_intern("call"), 1, self); }
|
542
|
+
} while( rbcm->running );
|
543
|
+
|
450
544
|
return Qtrue;
|
451
545
|
}
|
452
546
|
|
@@ -458,6 +552,8 @@ void init_curb_multi() {
|
|
458
552
|
|
459
553
|
/* Class methods */
|
460
554
|
rb_define_singleton_method(cCurlMulti, "new", ruby_curl_multi_new, 0);
|
555
|
+
rb_define_singleton_method(cCurlMulti, "default_timeout=", ruby_curl_multi_set_default_timeout, 1);
|
556
|
+
rb_define_singleton_method(cCurlMulti, "default_timeout", ruby_curl_multi_get_default_timeout, 0);
|
461
557
|
|
462
558
|
/* "Attributes" */
|
463
559
|
rb_define_method(cCurlMulti, "requests", ruby_curl_multi_requests, 0);
|
data/ext/curb_postfield.c
CHANGED
@@ -109,7 +109,7 @@ void append_to_form(VALUE self,
|
|
109
109
|
} else {
|
110
110
|
// is a content field
|
111
111
|
if (rbcpf->content_proc != Qnil) {
|
112
|
-
rbcpf->buffer_str = rb_funcall(rbcpf->content_proc, idCall, self);
|
112
|
+
rbcpf->buffer_str = rb_funcall(rbcpf->content_proc, idCall, 1, self);
|
113
113
|
|
114
114
|
if (rbcpf->content_type == Qnil) {
|
115
115
|
result = curl_formadd(first, last, CURLFORM_PTRNAME, StringValuePtr(rbcpf->name),
|
@@ -209,11 +209,11 @@ void curl_postfield_free(ruby_curl_postfield *rbcpf) {
|
|
209
209
|
*/
|
210
210
|
static VALUE ruby_curl_postfield_new_content(int argc, VALUE *argv, VALUE klass) {
|
211
211
|
ruby_curl_postfield *rbcpf = ALLOC(ruby_curl_postfield);
|
212
|
-
|
212
|
+
|
213
213
|
// wierdness - we actually require two args, unless a block is provided, but
|
214
214
|
// we have to work that out below.
|
215
215
|
rb_scan_args(argc, argv, "12&", &rbcpf->name, &rbcpf->content, &rbcpf->content_type, &rbcpf->content_proc);
|
216
|
-
|
216
|
+
|
217
217
|
// special handling if theres a block, second arg is actually content_type
|
218
218
|
if (rbcpf->content_proc != Qnil) {
|
219
219
|
if (rbcpf->content != Qnil) {
|
@@ -235,7 +235,7 @@ static VALUE ruby_curl_postfield_new_content(int argc, VALUE *argv, VALUE klass)
|
|
235
235
|
rbcpf->local_file = Qnil;
|
236
236
|
rbcpf->remote_file = Qnil;
|
237
237
|
rbcpf->buffer_str = Qnil;
|
238
|
-
|
238
|
+
|
239
239
|
return Data_Wrap_Struct(cCurlPostField, curl_postfield_mark, curl_postfield_free, rbcpf);
|
240
240
|
}
|
241
241
|
|
@@ -253,11 +253,11 @@ static VALUE ruby_curl_postfield_new_content(int argc, VALUE *argv, VALUE klass)
|
|
253
253
|
* data.
|
254
254
|
*/
|
255
255
|
static VALUE ruby_curl_postfield_new_file(int argc, VALUE *argv, VALUE klass) {
|
256
|
-
// TODO needs to handle content-type too
|
256
|
+
// TODO needs to handle content-type too
|
257
257
|
ruby_curl_postfield *rbcpf = ALLOC(ruby_curl_postfield);
|
258
|
-
|
258
|
+
|
259
259
|
rb_scan_args(argc, argv, "21&", &rbcpf->name, &rbcpf->local_file, &rbcpf->remote_file, &rbcpf->content_proc);
|
260
|
-
|
260
|
+
|
261
261
|
// special handling if theres a block, second arg is actually remote name.
|
262
262
|
if (rbcpf->content_proc != Qnil) {
|
263
263
|
if (rbcpf->local_file != Qnil) {
|
@@ -267,7 +267,7 @@ static VALUE ruby_curl_postfield_new_file(int argc, VALUE *argv, VALUE klass) {
|
|
267
267
|
// (correct block call form)
|
268
268
|
rbcpf->remote_file = rbcpf->local_file;
|
269
269
|
}
|
270
|
-
|
270
|
+
|
271
271
|
// Shouldn't get a local file, so can ignore it.
|
272
272
|
rbcpf->local_file = Qnil;
|
273
273
|
}
|
@@ -275,13 +275,13 @@ static VALUE ruby_curl_postfield_new_file(int argc, VALUE *argv, VALUE klass) {
|
|
275
275
|
if (rbcpf->remote_file == Qnil) {
|
276
276
|
rbcpf->remote_file = rbcpf->local_file;
|
277
277
|
}
|
278
|
-
}
|
279
|
-
|
278
|
+
}
|
279
|
+
|
280
280
|
/* assoc objects */
|
281
281
|
rbcpf->content = Qnil;
|
282
282
|
rbcpf->content_type = Qnil;
|
283
283
|
rbcpf->buffer_str = Qnil;
|
284
|
-
|
284
|
+
|
285
285
|
return Data_Wrap_Struct(cCurlPostField, curl_postfield_mark, curl_postfield_free, rbcpf);
|
286
286
|
}
|
287
287
|
|
@@ -424,55 +424,67 @@ static VALUE ruby_curl_postfield_to_str(VALUE self) {
|
|
424
424
|
// FIXME This is using the deprecated curl_escape func
|
425
425
|
ruby_curl_postfield *rbcpf;
|
426
426
|
VALUE result = Qnil;
|
427
|
+
VALUE name = Qnil;
|
428
|
+
char *tmpchrs;
|
427
429
|
|
428
430
|
Data_Get_Struct(self, ruby_curl_postfield, rbcpf);
|
429
431
|
|
430
|
-
if ((rbcpf->local_file == Qnil) && (rbcpf->remote_file == Qnil)) {
|
431
432
|
if (rbcpf->name != Qnil) {
|
433
|
+
name = rbcpf->name;
|
434
|
+
if (rb_type(name) == T_STRING) {
|
435
|
+
name = rbcpf->name;
|
436
|
+
} else if (rb_respond_to(name,rb_intern("to_s"))) {
|
437
|
+
name = rb_funcall(name, rb_intern("to_s"), 0);
|
438
|
+
}
|
439
|
+
else {
|
440
|
+
name = Qnil; // we can't handle this object
|
441
|
+
}
|
442
|
+
}
|
443
|
+
if (name == Qnil) {
|
444
|
+
rb_raise(eCurlErrInvalidPostField, "Cannot convert unnamed field to string %s:%d, make sure your field name responds_to :to_s", __FILE__, __LINE__);
|
445
|
+
}
|
432
446
|
|
433
|
-
|
447
|
+
tmpchrs = curl_escape(StringValuePtr(name), (int)RSTRING_LEN(name));
|
448
|
+
|
449
|
+
if (!tmpchrs) {
|
450
|
+
rb_raise(eCurlErrInvalidPostField, "Failed to url-encode name `%s'", tmpchrs);
|
451
|
+
} else {
|
452
|
+
VALUE tmpcontent = Qnil;
|
453
|
+
VALUE escd_name = rb_str_new2(tmpchrs);
|
454
|
+
curl_free(tmpchrs);
|
434
455
|
|
456
|
+
if (rbcpf->content_proc != Qnil) {
|
457
|
+
tmpcontent = rb_funcall(rbcpf->content_proc, idCall, 1, self);
|
458
|
+
} else if (rbcpf->content != Qnil) {
|
459
|
+
tmpcontent = rbcpf->content;
|
460
|
+
} else if (rbcpf->local_file != Qnil) {
|
461
|
+
tmpcontent = rbcpf->local_file;
|
462
|
+
} else if (rbcpf->remote_file != Qnil) {
|
463
|
+
tmpcontent = rbcpf->remote_file;
|
464
|
+
} else {
|
465
|
+
tmpcontent = rb_str_new2("");
|
466
|
+
}
|
467
|
+
if (TYPE(tmpcontent) != T_STRING) {
|
468
|
+
if (rb_respond_to(tmpcontent, rb_intern("to_s"))) {
|
469
|
+
tmpcontent = rb_funcall(tmpcontent, rb_intern("to_s"), 0);
|
470
|
+
}
|
471
|
+
else {
|
472
|
+
rb_raise(rb_eRuntimeError, "postfield(%s) is not a string and does not respond_to to_s", RSTRING_PTR(escd_name) );
|
473
|
+
}
|
474
|
+
}
|
475
|
+
//fprintf(stderr, "encoding content: %ld - %s\n", RSTRING_LEN(tmpcontent), RSTRING_PTR(tmpcontent) );
|
476
|
+
tmpchrs = curl_escape(RSTRING_PTR(tmpcontent), (int)RSTRING_LEN(tmpcontent));
|
435
477
|
if (!tmpchrs) {
|
436
|
-
rb_raise(eCurlErrInvalidPostField, "Failed to url-encode
|
478
|
+
rb_raise(eCurlErrInvalidPostField, "Failed to url-encode content `%s'", tmpchrs);
|
437
479
|
} else {
|
438
|
-
VALUE
|
439
|
-
VALUE escd_name = rb_str_new2(tmpchrs);
|
480
|
+
VALUE escd_content = rb_str_new2(tmpchrs);
|
440
481
|
curl_free(tmpchrs);
|
441
482
|
|
442
|
-
|
443
|
-
|
444
|
-
|
445
|
-
tmpcontent = rbcpf->content;
|
446
|
-
} else {
|
447
|
-
tmpcontent = rb_str_new2("");
|
448
|
-
}
|
449
|
-
if (TYPE(tmpcontent) != T_STRING) {
|
450
|
-
if (rb_respond_to(tmpcontent, rb_intern("to_s"))) {
|
451
|
-
tmpcontent = rb_funcall(tmpcontent, rb_intern("to_s"), 0);
|
452
|
-
}
|
453
|
-
else {
|
454
|
-
rb_raise(rb_eRuntimeError, "postfield(%s) is not a string and does not respond_to to_s", RSTRING_PTR(escd_name) );
|
455
|
-
}
|
456
|
-
}
|
457
|
-
//fprintf(stderr, "encoding content: %ld - %s\n", RSTRING_LEN(tmpcontent), RSTRING_PTR(tmpcontent) );
|
458
|
-
tmpchrs = curl_escape(RSTRING_PTR(tmpcontent), RSTRING_LEN(tmpcontent));
|
459
|
-
if (!tmpchrs) {
|
460
|
-
rb_raise(eCurlErrInvalidPostField, "Failed to url-encode content `%s'", tmpchrs);
|
461
|
-
} else {
|
462
|
-
VALUE escd_content = rb_str_new2(tmpchrs);
|
463
|
-
curl_free(tmpchrs);
|
464
|
-
|
465
|
-
result = escd_name;
|
466
|
-
rb_str_cat(result, "=", 1);
|
467
|
-
rb_str_concat(result, escd_content);
|
468
|
-
}
|
483
|
+
result = escd_name;
|
484
|
+
rb_str_cat(result, "=", 1);
|
485
|
+
rb_str_concat(result, escd_content);
|
469
486
|
}
|
470
|
-
}
|
471
|
-
rb_raise(eCurlErrInvalidPostField, "Cannot convert unnamed field to string %s:%d", __FILE__, __LINE__);
|
472
|
-
}
|
473
|
-
} else {
|
474
|
-
rb_raise(eCurlErrInvalidPostField, "Cannot convert non-content field to string %s:%d", __FILE__, __LINE__);
|
475
|
-
}
|
487
|
+
}
|
476
488
|
|
477
489
|
return result;
|
478
490
|
}
|
data/ext/curb_upload.c
CHANGED
@@ -11,7 +11,7 @@ VALUE cCurlUpload;
|
|
11
11
|
#endif
|
12
12
|
|
13
13
|
static void curl_upload_mark(ruby_curl_upload *rbcu) {
|
14
|
-
if (rbcu->stream) rb_gc_mark(rbcu->stream);
|
14
|
+
if (rbcu->stream && !NIL_P(rbcu->stream)) rb_gc_mark(rbcu->stream);
|
15
15
|
}
|
16
16
|
static void curl_upload_free(ruby_curl_upload *rbcu) {
|
17
17
|
free(rbcu);
|
@@ -56,7 +56,7 @@ VALUE ruby_curl_upload_stream_get(VALUE self) {
|
|
56
56
|
VALUE ruby_curl_upload_offset_set(VALUE self, VALUE offset) {
|
57
57
|
ruby_curl_upload *rbcu;
|
58
58
|
Data_Get_Struct(self, ruby_curl_upload, rbcu);
|
59
|
-
rbcu->offset =
|
59
|
+
rbcu->offset = FIX2LONG(offset);
|
60
60
|
return offset;
|
61
61
|
}
|
62
62
|
/*
|
data/ext/extconf.rb
CHANGED
@@ -1,10 +1,9 @@
|
|
1
1
|
require 'mkmf'
|
2
|
-
puts $CFLAGS.inspect
|
3
2
|
|
4
3
|
dir_config('curl')
|
5
4
|
|
6
5
|
if find_executable('curl-config')
|
7
|
-
$CFLAGS << " #{`curl-config --cflags`.strip}"
|
6
|
+
$CFLAGS << " #{`curl-config --cflags`.strip} -g"
|
8
7
|
if ENV['STATIC_BUILD']
|
9
8
|
$LIBS << " #{`curl-config --static-libs`.strip}"
|
10
9
|
else
|
@@ -114,10 +113,16 @@ have_constant "curle_ssl_issuer_error"
|
|
114
113
|
# username/password added in 7.19.1
|
115
114
|
have_constant "curlopt_username"
|
116
115
|
have_constant "curlopt_password"
|
116
|
+
have_constant "curlinfo_primary_ip"
|
117
117
|
|
118
118
|
# ie quirk added in 7.19.3
|
119
119
|
have_constant "curlauth_digest_ie"
|
120
120
|
|
121
|
+
# added in 7.15.1
|
122
|
+
have_constant "curlftpmethod_multicwd"
|
123
|
+
have_constant "curlftpmethod_nocwd"
|
124
|
+
have_constant "curlftpmethod_singlecwd"
|
125
|
+
|
121
126
|
# centos 4.5 build of libcurl
|
122
127
|
have_constant "curlm_bad_socket"
|
123
128
|
have_constant "curlm_unknown_option"
|