ghazel-curb 0.6.2.3 → 0.7.9.1
Sign up to get free protection for your applications and to get access to all the features.
- 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"
|