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.

@@ -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
- /* Objects we associate */
22
- VALUE url;
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, VALUE *bodybuf, VALUE *headerbuf, struct curl_slist **headers);
99
- VALUE ruby_curl_easy_cleanup(VALUE self, ruby_curl_easy *rbce, VALUE bodybuf, VALUE headerbuf, struct curl_slist *headers);
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
 
Binary file
@@ -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);
@@ -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;
Binary file
@@ -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; \
@@ -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
- VALUE r;
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
- // Hash#foreach callback for ruby_curl_multi_requests
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
- // iterate over the requests hash, and stuff references into the array.
125
- rb_hash_foreach( rbcm->requests, ruby_curl_multi_requests_callback, result_array );
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, rbce->bodybuf, rbce->headerbuf, rbce->curl_headers );
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
- rb_raise(rb_eRuntimeError, "Critical:: Unable to remove easy from requests");
293
+ rb_warn("Possibly lost track of Curl::Easy VALUE, it may not be reclaimed by GC");
275
294
  }
276
295
  }
277
296
 
278
- // Hash#foreach callback for ruby_curl_multi_cancel
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
- // for chaining
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
- if (ecode != 0) {
310
- raise_curl_easy_error_exception(ecode);
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, rbce->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 (rbce->complete_proc != Qnil) {
318
- rb_funcall( rbce->complete_proc, idCall, 1, rbce->self );
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 (rbce->failure_proc != Qnil) {
329
- rb_funcall( rbce->failure_proc, idCall, 2, ref, rb_curl_easy_error(result) );
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 (rbce->success_proc != Qnil &&
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( rbce->success_proc, idCall, 1, ref );
353
+ rb_funcall( rb_easy_get("success_proc"), idCall, 1, easy );
336
354
  }
337
- else if (rbce->failure_proc != Qnil &&
355
+ else if (!rb_easy_nil("failure_proc") &&
338
356
  (response_code >= 300 && response_code <= 999)) {
339
- rb_funcall( rbce->failure_proc, idCall, 2, ref, rb_curl_easy_error(result) );
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
- rb_curl_multi_run( self, rbcm->handle, &(rbcm->running) );
405
-
406
- while(rbcm->running) {
407
- FD_ZERO(&fdread);
408
- FD_ZERO(&fdwrite);
409
- FD_ZERO(&fdexcep);
421
+ timeout_milliseconds = cCurlMutiDefaulttimeout;
410
422
 
411
- /* load the fd sets from the multi handle */
412
- mcode = curl_multi_fdset(rbcm->handle, &fdread, &fdwrite, &fdexcep, &maxfd);
413
- if (mcode != CURLM_OK) {
414
- raise_curl_multi_error_exception(mcode);
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
- /* get the curl suggested time out */
419
- mcode = curl_multi_timeout(rbcm->handle, &timeout_milliseconds);
420
- if (mcode != CURLM_OK) {
421
- raise_curl_multi_error_exception(mcode);
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
- /* libcurl doesn't have a timeout method defined... make a wild guess */
425
- timeout_milliseconds = -1;
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
- if (timeout_milliseconds == 0) { /* no delay */
430
- rb_curl_multi_run( self, rbcm->handle, &(rbcm->running) );
431
- continue;
432
- }
433
- else if(timeout_milliseconds < 0) {
434
- timeout_milliseconds = 500; /* wait half a second, libcurl doesn't know how long to wait */
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
- tv.tv_sec = timeout_milliseconds / 1000; // convert milliseconds to seconds
443
- tv.tv_usec = (timeout_milliseconds % 1000) * 1000; // get the remainder of milliseconds and convert to micro seconds
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);